From 1580f5bc641b5cb31a99e8747cc2bbc7bf599b26 Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Wed, 25 Mar 2026 09:37:53 +0000 Subject: [PATCH 1/3] fix(spawn): run agent directly via ssh instead of attaching tmux --- .changeset/remove-tmux.md | 5 ++++ packages/app/src/docker-git/main.ts | 6 ++--- packages/app/src/docker-git/spawn.ts | 40 +++++++++++++++++++++++++--- 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 .changeset/remove-tmux.md diff --git a/.changeset/remove-tmux.md b/.changeset/remove-tmux.md new file mode 100644 index 0000000..b80cfcc --- /dev/null +++ b/.changeset/remove-tmux.md @@ -0,0 +1,5 @@ +--- +"@spawn-dock/cli": patch +--- + +fix: execute agent directly via ssh instead of attaching tmux in spawn command diff --git a/packages/app/src/docker-git/main.ts b/packages/app/src/docker-git/main.ts index c869795..dc448f7 100644 --- a/packages/app/src/docker-git/main.ts +++ b/packages/app/src/docker-git/main.ts @@ -1,5 +1,6 @@ #!/usr/bin/env node +import * as _9 from "@effect/cli" import * as _1 from "@effect/cluster" import * as _2 from "@effect/experimental" import * as _3 from "@effect/printer" @@ -8,15 +9,14 @@ import * as _5 from "@effect/rpc" import * as _6 from "@effect/sql" import * as _7 from "@effect/typeclass" import * as _8 from "@effect/workflow" -import * as _9 from "@effect/cli" - -export const _dummyDeps = [_1, _2, _3, _4, _5, _6, _7, _8, _9] import { NodeContext, NodeRuntime } from "@effect/platform-node" import { Effect } from "effect" import { program } from "./program.js" +export const _dummyDeps = [_1, _2, _3, _4, _5, _6, _7, _8, _9] + // CHANGE: run docker-git CLI through the Node runtime // WHY: ensure platform services (FS, Path, Command) are available in app CLI // QUOTE(ТЗ): "CLI (отображение, фронт) это app" diff --git a/packages/app/src/docker-git/spawn.ts b/packages/app/src/docker-git/spawn.ts index 9355206..6d0d2fe 100644 --- a/packages/app/src/docker-git/spawn.ts +++ b/packages/app/src/docker-git/spawn.ts @@ -11,15 +11,17 @@ import { type TemplateConfig } from "@effect-template/lib/core/domain" import type { SpawnCommand } from "@effect-template/lib/core/spawn-domain" -import { runCommandCapture, runCommandExitCode } from "@effect-template/lib/shell/command-runner" +import { + runCommandCapture, + runCommandExitCode, + runCommandWithExitCodes +} from "@effect-template/lib/shell/command-runner" import { readProjectConfig } from "@effect-template/lib/shell/config" import { CommandFailedError, SpawnProjectDirError, SpawnSetupError } from "@effect-template/lib/shell/errors" import { createProject } from "@effect-template/lib/usecases/actions" import { findSshPrivateKey } from "@effect-template/lib/usecases/path-helpers" import { getContainerIpIfInsideContainer } from "@effect-template/lib/usecases/projects-core" -import { spawnAttachTmux } from "./tmux.js" - const SPAWNDOCK_REPO_URL = "https://github.com/SpawnDock/tma-project" const SPAWNDOCK_REPO_REF = "main" @@ -121,6 +123,35 @@ const buildSpawnCreateCommand = (outDir: string, force: boolean): CreateCommand } } +const spawnAttachDirect = ( + template: TemplateConfig, + projectDir: string, + sshKey: string | null, + ipAddress: string | undefined +): Effect.Effect => + Effect.gen(function*(_) { + yield* _(Effect.log("Starting opencode directly via SSH...")) + yield* _( + runCommandWithExitCodes( + { + cwd: process.cwd(), + command: "ssh", + args: buildSshArgs( + template, + sshKey, + ipAddress, + `cd '${projectDir}' && spawn-dock agent` + ).filter((arg) => + arg !== "-T" && arg !== "-o" && arg !== "BatchMode=yes" && arg !== "ConnectTimeout=2" && + arg !== "ConnectionAttempts=1" + ) + }, + [0, 255], // SSH frequently exits with 255 on user disconnect, which is normal + (exitCode) => new CommandFailedError({ command: "ssh agent", exitCode }) + ) + ) + }) + // CHANGE: orchestrate spawn-dock spawn — creates container, runs @spawn-dock/create, opens tmux+opencode // WHY: provide one-command bootstrap from a Telegram bot pairing token // REF: spawn-command @@ -174,5 +205,6 @@ export const spawnProject = (command: SpawnCommand) => } yield* _(Effect.log(`Project bootstrapped at ${projectDir}`)) - yield* _(spawnAttachTmux(template, projectDir, sshKey)) + + yield* _(spawnAttachDirect(template, projectDir, sshKey, ipAddress)) }) From b7df229a302395ce9443be33510edaa5750ff267 Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:08:36 +0000 Subject: [PATCH 2/3] fix(spawn): force tty allocation (-tt) for interactive opencode session via SSH --- packages/app/src/docker-git/spawn.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/app/src/docker-git/spawn.ts b/packages/app/src/docker-git/spawn.ts index 16f5ef4..324389b 100644 --- a/packages/app/src/docker-git/spawn.ts +++ b/packages/app/src/docker-git/spawn.ts @@ -132,15 +132,18 @@ const spawnAttachDirect = ( { cwd: process.cwd(), command: "ssh", - args: buildSshArgs( - template, - sshKey, - ipAddress, - `cd '${projectDir}' && spawn-dock agent` - ).filter((arg) => - arg !== "-T" && arg !== "-o" && arg !== "BatchMode=yes" && arg !== "ConnectTimeout=2" && - arg !== "ConnectionAttempts=1" - ) + args: [ + "-tt", // Force TTY allocation for interactive opencode session + ...buildSshArgs( + template, + sshKey, + ipAddress, + `cd '${projectDir}' && spawn-dock agent` + ).filter((arg) => + arg !== "-T" && arg !== "-o" && arg !== "BatchMode=yes" && arg !== "ConnectTimeout=2" && + arg !== "ConnectionAttempts=1" + ) + ] }, [0, 255], // SSH frequently exits with 255 on user disconnect, which is normal (exitCode) => new CommandFailedError({ command: "ssh agent", exitCode }) From 1b0564c60d987cb7827050dfec00cc001719198b Mon Sep 17 00:00:00 2001 From: skulidropek <66840575+skulidropek@users.noreply.github.com> Date: Wed, 25 Mar 2026 10:08:36 +0000 Subject: [PATCH 3/3] chore: bump version for ssh tty fix --- .changeset/fix-tty.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-tty.md diff --git a/.changeset/fix-tty.md b/.changeset/fix-tty.md new file mode 100644 index 0000000..2a77229 --- /dev/null +++ b/.changeset/fix-tty.md @@ -0,0 +1,5 @@ +--- +"@spawn-dock/cli": patch +--- + +fix: force TTY allocation (-tt) during SSH so opencode is fully interactive without tmux