Skip to content

feat: add spawn command — one-command SpawnDock container bootstrap#3

Merged
skulidropek merged 4 commits intomainfrom
feat/spawn-command
Mar 24, 2026
Merged

feat: add spawn command — one-command SpawnDock container bootstrap#3
skulidropek merged 4 commits intomainfrom
feat/spawn-command

Conversation

@skulidropek
Copy link
Copy Markdown
Member

Summary

  • Adds docker-git spawn --token <pairing-token> command that orchestrates the full SpawnDock workflow in one step
  • Creates a Docker container from SpawnDock/tma-project, runs @spawn-dock/create@beta inside via SSH, then opens a tmux workspace with spawn-dock agent
  • Adds SpawnCommand type to domain, SpawnProjectDirError/SpawnSetupError error types, and full error rendering

Changes

File Change
packages/lib/src/core/domain.ts SpawnCommand interface + Command union
packages/lib/src/shell/errors.ts SpawnProjectDirError, SpawnSetupError
packages/lib/src/usecases/errors.ts AppError union + renderError handlers
packages/app/src/docker-git/cli/parser-spawn.ts New — parses --token into SpawnCommand
packages/app/src/docker-git/cli/parser.ts Registers spawn verb
packages/app/src/docker-git/spawn.ts New — full orchestration effect
packages/app/src/docker-git/tmux.ts spawnAttachTmux — opens tmux with agent pre-loaded
packages/app/src/docker-git/program.ts Spawn dispatch + catchTag handlers
packages/app/src/docker-git/cli/usage.ts spawn command documented

Test plan

  • docker-git --help shows spawn command in usage text
  • docker-git spawn (no token) prints Missing required option: --token
  • docker-git spawn --token pair_xxx starts container, runs @spawn-dock/create, opens tmux
  • pnpm -w typecheck passes (verified ✅)
  • pnpm build succeeds (verified ✅)

🤖 Generated with Claude Code

skulidropek and others added 4 commits March 24, 2026 14:34
Adds `docker-git spawn --token <pairing-token>` which:
1. Creates a fresh Docker dev container (SpawnDock/tma-project)
2. Waits for SSH readiness (30 retries × 2s)
3. Runs `npx -y @spawn-dock/create@beta --token <token>` inside the container
4. Parses project dir from output
5. Opens tmux with SSH pane pre-loaded: `cd '<dir>' && spawn-dock agent`

New files:
- packages/app/src/docker-git/cli/parser-spawn.ts
- packages/app/src/docker-git/spawn.ts

Modified:
- domain.ts: SpawnCommand interface + Command union
- shell/errors.ts: SpawnProjectDirError, SpawnSetupError
- usecases/errors.ts: AppError union + renderError handlers
- parser.ts: spawn verb registered
- tmux.ts: spawnAttachTmux exported
- program.ts: Spawn dispatch wired + catchTags
- usage.ts: spawn command documented

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- parser-spawn.ts: replace `as const` with typed intermediate vars (ParseError, SpawnCommand)
  + add functional comment block per AGENTS.md convention
- spawn.ts: type buildSpawnCreateCommand return as CreateCommand (removes _tag cast);
  fix useless-undefined via ip ?? "" + length check; inline import for dprint
- tmux.ts: flip negated condition sshKey !== null → sshKey === null

All three violations caught by eslint-effect-ts-check (no-restricted-syntax: TSAsExpression)
and standard eslint (unicorn/no-negated-condition, dprint).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
tmux.ts:
- Extract private openTmuxWorkspace(template, leftPaneCommand) helper that
  contains session detection + create + configure + setup + attach logic
- attachTmux: delegate to openTmuxWorkspace (removes duplicated session setup)
- spawnAttachTmux: delegate to openTmuxWorkspace (removes duplicated session
  detection, bind-keys, select-pane blocks — DUPLICATE #1 and #2)

spawn.ts:
- Merge buildSshProbeArgs + buildSshRunArgs into single buildSshArgs(template,
  sshKey, ipAddress, remoteCommand?) — probe mode when remoteCommand=undefined
  (removes structural duplication — DUPLICATE #3)
- Fix unicorn/no-negated-condition: flip if(remoteCommand!==undefined) guard
- Fix unicorn/prefer-single-call: inline trailing push into preceding spread

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
domain.ts was 5 lines over the 300 non-blank-line ESLint limit after
adding SpawnCommand. Extracted the interface to spawn-domain.ts (mirrors
session-gist-domain pattern), re-exported via session-gist-domain so the
import can be merged with the existing line-1 import. Updated app consumers
to import SpawnCommand from @effect-template/lib/core/spawn-domain.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@skulidropek skulidropek merged commit 8e6aaed into main Mar 24, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant