@cluesmith/codev 2.0.0-rc.9 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/af.js +2 -2
- package/bin/consult.js +1 -1
- package/dashboard/dist/assets/index-4n9zpWLY.css +32 -0
- package/dashboard/dist/assets/index-b38SaXk5.js +136 -0
- package/dashboard/dist/assets/index-b38SaXk5.js.map +1 -0
- package/dashboard/dist/index.html +14 -0
- package/dist/agent-farm/cli.d.ts.map +1 -1
- package/dist/agent-farm/cli.js +179 -104
- package/dist/agent-farm/cli.js.map +1 -1
- package/dist/agent-farm/commands/architect.d.ts +3 -3
- package/dist/agent-farm/commands/architect.d.ts.map +1 -1
- package/dist/agent-farm/commands/architect.js +20 -147
- package/dist/agent-farm/commands/architect.js.map +1 -1
- package/dist/agent-farm/commands/attach.d.ts +13 -0
- package/dist/agent-farm/commands/attach.d.ts.map +1 -0
- package/dist/agent-farm/commands/attach.js +144 -0
- package/dist/agent-farm/commands/attach.js.map +1 -0
- package/dist/agent-farm/commands/cleanup.d.ts.map +1 -1
- package/dist/agent-farm/commands/cleanup.js +35 -19
- package/dist/agent-farm/commands/cleanup.js.map +1 -1
- package/dist/agent-farm/commands/consult.d.ts +3 -4
- package/dist/agent-farm/commands/consult.d.ts.map +1 -1
- package/dist/agent-farm/commands/consult.js +27 -37
- package/dist/agent-farm/commands/consult.js.map +1 -1
- package/dist/agent-farm/commands/index.d.ts +2 -2
- package/dist/agent-farm/commands/index.d.ts.map +1 -1
- package/dist/agent-farm/commands/index.js +2 -2
- package/dist/agent-farm/commands/index.js.map +1 -1
- package/dist/agent-farm/commands/open.d.ts +4 -2
- package/dist/agent-farm/commands/open.d.ts.map +1 -1
- package/dist/agent-farm/commands/open.js +33 -83
- package/dist/agent-farm/commands/open.js.map +1 -1
- package/dist/agent-farm/commands/send.d.ts +1 -1
- package/dist/agent-farm/commands/send.d.ts.map +1 -1
- package/dist/agent-farm/commands/send.js +70 -79
- package/dist/agent-farm/commands/send.js.map +1 -1
- package/dist/agent-farm/commands/shell.d.ts +15 -0
- package/dist/agent-farm/commands/shell.d.ts.map +1 -0
- package/dist/agent-farm/commands/shell.js +50 -0
- package/dist/agent-farm/commands/shell.js.map +1 -0
- package/dist/agent-farm/commands/spawn-roles.d.ts +80 -0
- package/dist/agent-farm/commands/spawn-roles.d.ts.map +1 -0
- package/dist/agent-farm/commands/spawn-roles.js +278 -0
- package/dist/agent-farm/commands/spawn-roles.js.map +1 -0
- package/dist/agent-farm/commands/spawn-worktree.d.ts +96 -0
- package/dist/agent-farm/commands/spawn-worktree.d.ts.map +1 -0
- package/dist/agent-farm/commands/spawn-worktree.js +305 -0
- package/dist/agent-farm/commands/spawn-worktree.js.map +1 -0
- package/dist/agent-farm/commands/spawn.d.ts +5 -1
- package/dist/agent-farm/commands/spawn.d.ts.map +1 -1
- package/dist/agent-farm/commands/spawn.js +241 -561
- package/dist/agent-farm/commands/spawn.js.map +1 -1
- package/dist/agent-farm/commands/start.d.ts +10 -20
- package/dist/agent-farm/commands/start.d.ts.map +1 -1
- package/dist/agent-farm/commands/start.js +45 -449
- package/dist/agent-farm/commands/start.js.map +1 -1
- package/dist/agent-farm/commands/status.d.ts +2 -0
- package/dist/agent-farm/commands/status.d.ts.map +1 -1
- package/dist/agent-farm/commands/status.js +75 -24
- package/dist/agent-farm/commands/status.js.map +1 -1
- package/dist/agent-farm/commands/stop.d.ts +6 -0
- package/dist/agent-farm/commands/stop.d.ts.map +1 -1
- package/dist/agent-farm/commands/stop.js +49 -109
- package/dist/agent-farm/commands/stop.js.map +1 -1
- package/dist/agent-farm/commands/tower-cloud.d.ts +48 -0
- package/dist/agent-farm/commands/tower-cloud.d.ts.map +1 -0
- package/dist/agent-farm/commands/tower-cloud.js +293 -0
- package/dist/agent-farm/commands/tower-cloud.js.map +1 -0
- package/dist/agent-farm/commands/tower.d.ts +9 -0
- package/dist/agent-farm/commands/tower.d.ts.map +1 -1
- package/dist/agent-farm/commands/tower.js +59 -19
- package/dist/agent-farm/commands/tower.js.map +1 -1
- package/dist/agent-farm/db/index.d.ts +6 -2
- package/dist/agent-farm/db/index.d.ts.map +1 -1
- package/dist/agent-farm/db/index.js +301 -19
- package/dist/agent-farm/db/index.js.map +1 -1
- package/dist/agent-farm/db/migrate.d.ts +0 -4
- package/dist/agent-farm/db/migrate.d.ts.map +1 -1
- package/dist/agent-farm/db/migrate.js +6 -55
- package/dist/agent-farm/db/migrate.js.map +1 -1
- package/dist/agent-farm/db/schema.d.ts +3 -3
- package/dist/agent-farm/db/schema.d.ts.map +1 -1
- package/dist/agent-farm/db/schema.js +25 -19
- package/dist/agent-farm/db/schema.js.map +1 -1
- package/dist/agent-farm/db/types.d.ts +3 -13
- package/dist/agent-farm/db/types.d.ts.map +1 -1
- package/dist/agent-farm/db/types.js +3 -11
- package/dist/agent-farm/db/types.js.map +1 -1
- package/dist/agent-farm/hq-connector.d.ts +2 -6
- package/dist/agent-farm/hq-connector.d.ts.map +1 -1
- package/dist/agent-farm/hq-connector.js +2 -17
- package/dist/agent-farm/hq-connector.js.map +1 -1
- package/dist/agent-farm/lib/cloud-config.d.ts +59 -0
- package/dist/agent-farm/lib/cloud-config.d.ts.map +1 -0
- package/dist/agent-farm/lib/cloud-config.js +143 -0
- package/dist/agent-farm/lib/cloud-config.js.map +1 -0
- package/dist/agent-farm/lib/device-name.d.ts +25 -0
- package/dist/agent-farm/lib/device-name.d.ts.map +1 -0
- package/dist/agent-farm/lib/device-name.js +46 -0
- package/dist/agent-farm/lib/device-name.js.map +1 -0
- package/dist/agent-farm/lib/nonce-store.d.ts +28 -0
- package/dist/agent-farm/lib/nonce-store.d.ts.map +1 -0
- package/dist/agent-farm/lib/nonce-store.js +60 -0
- package/dist/agent-farm/lib/nonce-store.js.map +1 -0
- package/dist/agent-farm/lib/token-exchange.d.ts +18 -0
- package/dist/agent-farm/lib/token-exchange.d.ts.map +1 -0
- package/dist/agent-farm/lib/token-exchange.js +48 -0
- package/dist/agent-farm/lib/token-exchange.js.map +1 -0
- package/dist/agent-farm/lib/tower-client.d.ts +163 -0
- package/dist/agent-farm/lib/tower-client.d.ts.map +1 -0
- package/dist/agent-farm/lib/tower-client.js +233 -0
- package/dist/agent-farm/lib/tower-client.js.map +1 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts +117 -0
- package/dist/agent-farm/lib/tunnel-client.d.ts.map +1 -0
- package/dist/agent-farm/lib/tunnel-client.js +504 -0
- package/dist/agent-farm/lib/tunnel-client.js.map +1 -0
- package/dist/agent-farm/servers/tower-instances.d.ts +82 -0
- package/dist/agent-farm/servers/tower-instances.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-instances.js +454 -0
- package/dist/agent-farm/servers/tower-instances.js.map +1 -0
- package/dist/agent-farm/servers/tower-routes.d.ts +34 -0
- package/dist/agent-farm/servers/tower-routes.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-routes.js +1445 -0
- package/dist/agent-farm/servers/tower-routes.js.map +1 -0
- package/dist/agent-farm/servers/tower-server.d.ts +5 -2
- package/dist/agent-farm/servers/tower-server.d.ts.map +1 -1
- package/dist/agent-farm/servers/tower-server.js +157 -475
- package/dist/agent-farm/servers/tower-server.js.map +1 -1
- package/dist/agent-farm/servers/tower-terminals.d.ts +119 -0
- package/dist/agent-farm/servers/tower-terminals.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-terminals.js +629 -0
- package/dist/agent-farm/servers/tower-terminals.js.map +1 -0
- package/dist/agent-farm/servers/tower-tunnel.d.ts +34 -0
- package/dist/agent-farm/servers/tower-tunnel.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-tunnel.js +480 -0
- package/dist/agent-farm/servers/tower-tunnel.js.map +1 -0
- package/dist/agent-farm/servers/tower-types.d.ts +86 -0
- package/dist/agent-farm/servers/tower-types.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-types.js +6 -0
- package/dist/agent-farm/servers/tower-types.js.map +1 -0
- package/dist/agent-farm/servers/tower-utils.d.ts +58 -0
- package/dist/agent-farm/servers/tower-utils.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-utils.js +182 -0
- package/dist/agent-farm/servers/tower-utils.js.map +1 -0
- package/dist/agent-farm/servers/tower-websocket.d.ts +25 -0
- package/dist/agent-farm/servers/tower-websocket.d.ts.map +1 -0
- package/dist/agent-farm/servers/tower-websocket.js +171 -0
- package/dist/agent-farm/servers/tower-websocket.js.map +1 -0
- package/dist/agent-farm/state.d.ts +6 -2
- package/dist/agent-farm/state.d.ts.map +1 -1
- package/dist/agent-farm/state.js +34 -25
- package/dist/agent-farm/state.js.map +1 -1
- package/dist/agent-farm/types.d.ts +49 -26
- package/dist/agent-farm/types.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.d.ts +0 -5
- package/dist/agent-farm/utils/config.d.ts.map +1 -1
- package/dist/agent-farm/utils/config.js +12 -44
- package/dist/agent-farm/utils/config.js.map +1 -1
- package/dist/agent-farm/utils/deps.d.ts.map +1 -1
- package/dist/agent-farm/utils/deps.js +0 -32
- package/dist/agent-farm/utils/deps.js.map +1 -1
- package/dist/agent-farm/utils/file-tabs.d.ts +27 -0
- package/dist/agent-farm/utils/file-tabs.d.ts.map +1 -0
- package/dist/agent-farm/utils/file-tabs.js +46 -0
- package/dist/agent-farm/utils/file-tabs.js.map +1 -0
- package/dist/agent-farm/utils/gate-status.d.ts +16 -0
- package/dist/agent-farm/utils/gate-status.d.ts.map +1 -0
- package/dist/agent-farm/utils/gate-status.js +79 -0
- package/dist/agent-farm/utils/gate-status.js.map +1 -0
- package/dist/agent-farm/utils/gate-watcher.d.ts +38 -0
- package/dist/agent-farm/utils/gate-watcher.d.ts.map +1 -0
- package/dist/agent-farm/utils/gate-watcher.js +122 -0
- package/dist/agent-farm/utils/gate-watcher.js.map +1 -0
- package/dist/agent-farm/utils/index.d.ts +0 -1
- package/dist/agent-farm/utils/index.d.ts.map +1 -1
- package/dist/agent-farm/utils/index.js +0 -1
- package/dist/agent-farm/utils/index.js.map +1 -1
- package/dist/agent-farm/utils/notifications.d.ts +30 -0
- package/dist/agent-farm/utils/notifications.d.ts.map +1 -0
- package/dist/agent-farm/utils/notifications.js +121 -0
- package/dist/agent-farm/utils/notifications.js.map +1 -0
- package/dist/agent-farm/utils/server-utils.d.ts +5 -5
- package/dist/agent-farm/utils/server-utils.d.ts.map +1 -1
- package/dist/agent-farm/utils/server-utils.js +5 -16
- package/dist/agent-farm/utils/server-utils.js.map +1 -1
- package/dist/agent-farm/utils/session.d.ts +32 -0
- package/dist/agent-farm/utils/session.d.ts.map +1 -0
- package/dist/agent-farm/utils/session.js +57 -0
- package/dist/agent-farm/utils/session.js.map +1 -0
- package/dist/agent-farm/utils/shell.d.ts +9 -22
- package/dist/agent-farm/utils/shell.d.ts.map +1 -1
- package/dist/agent-farm/utils/shell.js +34 -34
- package/dist/agent-farm/utils/shell.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +6 -37
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt.d.ts.map +1 -1
- package/dist/commands/adopt.js +33 -4
- package/dist/commands/adopt.js.map +1 -1
- package/dist/commands/consult/index.d.ts +13 -2
- package/dist/commands/consult/index.d.ts.map +1 -1
- package/dist/commands/consult/index.js +244 -29
- package/dist/commands/consult/index.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +96 -79
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +36 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/porch/build-counter.d.ts +5 -0
- package/dist/commands/porch/build-counter.d.ts.map +1 -0
- package/dist/commands/porch/build-counter.js +5 -0
- package/dist/commands/porch/build-counter.js.map +1 -0
- package/dist/commands/porch/checks.d.ts +3 -2
- package/dist/commands/porch/checks.d.ts.map +1 -1
- package/dist/commands/porch/checks.js +8 -2
- package/dist/commands/porch/checks.js.map +1 -1
- package/dist/commands/porch/index.d.ts +4 -0
- package/dist/commands/porch/index.d.ts.map +1 -1
- package/dist/commands/porch/index.js +109 -70
- package/dist/commands/porch/index.js.map +1 -1
- package/dist/commands/porch/next.d.ts +22 -0
- package/dist/commands/porch/next.d.ts.map +1 -0
- package/dist/commands/porch/next.js +571 -0
- package/dist/commands/porch/next.js.map +1 -0
- package/dist/commands/porch/plan.d.ts +11 -1
- package/dist/commands/porch/plan.d.ts.map +1 -1
- package/dist/commands/porch/plan.js +33 -5
- package/dist/commands/porch/plan.js.map +1 -1
- package/dist/commands/porch/prompts.d.ts.map +1 -1
- package/dist/commands/porch/prompts.js +44 -26
- package/dist/commands/porch/prompts.js.map +1 -1
- package/dist/commands/porch/protocol.d.ts +6 -4
- package/dist/commands/porch/protocol.d.ts.map +1 -1
- package/dist/commands/porch/protocol.js +59 -15
- package/dist/commands/porch/protocol.js.map +1 -1
- package/dist/commands/porch/state.d.ts +29 -2
- package/dist/commands/porch/state.d.ts.map +1 -1
- package/dist/commands/porch/state.js +71 -3
- package/dist/commands/porch/state.js.map +1 -1
- package/dist/commands/porch/types.d.ts +45 -2
- package/dist/commands/porch/types.d.ts.map +1 -1
- package/dist/commands/porch/verdict.d.ts +31 -0
- package/dist/commands/porch/verdict.d.ts.map +1 -0
- package/dist/commands/porch/verdict.js +59 -0
- package/dist/commands/porch/verdict.js.map +1 -0
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +18 -6
- package/dist/commands/update.js.map +1 -1
- package/dist/lib/scaffold.d.ts +13 -0
- package/dist/lib/scaffold.d.ts.map +1 -1
- package/dist/lib/scaffold.js +36 -0
- package/dist/lib/scaffold.js.map +1 -1
- package/dist/terminal/index.d.ts +8 -0
- package/dist/terminal/index.d.ts.map +1 -0
- package/dist/terminal/index.js +5 -0
- package/dist/terminal/index.js.map +1 -0
- package/dist/terminal/pty-manager.d.ts +69 -0
- package/dist/terminal/pty-manager.d.ts.map +1 -0
- package/dist/terminal/pty-manager.js +377 -0
- package/dist/terminal/pty-manager.js.map +1 -0
- package/dist/terminal/pty-session.d.ts +104 -0
- package/dist/terminal/pty-session.d.ts.map +1 -0
- package/dist/terminal/pty-session.js +327 -0
- package/dist/terminal/pty-session.js.map +1 -0
- package/dist/terminal/ring-buffer.d.ts +34 -0
- package/dist/terminal/ring-buffer.d.ts.map +1 -0
- package/dist/terminal/ring-buffer.js +94 -0
- package/dist/terminal/ring-buffer.js.map +1 -0
- package/dist/terminal/session-manager.d.ts +115 -0
- package/dist/terminal/session-manager.d.ts.map +1 -0
- package/dist/terminal/session-manager.js +582 -0
- package/dist/terminal/session-manager.js.map +1 -0
- package/dist/terminal/shellper-client.d.ts +66 -0
- package/dist/terminal/shellper-client.d.ts.map +1 -0
- package/dist/terminal/shellper-client.js +234 -0
- package/dist/terminal/shellper-client.js.map +1 -0
- package/dist/terminal/shellper-main.d.ts +19 -0
- package/dist/terminal/shellper-main.d.ts.map +1 -0
- package/dist/terminal/shellper-main.js +153 -0
- package/dist/terminal/shellper-main.js.map +1 -0
- package/dist/terminal/shellper-process.d.ts +75 -0
- package/dist/terminal/shellper-process.d.ts.map +1 -0
- package/dist/terminal/shellper-process.js +279 -0
- package/dist/terminal/shellper-process.js.map +1 -0
- package/dist/terminal/shellper-protocol.d.ts +115 -0
- package/dist/terminal/shellper-protocol.d.ts.map +1 -0
- package/dist/terminal/shellper-protocol.js +214 -0
- package/dist/terminal/shellper-protocol.js.map +1 -0
- package/dist/terminal/shellper-replay-buffer.d.ts +38 -0
- package/dist/terminal/shellper-replay-buffer.d.ts.map +1 -0
- package/dist/terminal/shellper-replay-buffer.js +94 -0
- package/dist/terminal/shellper-replay-buffer.js.map +1 -0
- package/dist/terminal/ws-protocol.d.ts +27 -0
- package/dist/terminal/ws-protocol.d.ts.map +1 -0
- package/dist/terminal/ws-protocol.js +44 -0
- package/dist/terminal/ws-protocol.js.map +1 -0
- package/package.json +17 -5
- package/skeleton/.claude/skills/af/SKILL.md +89 -0
- package/skeleton/.claude/skills/codev/SKILL.md +41 -0
- package/skeleton/.claude/skills/consult/SKILL.md +81 -0
- package/skeleton/.claude/skills/generate-image/SKILL.md +56 -0
- package/skeleton/DEPENDENCIES.md +4 -62
- package/skeleton/builders.md +1 -1
- package/skeleton/consult-types/impl-review.md +18 -9
- package/skeleton/consult-types/integration-review.md +1 -1
- package/skeleton/consult-types/plan-review.md +1 -1
- package/skeleton/consult-types/pr-ready.md +1 -1
- package/skeleton/consult-types/spec-review.md +1 -1
- package/skeleton/porch/prompts/defend.md +1 -1
- package/skeleton/porch/prompts/evaluate.md +2 -2
- package/skeleton/porch/prompts/implement.md +1 -1
- package/skeleton/porch/prompts/plan.md +1 -1
- package/skeleton/porch/prompts/review.md +4 -4
- package/skeleton/porch/prompts/specify.md +1 -1
- package/skeleton/porch/prompts/understand.md +2 -2
- package/skeleton/protocol-schema.json +282 -0
- package/skeleton/protocols/bugfix/builder-prompt.md +60 -0
- package/skeleton/protocols/bugfix/prompts/fix.md +77 -0
- package/skeleton/protocols/bugfix/prompts/investigate.md +77 -0
- package/skeleton/protocols/bugfix/prompts/pr.md +84 -0
- package/skeleton/protocols/bugfix/protocol.json +20 -33
- package/skeleton/protocols/experiment/builder-prompt.md +52 -0
- package/skeleton/protocols/experiment/protocol.json +101 -0
- package/skeleton/protocols/experiment/protocol.md +3 -3
- package/skeleton/protocols/experiment/templates/notes.md +1 -1
- package/skeleton/protocols/maintain/builder-prompt.md +46 -0
- package/skeleton/protocols/maintain/prompts/audit.md +111 -0
- package/skeleton/protocols/maintain/prompts/clean.md +91 -0
- package/skeleton/protocols/maintain/prompts/sync.md +113 -0
- package/skeleton/protocols/maintain/prompts/verify.md +110 -0
- package/skeleton/protocols/maintain/protocol.json +141 -0
- package/skeleton/protocols/maintain/protocol.md +17 -11
- package/skeleton/protocols/protocol-schema.json +54 -1
- package/skeleton/protocols/spir/builder-prompt.md +66 -0
- package/skeleton/protocols/spir/prompts/implement.md +208 -0
- package/skeleton/protocols/{spider → spir}/prompts/plan.md +6 -70
- package/skeleton/protocols/{spider → spir}/prompts/review.md +20 -39
- package/skeleton/protocols/{spider → spir}/prompts/specify.md +24 -59
- package/skeleton/protocols/{spider → spir}/protocol.json +30 -10
- package/skeleton/protocols/{spider → spir}/protocol.md +35 -21
- package/skeleton/protocols/spir/templates/review.md +89 -0
- package/skeleton/protocols/tick/builder-prompt.md +56 -0
- package/skeleton/protocols/tick/protocol.json +7 -2
- package/skeleton/protocols/tick/protocol.md +18 -18
- package/skeleton/protocols/tick/templates/review.md +1 -1
- package/skeleton/resources/commands/agent-farm.md +63 -46
- package/skeleton/resources/commands/codev.md +0 -2
- package/skeleton/resources/commands/overview.md +7 -17
- package/skeleton/resources/workflow-reference.md +4 -4
- package/skeleton/roles/architect.md +151 -306
- package/skeleton/roles/builder.md +115 -332
- package/skeleton/roles/consultant.md +6 -6
- package/skeleton/templates/AGENTS.md +2 -2
- package/skeleton/templates/CLAUDE.md +2 -2
- package/skeleton/templates/cheatsheet.md +7 -5
- package/skeleton/templates/projectlist.md +1 -1
- package/templates/dashboard/index.html +17 -16
- package/templates/dashboard/js/dialogs.js +7 -7
- package/templates/dashboard/js/files.js +2 -2
- package/templates/dashboard/js/main.js +4 -4
- package/templates/dashboard/js/projects.js +3 -3
- package/templates/dashboard/js/tabs.js +1 -1
- package/templates/dashboard/js/utils.js +22 -1
- package/templates/open.html +26 -0
- package/templates/tower.html +731 -91
- package/dist/agent-farm/commands/kickoff.d.ts +0 -20
- package/dist/agent-farm/commands/kickoff.d.ts.map +0 -1
- package/dist/agent-farm/commands/kickoff.js +0 -273
- package/dist/agent-farm/commands/kickoff.js.map +0 -1
- package/dist/agent-farm/commands/rename.d.ts +0 -13
- package/dist/agent-farm/commands/rename.d.ts.map +0 -1
- package/dist/agent-farm/commands/rename.js +0 -33
- package/dist/agent-farm/commands/rename.js.map +0 -1
- package/dist/agent-farm/commands/tutorial.d.ts +0 -10
- package/dist/agent-farm/commands/tutorial.d.ts.map +0 -1
- package/dist/agent-farm/commands/tutorial.js +0 -49
- package/dist/agent-farm/commands/tutorial.js.map +0 -1
- package/dist/agent-farm/commands/util.d.ts +0 -15
- package/dist/agent-farm/commands/util.d.ts.map +0 -1
- package/dist/agent-farm/commands/util.js +0 -108
- package/dist/agent-farm/commands/util.js.map +0 -1
- package/dist/agent-farm/servers/dashboard-server.d.ts +0 -7
- package/dist/agent-farm/servers/dashboard-server.d.ts.map +0 -1
- package/dist/agent-farm/servers/dashboard-server.js +0 -1858
- package/dist/agent-farm/servers/dashboard-server.js.map +0 -1
- package/dist/agent-farm/servers/open-server.d.ts +0 -7
- package/dist/agent-farm/servers/open-server.d.ts.map +0 -1
- package/dist/agent-farm/servers/open-server.js +0 -315
- package/dist/agent-farm/servers/open-server.js.map +0 -1
- package/dist/agent-farm/tutorial/index.d.ts +0 -8
- package/dist/agent-farm/tutorial/index.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/index.js +0 -8
- package/dist/agent-farm/tutorial/index.js.map +0 -1
- package/dist/agent-farm/tutorial/prompts.d.ts +0 -57
- package/dist/agent-farm/tutorial/prompts.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/prompts.js +0 -147
- package/dist/agent-farm/tutorial/prompts.js.map +0 -1
- package/dist/agent-farm/tutorial/runner.d.ts +0 -52
- package/dist/agent-farm/tutorial/runner.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/runner.js +0 -204
- package/dist/agent-farm/tutorial/runner.js.map +0 -1
- package/dist/agent-farm/tutorial/state.d.ts +0 -26
- package/dist/agent-farm/tutorial/state.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/state.js +0 -89
- package/dist/agent-farm/tutorial/state.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/first-spec.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/first-spec.js +0 -136
- package/dist/agent-farm/tutorial/steps/first-spec.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/implementation.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/implementation.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/implementation.js +0 -76
- package/dist/agent-farm/tutorial/steps/implementation.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/index.d.ts +0 -10
- package/dist/agent-farm/tutorial/steps/index.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/index.js +0 -10
- package/dist/agent-farm/tutorial/steps/index.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/planning.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/planning.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/planning.js +0 -143
- package/dist/agent-farm/tutorial/steps/planning.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/review.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/review.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/review.js +0 -78
- package/dist/agent-farm/tutorial/steps/review.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/setup.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/setup.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/setup.js +0 -126
- package/dist/agent-farm/tutorial/steps/setup.js.map +0 -1
- package/dist/agent-farm/tutorial/steps/welcome.d.ts +0 -7
- package/dist/agent-farm/tutorial/steps/welcome.d.ts.map +0 -1
- package/dist/agent-farm/tutorial/steps/welcome.js +0 -50
- package/dist/agent-farm/tutorial/steps/welcome.js.map +0 -1
- package/dist/agent-farm/utils/orphan-handler.d.ts +0 -27
- package/dist/agent-farm/utils/orphan-handler.d.ts.map +0 -1
- package/dist/agent-farm/utils/orphan-handler.js +0 -149
- package/dist/agent-farm/utils/orphan-handler.js.map +0 -1
- package/dist/agent-farm/utils/port-registry.d.ts +0 -58
- package/dist/agent-farm/utils/port-registry.d.ts.map +0 -1
- package/dist/agent-farm/utils/port-registry.js +0 -166
- package/dist/agent-farm/utils/port-registry.js.map +0 -1
- package/dist/agent-farm/utils/terminal-ports.d.ts +0 -18
- package/dist/agent-farm/utils/terminal-ports.d.ts.map +0 -1
- package/dist/agent-farm/utils/terminal-ports.js +0 -35
- package/dist/agent-farm/utils/terminal-ports.js.map +0 -1
- package/dist/commands/pcheck/cache.d.ts +0 -48
- package/dist/commands/pcheck/cache.d.ts.map +0 -1
- package/dist/commands/pcheck/cache.js +0 -170
- package/dist/commands/pcheck/cache.js.map +0 -1
- package/dist/commands/pcheck/evaluator.d.ts +0 -15
- package/dist/commands/pcheck/evaluator.d.ts.map +0 -1
- package/dist/commands/pcheck/evaluator.js +0 -246
- package/dist/commands/pcheck/evaluator.js.map +0 -1
- package/dist/commands/pcheck/index.d.ts +0 -12
- package/dist/commands/pcheck/index.d.ts.map +0 -1
- package/dist/commands/pcheck/index.js +0 -249
- package/dist/commands/pcheck/index.js.map +0 -1
- package/dist/commands/pcheck/parser.d.ts +0 -39
- package/dist/commands/pcheck/parser.d.ts.map +0 -1
- package/dist/commands/pcheck/parser.js +0 -155
- package/dist/commands/pcheck/parser.js.map +0 -1
- package/dist/commands/pcheck/types.d.ts +0 -82
- package/dist/commands/pcheck/types.d.ts.map +0 -1
- package/dist/commands/pcheck/types.js +0 -5
- package/dist/commands/pcheck/types.js.map +0 -1
- package/dist/commands/porch/claude.d.ts +0 -29
- package/dist/commands/porch/claude.d.ts.map +0 -1
- package/dist/commands/porch/claude.js +0 -79
- package/dist/commands/porch/claude.js.map +0 -1
- package/dist/commands/porch/consultation.d.ts +0 -56
- package/dist/commands/porch/consultation.d.ts.map +0 -1
- package/dist/commands/porch/consultation.js +0 -330
- package/dist/commands/porch/consultation.js.map +0 -1
- package/dist/commands/porch/notifications.d.ts +0 -99
- package/dist/commands/porch/notifications.d.ts.map +0 -1
- package/dist/commands/porch/notifications.js +0 -223
- package/dist/commands/porch/notifications.js.map +0 -1
- package/dist/commands/porch/plan-parser.d.ts +0 -38
- package/dist/commands/porch/plan-parser.d.ts.map +0 -1
- package/dist/commands/porch/plan-parser.js +0 -166
- package/dist/commands/porch/plan-parser.js.map +0 -1
- package/dist/commands/porch/protocol-loader.d.ts +0 -46
- package/dist/commands/porch/protocol-loader.d.ts.map +0 -1
- package/dist/commands/porch/protocol-loader.js +0 -262
- package/dist/commands/porch/protocol-loader.js.map +0 -1
- package/dist/commands/porch/repl.d.ts +0 -33
- package/dist/commands/porch/repl.d.ts.map +0 -1
- package/dist/commands/porch/repl.js +0 -206
- package/dist/commands/porch/repl.js.map +0 -1
- package/dist/commands/porch/run.d.ts +0 -15
- package/dist/commands/porch/run.d.ts.map +0 -1
- package/dist/commands/porch/run.js +0 -551
- package/dist/commands/porch/run.js.map +0 -1
- package/dist/commands/porch/signal-parser.d.ts +0 -102
- package/dist/commands/porch/signal-parser.d.ts.map +0 -1
- package/dist/commands/porch/signal-parser.js +0 -199
- package/dist/commands/porch/signal-parser.js.map +0 -1
- package/dist/commands/porch/signals.d.ts +0 -35
- package/dist/commands/porch/signals.d.ts.map +0 -1
- package/dist/commands/porch/signals.js +0 -76
- package/dist/commands/porch/signals.js.map +0 -1
- package/dist/commands/porch2/checks.d.ts +0 -29
- package/dist/commands/porch2/checks.d.ts.map +0 -1
- package/dist/commands/porch2/checks.js +0 -141
- package/dist/commands/porch2/checks.js.map +0 -1
- package/dist/commands/porch2/index.d.ts +0 -38
- package/dist/commands/porch2/index.d.ts.map +0 -1
- package/dist/commands/porch2/index.js +0 -483
- package/dist/commands/porch2/index.js.map +0 -1
- package/dist/commands/porch2/plan.d.ts +0 -70
- package/dist/commands/porch2/plan.d.ts.map +0 -1
- package/dist/commands/porch2/plan.js +0 -227
- package/dist/commands/porch2/plan.js.map +0 -1
- package/dist/commands/porch2/protocol.d.ts +0 -37
- package/dist/commands/porch2/protocol.d.ts.map +0 -1
- package/dist/commands/porch2/protocol.js +0 -183
- package/dist/commands/porch2/protocol.js.map +0 -1
- package/dist/commands/porch2/state.d.ts +0 -35
- package/dist/commands/porch2/state.d.ts.map +0 -1
- package/dist/commands/porch2/state.js +0 -124
- package/dist/commands/porch2/state.js.map +0 -1
- package/dist/commands/porch2/types.d.ts +0 -79
- package/dist/commands/porch2/types.d.ts.map +0 -1
- package/dist/commands/porch2/types.js +0 -8
- package/dist/commands/porch2/types.js.map +0 -1
- package/dist/commands/tower.d.ts +0 -16
- package/dist/commands/tower.d.ts.map +0 -1
- package/dist/commands/tower.js +0 -21
- package/dist/commands/tower.js.map +0 -1
- package/skeleton/config.json +0 -7
- package/skeleton/protocols/spider/prompts/defend.md +0 -215
- package/skeleton/protocols/spider/prompts/evaluate.md +0 -241
- package/skeleton/protocols/spider/prompts/implement.md +0 -149
- package/skeleton/protocols/spider/templates/review.md +0 -207
- /package/skeleton/protocols/{spider → spir}/templates/plan.md +0 -0
- /package/skeleton/protocols/{spider → spir}/templates/spec.md +0 -0
|
@@ -1,23 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Tower server for Agent Farm.
|
|
4
|
-
*
|
|
3
|
+
* Tower server for Agent Farm — orchestrator module.
|
|
4
|
+
* Spec 0105: Tower Server Decomposition
|
|
5
|
+
*
|
|
6
|
+
* Creates HTTP/WS servers, initializes all subsystem modules, and
|
|
7
|
+
* delegates HTTP request handling to tower-routes.ts.
|
|
5
8
|
*/
|
|
6
9
|
import http from 'node:http';
|
|
7
10
|
import fs from 'node:fs';
|
|
8
11
|
import path from 'node:path';
|
|
9
|
-
import net from 'node:net';
|
|
10
|
-
import { spawn, execSync } from 'node:child_process';
|
|
11
12
|
import { homedir } from 'node:os';
|
|
12
13
|
import { fileURLToPath } from 'node:url';
|
|
13
14
|
import { Command } from 'commander';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
15
|
+
import { WebSocketServer } from 'ws';
|
|
16
|
+
import { SessionManager } from '../../terminal/session-manager.js';
|
|
17
|
+
import { startRateLimitCleanup } from './tower-utils.js';
|
|
18
|
+
import { initTunnel, shutdownTunnel, } from './tower-tunnel.js';
|
|
19
|
+
import { initInstances, shutdownInstances, registerKnownProject, getKnownProjectPaths, getInstances, } from './tower-instances.js';
|
|
20
|
+
import { initTerminals, shutdownTerminals, getProjectTerminals, getTerminalManager, getProjectTerminalsEntry, saveTerminalSession, deleteTerminalSession, deleteProjectTerminalSessions, getTerminalsForProject, reconcileTerminalSessions, startGateWatcher, } from './tower-terminals.js';
|
|
21
|
+
import { setupUpgradeHandler, } from './tower-websocket.js';
|
|
22
|
+
import { handleRequest } from './tower-routes.js';
|
|
17
23
|
const __filename = fileURLToPath(import.meta.url);
|
|
18
24
|
const __dirname = path.dirname(__filename);
|
|
19
25
|
// Default port for tower dashboard
|
|
20
26
|
const DEFAULT_PORT = 4100;
|
|
27
|
+
// Rate limiting: cleanup interval for token bucket
|
|
28
|
+
const rateLimitCleanupInterval = startRateLimitCleanup();
|
|
29
|
+
// Shellper session manager (initialized at startup)
|
|
30
|
+
let shellperManager = null;
|
|
21
31
|
// Parse arguments with Commander
|
|
22
32
|
const program = new Command()
|
|
23
33
|
.name('tower-server')
|
|
@@ -52,311 +62,74 @@ function log(level, message) {
|
|
|
52
62
|
}
|
|
53
63
|
}
|
|
54
64
|
}
|
|
65
|
+
// Global exception handlers to catch uncaught errors
|
|
66
|
+
process.on('uncaughtException', (err) => {
|
|
67
|
+
log('ERROR', `Uncaught exception: ${err.message}\n${err.stack}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
process.on('unhandledRejection', (reason) => {
|
|
71
|
+
const message = reason instanceof Error ? `${reason.message}\n${reason.stack}` : String(reason);
|
|
72
|
+
log('ERROR', `Unhandled rejection: ${message}`);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
});
|
|
75
|
+
// Graceful shutdown handler (Phase 2 - Spec 0090)
|
|
76
|
+
async function gracefulShutdown(signal) {
|
|
77
|
+
log('INFO', `Received ${signal}, starting graceful shutdown...`);
|
|
78
|
+
// 1. Stop accepting new connections
|
|
79
|
+
server?.close();
|
|
80
|
+
// 2. Close all WebSocket connections
|
|
81
|
+
if (terminalWss) {
|
|
82
|
+
for (const client of terminalWss.clients) {
|
|
83
|
+
client.close(1001, 'Server shutting down');
|
|
84
|
+
}
|
|
85
|
+
terminalWss.close();
|
|
86
|
+
}
|
|
87
|
+
// 3. Shellper clients: do NOT call shellperManager.shutdown() here.
|
|
88
|
+
// SessionManager.shutdown() disconnects sockets, which triggers ShellperClient
|
|
89
|
+
// 'close' events → PtySession exit(-1) → SQLite row deletion. This would erase
|
|
90
|
+
// the rows that reconcileTerminalSessions() needs on restart.
|
|
91
|
+
// Instead, let the process exit naturally — OS closes all sockets, and shellpers
|
|
92
|
+
// detect the disconnection and keep running. SQLite rows are preserved.
|
|
93
|
+
if (shellperManager) {
|
|
94
|
+
log('INFO', 'Shellper sessions will continue running (sockets close on process exit)');
|
|
95
|
+
}
|
|
96
|
+
// 4. Stop rate limit cleanup
|
|
97
|
+
clearInterval(rateLimitCleanupInterval);
|
|
98
|
+
// 5. Disconnect tunnel (Spec 0097 Phase 4 / Spec 0105 Phase 2)
|
|
99
|
+
shutdownTunnel();
|
|
100
|
+
// 6. Tear down instance module (Spec 0105 Phase 3)
|
|
101
|
+
shutdownInstances();
|
|
102
|
+
// 7. Tear down terminal module (Spec 0105 Phase 4) — stops gate watcher, shuts down terminal manager
|
|
103
|
+
shutdownTerminals();
|
|
104
|
+
log('INFO', 'Graceful shutdown complete');
|
|
105
|
+
process.exit(0);
|
|
106
|
+
}
|
|
107
|
+
// Catch signals for clean shutdown
|
|
108
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
109
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
55
110
|
if (isNaN(port) || port < 1 || port > 65535) {
|
|
56
111
|
log('ERROR', `Invalid port "${portArg}". Must be a number between 1 and 65535.`);
|
|
57
112
|
process.exit(1);
|
|
58
113
|
}
|
|
59
114
|
log('INFO', `Tower server starting on port ${port}`);
|
|
115
|
+
// SSE (Server-Sent Events) infrastructure for push notifications
|
|
116
|
+
const sseClients = [];
|
|
117
|
+
let notificationIdCounter = 0;
|
|
60
118
|
/**
|
|
61
|
-
*
|
|
62
|
-
*/
|
|
63
|
-
function loadPortAllocations() {
|
|
64
|
-
try {
|
|
65
|
-
const db = getGlobalDb();
|
|
66
|
-
return db.prepare('SELECT * FROM port_allocations ORDER BY last_used_at DESC').all();
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
log('ERROR', `Error loading port allocations: ${err.message}`);
|
|
70
|
-
return [];
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
/**
|
|
74
|
-
* Check if a port is listening
|
|
75
|
-
*/
|
|
76
|
-
async function isPortListening(port) {
|
|
77
|
-
return new Promise((resolve) => {
|
|
78
|
-
const socket = new net.Socket();
|
|
79
|
-
socket.setTimeout(1000);
|
|
80
|
-
socket.on('connect', () => {
|
|
81
|
-
socket.destroy();
|
|
82
|
-
resolve(true);
|
|
83
|
-
});
|
|
84
|
-
socket.on('timeout', () => {
|
|
85
|
-
socket.destroy();
|
|
86
|
-
resolve(false);
|
|
87
|
-
});
|
|
88
|
-
socket.on('error', () => {
|
|
89
|
-
resolve(false);
|
|
90
|
-
});
|
|
91
|
-
socket.connect(port, '127.0.0.1');
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Get project name from path
|
|
96
|
-
*/
|
|
97
|
-
function getProjectName(projectPath) {
|
|
98
|
-
return path.basename(projectPath);
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Get all instances with their status
|
|
102
|
-
*/
|
|
103
|
-
async function getInstances() {
|
|
104
|
-
const allocations = loadPortAllocations();
|
|
105
|
-
const instances = [];
|
|
106
|
-
for (const allocation of allocations) {
|
|
107
|
-
// Skip builder worktrees - they're managed by their parent project
|
|
108
|
-
if (allocation.project_path.includes('/.builders/')) {
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
const basePort = allocation.base_port;
|
|
112
|
-
const dashboardPort = basePort;
|
|
113
|
-
const architectPort = basePort + 1;
|
|
114
|
-
// Check if dashboard is running (main indicator of running instance)
|
|
115
|
-
const dashboardActive = await isPortListening(dashboardPort);
|
|
116
|
-
// Only check architect port if dashboard is active (to avoid unnecessary probing)
|
|
117
|
-
const architectActive = dashboardActive ? await isPortListening(architectPort) : false;
|
|
118
|
-
const ports = [
|
|
119
|
-
{
|
|
120
|
-
type: 'Dashboard',
|
|
121
|
-
port: dashboardPort,
|
|
122
|
-
url: `http://localhost:${dashboardPort}`,
|
|
123
|
-
active: dashboardActive,
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
type: 'Architect',
|
|
127
|
-
port: architectPort,
|
|
128
|
-
url: `http://localhost:${architectPort}`,
|
|
129
|
-
active: architectActive,
|
|
130
|
-
},
|
|
131
|
-
];
|
|
132
|
-
instances.push({
|
|
133
|
-
projectPath: allocation.project_path,
|
|
134
|
-
projectName: getProjectName(allocation.project_path),
|
|
135
|
-
basePort,
|
|
136
|
-
dashboardPort,
|
|
137
|
-
architectPort,
|
|
138
|
-
registered: allocation.registered_at,
|
|
139
|
-
lastUsed: allocation.last_used_at,
|
|
140
|
-
running: dashboardActive,
|
|
141
|
-
ports,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
// Sort: running first, then by last used (most recent first)
|
|
145
|
-
instances.sort((a, b) => {
|
|
146
|
-
if (a.running !== b.running) {
|
|
147
|
-
return a.running ? -1 : 1;
|
|
148
|
-
}
|
|
149
|
-
const aTime = a.lastUsed ? new Date(a.lastUsed).getTime() : 0;
|
|
150
|
-
const bTime = b.lastUsed ? new Date(b.lastUsed).getTime() : 0;
|
|
151
|
-
return bTime - aTime;
|
|
152
|
-
});
|
|
153
|
-
return instances;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* Get directory suggestions for autocomplete
|
|
157
|
-
*/
|
|
158
|
-
async function getDirectorySuggestions(inputPath) {
|
|
159
|
-
// Default to home directory if empty
|
|
160
|
-
if (!inputPath) {
|
|
161
|
-
inputPath = homedir();
|
|
162
|
-
}
|
|
163
|
-
// Expand ~ to home directory
|
|
164
|
-
if (inputPath.startsWith('~')) {
|
|
165
|
-
inputPath = inputPath.replace('~', homedir());
|
|
166
|
-
}
|
|
167
|
-
// Determine the directory to list and the prefix to filter by
|
|
168
|
-
let dirToList;
|
|
169
|
-
let prefix;
|
|
170
|
-
if (inputPath.endsWith('/')) {
|
|
171
|
-
// User typed a complete directory path, list its contents
|
|
172
|
-
dirToList = inputPath;
|
|
173
|
-
prefix = '';
|
|
174
|
-
}
|
|
175
|
-
else {
|
|
176
|
-
// User is typing a partial name, list parent and filter
|
|
177
|
-
dirToList = path.dirname(inputPath);
|
|
178
|
-
prefix = path.basename(inputPath).toLowerCase();
|
|
179
|
-
}
|
|
180
|
-
// Check if directory exists
|
|
181
|
-
if (!fs.existsSync(dirToList)) {
|
|
182
|
-
return [];
|
|
183
|
-
}
|
|
184
|
-
const stat = fs.statSync(dirToList);
|
|
185
|
-
if (!stat.isDirectory()) {
|
|
186
|
-
return [];
|
|
187
|
-
}
|
|
188
|
-
// Read directory contents
|
|
189
|
-
const entries = fs.readdirSync(dirToList, { withFileTypes: true });
|
|
190
|
-
// Filter to directories only, apply prefix filter, and check for codev/
|
|
191
|
-
const suggestions = [];
|
|
192
|
-
for (const entry of entries) {
|
|
193
|
-
if (!entry.isDirectory())
|
|
194
|
-
continue;
|
|
195
|
-
if (entry.name.startsWith('.'))
|
|
196
|
-
continue; // Skip hidden directories
|
|
197
|
-
const name = entry.name.toLowerCase();
|
|
198
|
-
if (prefix && !name.startsWith(prefix))
|
|
199
|
-
continue;
|
|
200
|
-
const fullPath = path.join(dirToList, entry.name);
|
|
201
|
-
const isProject = fs.existsSync(path.join(fullPath, 'codev'));
|
|
202
|
-
suggestions.push({ path: fullPath, isProject });
|
|
203
|
-
}
|
|
204
|
-
// Sort: projects first, then alphabetically
|
|
205
|
-
suggestions.sort((a, b) => {
|
|
206
|
-
if (a.isProject !== b.isProject) {
|
|
207
|
-
return a.isProject ? -1 : 1;
|
|
208
|
-
}
|
|
209
|
-
return a.path.localeCompare(b.path);
|
|
210
|
-
});
|
|
211
|
-
// Limit to 20 suggestions
|
|
212
|
-
return suggestions.slice(0, 20);
|
|
213
|
-
}
|
|
214
|
-
/**
|
|
215
|
-
* Launch a new agent-farm instance
|
|
216
|
-
* First stops any stale state, then starts fresh
|
|
217
|
-
* Auto-adopts non-codev directories
|
|
119
|
+
* Broadcast a notification to all connected SSE clients
|
|
218
120
|
*/
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
return { success: false, error: `Path does not exist: ${projectPath}` };
|
|
225
|
-
}
|
|
226
|
-
// Validate it's a directory
|
|
227
|
-
const stat = fs.statSync(projectPath);
|
|
228
|
-
if (!stat.isDirectory()) {
|
|
229
|
-
return { success: false, error: `Not a directory: ${projectPath}` };
|
|
230
|
-
}
|
|
231
|
-
// Auto-adopt non-codev directories
|
|
232
|
-
const codevDir = path.join(projectPath, 'codev');
|
|
233
|
-
let adopted = false;
|
|
234
|
-
if (!fs.existsSync(codevDir)) {
|
|
121
|
+
function broadcastNotification(notification) {
|
|
122
|
+
const id = ++notificationIdCounter;
|
|
123
|
+
const data = JSON.stringify({ ...notification, id });
|
|
124
|
+
const message = `id: ${id}\ndata: ${data}\n\n`;
|
|
125
|
+
for (const client of sseClients) {
|
|
235
126
|
try {
|
|
236
|
-
|
|
237
|
-
execSync('npx codev adopt --yes', {
|
|
238
|
-
cwd: projectPath,
|
|
239
|
-
stdio: 'pipe',
|
|
240
|
-
timeout: 30000,
|
|
241
|
-
});
|
|
242
|
-
adopted = true;
|
|
243
|
-
log('INFO', `Auto-adopted codev in: ${projectPath}`);
|
|
244
|
-
}
|
|
245
|
-
catch (err) {
|
|
246
|
-
return { success: false, error: `Failed to adopt codev: ${err.message}` };
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
// Use codev af command (avoids npx cache issues)
|
|
250
|
-
// Falls back to npx codev af if codev not in PATH
|
|
251
|
-
// SECURITY: Use spawn with cwd option to avoid command injection
|
|
252
|
-
// Do NOT use bash -c with string concatenation
|
|
253
|
-
try {
|
|
254
|
-
// First, stop any existing (possibly stale) instance
|
|
255
|
-
const stopChild = spawn('codev', ['af', 'stop'], {
|
|
256
|
-
cwd: projectPath,
|
|
257
|
-
stdio: 'ignore',
|
|
258
|
-
});
|
|
259
|
-
// Wait for stop to complete
|
|
260
|
-
await new Promise((resolve) => {
|
|
261
|
-
stopChild.on('close', () => resolve());
|
|
262
|
-
stopChild.on('error', () => resolve());
|
|
263
|
-
// Timeout after 3 seconds
|
|
264
|
-
setTimeout(() => resolve(), 3000);
|
|
265
|
-
});
|
|
266
|
-
// Small delay to ensure cleanup
|
|
267
|
-
await new Promise((resolve) => setTimeout(resolve, 500));
|
|
268
|
-
// Now start using codev af (avoids npx caching issues)
|
|
269
|
-
// Capture output to detect errors
|
|
270
|
-
const child = spawn('codev', ['af', 'start'], {
|
|
271
|
-
detached: true,
|
|
272
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
273
|
-
cwd: projectPath,
|
|
274
|
-
});
|
|
275
|
-
let stdout = '';
|
|
276
|
-
let stderr = '';
|
|
277
|
-
child.stdout?.on('data', (data) => {
|
|
278
|
-
stdout += data.toString();
|
|
279
|
-
});
|
|
280
|
-
child.stderr?.on('data', (data) => {
|
|
281
|
-
stderr += data.toString();
|
|
282
|
-
});
|
|
283
|
-
// Wait a moment for the process to start (or fail)
|
|
284
|
-
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
285
|
-
// Check if the dashboard port is listening
|
|
286
|
-
// Resolve symlinks (macOS /tmp -> /private/tmp)
|
|
287
|
-
const resolvedPath = fs.realpathSync(projectPath);
|
|
288
|
-
const db = getGlobalDb();
|
|
289
|
-
const allocation = db
|
|
290
|
-
.prepare('SELECT base_port FROM port_allocations WHERE project_path = ? OR project_path = ?')
|
|
291
|
-
.get(projectPath, resolvedPath);
|
|
292
|
-
if (allocation) {
|
|
293
|
-
const dashboardPort = allocation.base_port;
|
|
294
|
-
const isRunning = await isPortListening(dashboardPort);
|
|
295
|
-
if (!isRunning) {
|
|
296
|
-
// Process failed to start - try to get error info
|
|
297
|
-
const errorInfo = stderr || stdout || 'Unknown error - check codev installation';
|
|
298
|
-
child.unref();
|
|
299
|
-
return {
|
|
300
|
-
success: false,
|
|
301
|
-
error: `Failed to start: ${errorInfo.trim().split('\n')[0]}`,
|
|
302
|
-
};
|
|
303
|
-
}
|
|
127
|
+
client.res.write(message);
|
|
304
128
|
}
|
|
305
|
-
|
|
306
|
-
//
|
|
307
|
-
if (stderr || stdout) {
|
|
308
|
-
const errorInfo = stderr || stdout;
|
|
309
|
-
child.unref();
|
|
310
|
-
return {
|
|
311
|
-
success: false,
|
|
312
|
-
error: `Failed to start: ${errorInfo.trim().split('\n')[0]}`,
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
child.unref();
|
|
317
|
-
return { success: true, adopted };
|
|
318
|
-
}
|
|
319
|
-
catch (err) {
|
|
320
|
-
return { success: false, error: `Failed to launch: ${err.message}` };
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Get PID of process listening on a port
|
|
325
|
-
*/
|
|
326
|
-
function getProcessOnPort(targetPort) {
|
|
327
|
-
try {
|
|
328
|
-
const result = execSync(`lsof -ti :${targetPort} 2>/dev/null`, { encoding: 'utf-8' });
|
|
329
|
-
const pid = parseInt(result.trim().split('\n')[0], 10);
|
|
330
|
-
return isNaN(pid) ? null : pid;
|
|
331
|
-
}
|
|
332
|
-
catch {
|
|
333
|
-
return null;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Stop an agent-farm instance by killing processes on its ports
|
|
338
|
-
*/
|
|
339
|
-
async function stopInstance(basePort) {
|
|
340
|
-
const stopped = [];
|
|
341
|
-
// Kill processes on the main port range (dashboard, architect, builders)
|
|
342
|
-
// Dashboard is basePort, architect is basePort+1, builders start at basePort+100
|
|
343
|
-
const portsToCheck = [basePort, basePort + 1];
|
|
344
|
-
for (const p of portsToCheck) {
|
|
345
|
-
const pid = getProcessOnPort(p);
|
|
346
|
-
if (pid) {
|
|
347
|
-
try {
|
|
348
|
-
process.kill(pid, 'SIGTERM');
|
|
349
|
-
stopped.push(p);
|
|
350
|
-
}
|
|
351
|
-
catch {
|
|
352
|
-
// Process may have already exited
|
|
353
|
-
}
|
|
129
|
+
catch {
|
|
130
|
+
// Client disconnected, will be cleaned up on next iteration
|
|
354
131
|
}
|
|
355
132
|
}
|
|
356
|
-
if (stopped.length === 0) {
|
|
357
|
-
return { success: true, error: 'No processes found to stop', stopped };
|
|
358
|
-
}
|
|
359
|
-
return { success: true, stopped };
|
|
360
133
|
}
|
|
361
134
|
/**
|
|
362
135
|
* Find the tower template
|
|
@@ -372,185 +145,94 @@ function findTemplatePath() {
|
|
|
372
145
|
}
|
|
373
146
|
return null;
|
|
374
147
|
}
|
|
375
|
-
// escapeHtml, parseJsonBody, isRequestAllowed imported from ../utils/server-utils.js
|
|
376
148
|
// Find template path
|
|
377
149
|
const templatePath = findTemplatePath();
|
|
378
|
-
//
|
|
150
|
+
// WebSocket server for terminal connections (Phase 2 - Spec 0090)
|
|
151
|
+
let terminalWss = null;
|
|
152
|
+
// React dashboard dist path (for serving directly from tower)
|
|
153
|
+
// Phase 4 (Spec 0090): Tower serves everything directly, no dashboard-server
|
|
154
|
+
const reactDashboardPath = path.resolve(__dirname, '../../../dashboard/dist');
|
|
155
|
+
const hasReactDashboard = fs.existsSync(reactDashboardPath);
|
|
156
|
+
if (hasReactDashboard) {
|
|
157
|
+
log('INFO', `React dashboard found at: ${reactDashboardPath}`);
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
log('WARN', 'React dashboard not found - project dashboards will not work');
|
|
161
|
+
}
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// Route context — wires orchestrator state into route handlers
|
|
164
|
+
// ============================================================================
|
|
165
|
+
const routeCtx = {
|
|
166
|
+
log,
|
|
167
|
+
port,
|
|
168
|
+
templatePath,
|
|
169
|
+
reactDashboardPath,
|
|
170
|
+
hasReactDashboard,
|
|
171
|
+
getShellperManager: () => shellperManager,
|
|
172
|
+
broadcastNotification,
|
|
173
|
+
addSseClient: (client) => {
|
|
174
|
+
sseClients.push(client);
|
|
175
|
+
},
|
|
176
|
+
removeSseClient: (id) => {
|
|
177
|
+
const index = sseClients.findIndex(c => c.id === id);
|
|
178
|
+
if (index !== -1) {
|
|
179
|
+
sseClients.splice(index, 1);
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
// ============================================================================
|
|
184
|
+
// Create server — delegates all HTTP handling to tower-routes.ts
|
|
185
|
+
// ============================================================================
|
|
379
186
|
const server = http.createServer(async (req, res) => {
|
|
380
|
-
|
|
381
|
-
if (!isRequestAllowed(req)) {
|
|
382
|
-
res.writeHead(403, { 'Content-Type': 'text/plain' });
|
|
383
|
-
res.end('Forbidden');
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
// CORS headers
|
|
387
|
-
const origin = req.headers.origin;
|
|
388
|
-
if (origin && (origin.startsWith('http://localhost:') || origin.startsWith('http://127.0.0.1:'))) {
|
|
389
|
-
res.setHeader('Access-Control-Allow-Origin', origin);
|
|
390
|
-
}
|
|
391
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
392
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
393
|
-
res.setHeader('Cache-Control', 'no-store');
|
|
394
|
-
if (req.method === 'OPTIONS') {
|
|
395
|
-
res.writeHead(200);
|
|
396
|
-
res.end();
|
|
397
|
-
return;
|
|
398
|
-
}
|
|
399
|
-
const url = new URL(req.url || '/', `http://localhost:${port}`);
|
|
400
|
-
try {
|
|
401
|
-
// API: Get status of all instances
|
|
402
|
-
if (req.method === 'GET' && url.pathname === '/api/status') {
|
|
403
|
-
const instances = await getInstances();
|
|
404
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
405
|
-
res.end(JSON.stringify({ instances }));
|
|
406
|
-
return;
|
|
407
|
-
}
|
|
408
|
-
// API: Browse directories for autocomplete
|
|
409
|
-
if (req.method === 'GET' && url.pathname === '/api/browse') {
|
|
410
|
-
const inputPath = url.searchParams.get('path') || '';
|
|
411
|
-
try {
|
|
412
|
-
const suggestions = await getDirectorySuggestions(inputPath);
|
|
413
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
414
|
-
res.end(JSON.stringify({ suggestions }));
|
|
415
|
-
}
|
|
416
|
-
catch (err) {
|
|
417
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
418
|
-
res.end(JSON.stringify({ suggestions: [], error: err.message }));
|
|
419
|
-
}
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
// API: Create new project
|
|
423
|
-
if (req.method === 'POST' && url.pathname === '/api/create') {
|
|
424
|
-
const body = await parseJsonBody(req);
|
|
425
|
-
const parentPath = body.parent;
|
|
426
|
-
const projectName = body.name;
|
|
427
|
-
if (!parentPath || !projectName) {
|
|
428
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
429
|
-
res.end(JSON.stringify({ success: false, error: 'Missing parent or name' }));
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
432
|
-
// Validate project name
|
|
433
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(projectName)) {
|
|
434
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
435
|
-
res.end(JSON.stringify({ success: false, error: 'Invalid project name' }));
|
|
436
|
-
return;
|
|
437
|
-
}
|
|
438
|
-
// Expand ~ to home directory
|
|
439
|
-
let expandedParent = parentPath;
|
|
440
|
-
if (expandedParent.startsWith('~')) {
|
|
441
|
-
expandedParent = expandedParent.replace('~', homedir());
|
|
442
|
-
}
|
|
443
|
-
// Validate parent exists
|
|
444
|
-
if (!fs.existsSync(expandedParent)) {
|
|
445
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
446
|
-
res.end(JSON.stringify({ success: false, error: `Parent directory does not exist: ${parentPath}` }));
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
const projectPath = path.join(expandedParent, projectName);
|
|
450
|
-
// Check if project already exists
|
|
451
|
-
if (fs.existsSync(projectPath)) {
|
|
452
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
453
|
-
res.end(JSON.stringify({ success: false, error: `Directory already exists: ${projectPath}` }));
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
try {
|
|
457
|
-
// Run codev init (it creates the directory)
|
|
458
|
-
execSync(`codev init --yes "${projectName}"`, {
|
|
459
|
-
cwd: expandedParent,
|
|
460
|
-
stdio: 'pipe',
|
|
461
|
-
timeout: 60000,
|
|
462
|
-
});
|
|
463
|
-
// Launch the instance
|
|
464
|
-
const launchResult = await launchInstance(projectPath);
|
|
465
|
-
if (!launchResult.success) {
|
|
466
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
467
|
-
res.end(JSON.stringify({ success: false, error: launchResult.error }));
|
|
468
|
-
return;
|
|
469
|
-
}
|
|
470
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
471
|
-
res.end(JSON.stringify({ success: true, projectPath }));
|
|
472
|
-
}
|
|
473
|
-
catch (err) {
|
|
474
|
-
// Clean up on failure
|
|
475
|
-
try {
|
|
476
|
-
if (fs.existsSync(projectPath)) {
|
|
477
|
-
fs.rmSync(projectPath, { recursive: true });
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
catch {
|
|
481
|
-
// Ignore cleanup errors
|
|
482
|
-
}
|
|
483
|
-
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
484
|
-
res.end(JSON.stringify({ success: false, error: `Failed to create project: ${err.message}` }));
|
|
485
|
-
}
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
// API: Launch new instance
|
|
489
|
-
if (req.method === 'POST' && url.pathname === '/api/launch') {
|
|
490
|
-
const body = await parseJsonBody(req);
|
|
491
|
-
const projectPath = body.projectPath;
|
|
492
|
-
if (!projectPath) {
|
|
493
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
494
|
-
res.end(JSON.stringify({ success: false, error: 'Missing projectPath' }));
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
497
|
-
const result = await launchInstance(projectPath);
|
|
498
|
-
res.writeHead(result.success ? 200 : 400, { 'Content-Type': 'application/json' });
|
|
499
|
-
res.end(JSON.stringify(result));
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
// API: Stop an instance
|
|
503
|
-
if (req.method === 'POST' && url.pathname === '/api/stop') {
|
|
504
|
-
const body = await parseJsonBody(req);
|
|
505
|
-
const basePort = body.basePort;
|
|
506
|
-
if (!basePort) {
|
|
507
|
-
res.writeHead(400, { 'Content-Type': 'application/json' });
|
|
508
|
-
res.end(JSON.stringify({ success: false, error: 'Missing basePort' }));
|
|
509
|
-
return;
|
|
510
|
-
}
|
|
511
|
-
const result = await stopInstance(basePort);
|
|
512
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
513
|
-
res.end(JSON.stringify(result));
|
|
514
|
-
return;
|
|
515
|
-
}
|
|
516
|
-
// Serve dashboard
|
|
517
|
-
if (req.method === 'GET' && (url.pathname === '/' || url.pathname === '/index.html')) {
|
|
518
|
-
if (!templatePath) {
|
|
519
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
520
|
-
res.end('Template not found. Make sure tower.html exists in agent-farm/templates/');
|
|
521
|
-
return;
|
|
522
|
-
}
|
|
523
|
-
try {
|
|
524
|
-
const template = fs.readFileSync(templatePath, 'utf-8');
|
|
525
|
-
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
526
|
-
res.end(template);
|
|
527
|
-
}
|
|
528
|
-
catch (err) {
|
|
529
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
530
|
-
res.end('Error loading template: ' + err.message);
|
|
531
|
-
}
|
|
532
|
-
return;
|
|
533
|
-
}
|
|
534
|
-
// 404 for everything else
|
|
535
|
-
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
536
|
-
res.end('Not found');
|
|
537
|
-
}
|
|
538
|
-
catch (err) {
|
|
539
|
-
log('ERROR', `Request error: ${err.message}`);
|
|
540
|
-
res.writeHead(500, { 'Content-Type': 'text/plain' });
|
|
541
|
-
res.end('Internal server error: ' + err.message);
|
|
542
|
-
}
|
|
187
|
+
await handleRequest(req, res, routeCtx);
|
|
543
188
|
});
|
|
544
189
|
// SECURITY: Bind to localhost only to prevent network exposure
|
|
545
|
-
server.listen(port, '127.0.0.1', () => {
|
|
190
|
+
server.listen(port, '127.0.0.1', async () => {
|
|
546
191
|
log('INFO', `Tower server listening at http://localhost:${port}`);
|
|
192
|
+
// Initialize shellper session manager for persistent terminals
|
|
193
|
+
const socketDir = path.join(homedir(), '.codev', 'run');
|
|
194
|
+
const shellperScript = path.join(__dirname, '..', '..', 'terminal', 'shellper-main.js');
|
|
195
|
+
shellperManager = new SessionManager({
|
|
196
|
+
socketDir,
|
|
197
|
+
shellperScript,
|
|
198
|
+
nodeExecutable: process.execPath,
|
|
199
|
+
});
|
|
200
|
+
const staleCleaned = await shellperManager.cleanupStaleSockets();
|
|
201
|
+
if (staleCleaned > 0) {
|
|
202
|
+
log('INFO', `Cleaned up ${staleCleaned} stale shellper socket(s)`);
|
|
203
|
+
}
|
|
204
|
+
log('INFO', 'Shellper session manager initialized');
|
|
205
|
+
// Spec 0105 Phase 4: Initialize terminal management module
|
|
206
|
+
initTerminals({
|
|
207
|
+
log,
|
|
208
|
+
shellperManager,
|
|
209
|
+
registerKnownProject,
|
|
210
|
+
getKnownProjectPaths,
|
|
211
|
+
});
|
|
212
|
+
// Spec 0105 Phase 3: Initialize instance lifecycle module
|
|
213
|
+
// Must be before reconcileTerminalSessions() so instance APIs are available
|
|
214
|
+
// as soon as the server starts accepting requests.
|
|
215
|
+
initInstances({
|
|
216
|
+
log,
|
|
217
|
+
projectTerminals: getProjectTerminals(),
|
|
218
|
+
getTerminalManager,
|
|
219
|
+
shellperManager,
|
|
220
|
+
getProjectTerminalsEntry,
|
|
221
|
+
saveTerminalSession,
|
|
222
|
+
deleteTerminalSession,
|
|
223
|
+
deleteProjectTerminalSessions,
|
|
224
|
+
getTerminalsForProject,
|
|
225
|
+
});
|
|
226
|
+
// TICK-001: Reconcile terminal sessions from previous run
|
|
227
|
+
await reconcileTerminalSessions();
|
|
228
|
+
// Spec 0100: Start background gate watcher for af send notifications
|
|
229
|
+
startGateWatcher();
|
|
230
|
+
log('INFO', 'Gate watcher started (10s poll interval)');
|
|
231
|
+
// Spec 0097 Phase 4 / Spec 0105 Phase 2: Initialize cloud tunnel
|
|
232
|
+
await initTunnel({ port, log, projectTerminals: getProjectTerminals(), terminalManager: getTerminalManager() }, { getInstances });
|
|
547
233
|
});
|
|
548
|
-
//
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
});
|
|
553
|
-
process.on('unhandledRejection', (reason) => {
|
|
554
|
-
log('ERROR', `Unhandled rejection: ${reason}`);
|
|
555
|
-
});
|
|
234
|
+
// Initialize terminal WebSocket server (Phase 2 - Spec 0090)
|
|
235
|
+
terminalWss = new WebSocketServer({ noServer: true });
|
|
236
|
+
// Spec 0105 Phase 5: WebSocket upgrade handler extracted to tower-websocket.ts
|
|
237
|
+
setupUpgradeHandler(server, terminalWss, port);
|
|
556
238
|
//# sourceMappingURL=tower-server.js.map
|