agent-tempo 1.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/CLAUDE.md +213 -0
- package/LICENSE +21 -0
- package/README.md +289 -0
- package/assets/icon-32.png +0 -0
- package/assets/icon-512.png +0 -0
- package/assets/icon-64.png +0 -0
- package/assets/icon-dark-32.png +0 -0
- package/assets/icon-dark-64.png +0 -0
- package/assets/icon-dark.svg +9 -0
- package/assets/icon.svg +9 -0
- package/assets/logo-dark.svg +11 -0
- package/assets/logo-light.svg +11 -0
- package/dashboard/README.md +91 -0
- package/dashboard/dist/assets/index-CB78ToNE.css +2 -0
- package/dashboard/dist/assets/index-_5jV0Znu.js +62 -0
- package/dashboard/dist/assets/index-_5jV0Znu.js.map +1 -0
- package/dashboard/dist/index.html +21 -0
- package/dashboard/package.json +47 -0
- package/dist/activities/hard-terminate.d.ts +32 -0
- package/dist/activities/hard-terminate.js +460 -0
- package/dist/activities/maestro.d.ts +72 -0
- package/dist/activities/maestro.js +254 -0
- package/dist/activities/outbox.d.ts +188 -0
- package/dist/activities/outbox.js +849 -0
- package/dist/activities/resolve.d.ts +64 -0
- package/dist/activities/resolve.js +129 -0
- package/dist/activities/schedule-fire.d.ts +36 -0
- package/dist/activities/schedule-fire.js +147 -0
- package/dist/adapters/base.d.ts +426 -0
- package/dist/adapters/base.js +1270 -0
- package/dist/adapters/claude-api/adapter.d.ts +168 -0
- package/dist/adapters/claude-api/adapter.js +797 -0
- package/dist/adapters/claude-api/api-error.d.ts +96 -0
- package/dist/adapters/claude-api/api-error.js +191 -0
- package/dist/adapters/claude-api/index.d.ts +16 -0
- package/dist/adapters/claude-api/index.js +21 -0
- package/dist/adapters/claude-api/mcp-bridge.d.ts +50 -0
- package/dist/adapters/claude-api/mcp-bridge.js +157 -0
- package/dist/adapters/claude-code/adapter.d.ts +133 -0
- package/dist/adapters/claude-code/adapter.js +274 -0
- package/dist/adapters/claude-code/index.d.ts +15 -0
- package/dist/adapters/claude-code/index.js +20 -0
- package/dist/adapters/claude-code-headless/adapter.d.ts +131 -0
- package/dist/adapters/claude-code-headless/adapter.js +710 -0
- package/dist/adapters/claude-code-headless/error-mapper.d.ts +107 -0
- package/dist/adapters/claude-code-headless/error-mapper.js +281 -0
- package/dist/adapters/claude-code-headless/index.d.ts +17 -0
- package/dist/adapters/claude-code-headless/index.js +26 -0
- package/dist/adapters/claude-code-headless/pre-flight.d.ts +51 -0
- package/dist/adapters/claude-code-headless/pre-flight.js +207 -0
- package/dist/adapters/claude-code-headless/prompt.d.ts +93 -0
- package/dist/adapters/claude-code-headless/prompt.js +79 -0
- package/dist/adapters/claude-code-headless/stream-json.d.ts +242 -0
- package/dist/adapters/claude-code-headless/stream-json.js +208 -0
- package/dist/adapters/claude-code-headless/types.d.ts +28 -0
- package/dist/adapters/claude-code-headless/types.js +36 -0
- package/dist/adapters/copilot/adapter.d.ts +100 -0
- package/dist/adapters/copilot/adapter.js +730 -0
- package/dist/adapters/copilot/index.d.ts +15 -0
- package/dist/adapters/copilot/index.js +20 -0
- package/dist/adapters/index.d.ts +42 -0
- package/dist/adapters/index.js +115 -0
- package/dist/adapters/opencode/adapter.d.ts +82 -0
- package/dist/adapters/opencode/adapter.js +710 -0
- package/dist/adapters/opencode/config.d.ts +90 -0
- package/dist/adapters/opencode/config.js +137 -0
- package/dist/adapters/opencode/helpers.d.ts +40 -0
- package/dist/adapters/opencode/helpers.js +144 -0
- package/dist/adapters/opencode/index.d.ts +12 -0
- package/dist/adapters/opencode/index.js +17 -0
- package/dist/adapters/opencode/server-bridge.d.ts +124 -0
- package/dist/adapters/opencode/server-bridge.js +216 -0
- package/dist/adapters/sdk/base.d.ts +95 -0
- package/dist/adapters/sdk/base.js +134 -0
- package/dist/adapters/sdk/system-prompt.d.ts +64 -0
- package/dist/adapters/sdk/system-prompt.js +78 -0
- package/dist/adapters/terminal-error.d.ts +27 -0
- package/dist/adapters/terminal-error.js +39 -0
- package/dist/channel.d.ts +3 -0
- package/dist/channel.js +48 -0
- package/dist/cli/commands.d.ts +245 -0
- package/dist/cli/commands.js +2438 -0
- package/dist/cli/config-command.d.ts +8 -0
- package/dist/cli/config-command.js +254 -0
- package/dist/cli/daemon-command.d.ts +57 -0
- package/dist/cli/daemon-command.js +493 -0
- package/dist/cli/daemon.d.ts +217 -0
- package/dist/cli/daemon.js +632 -0
- package/dist/cli/dashboard-command.d.ts +20 -0
- package/dist/cli/dashboard-command.js +241 -0
- package/dist/cli/dev-banner.d.ts +107 -0
- package/dist/cli/dev-banner.js +190 -0
- package/dist/cli/dev-mode-bootstrap.d.ts +29 -0
- package/dist/cli/dev-mode-bootstrap.js +36 -0
- package/dist/cli/dev-verbs.d.ts +43 -0
- package/dist/cli/dev-verbs.js +254 -0
- package/dist/cli/help-text.d.ts +1 -0
- package/dist/cli/help-text.js +158 -0
- package/dist/cli/legacy-migration.d.ts +35 -0
- package/dist/cli/legacy-migration.js +335 -0
- package/dist/cli/mcp.d.ts +8 -0
- package/dist/cli/mcp.js +63 -0
- package/dist/cli/output.d.ts +12 -0
- package/dist/cli/output.js +37 -0
- package/dist/cli/preflight.d.ts +9 -0
- package/dist/cli/preflight.js +96 -0
- package/dist/cli/removed-verbs.d.ts +9 -0
- package/dist/cli/removed-verbs.js +78 -0
- package/dist/cli/sa-preflight.d.ts +99 -0
- package/dist/cli/sa-preflight.js +183 -0
- package/dist/cli/scenarios-command.d.ts +6 -0
- package/dist/cli/scenarios-command.js +167 -0
- package/dist/cli/startup.d.ts +112 -0
- package/dist/cli/startup.js +641 -0
- package/dist/cli/upgrade-command.d.ts +5 -0
- package/dist/cli/upgrade-command.js +240 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +680 -0
- package/dist/client/core.d.ts +33 -0
- package/dist/client/core.js +1260 -0
- package/dist/client/ensure-conductor-spawned.d.ts +35 -0
- package/dist/client/ensure-conductor-spawned.js +48 -0
- package/dist/client/index.d.ts +32 -0
- package/dist/client/index.js +22 -0
- package/dist/client/interface.d.ts +461 -0
- package/dist/client/interface.js +2 -0
- package/dist/client/subscribe.d.ts +108 -0
- package/dist/client/subscribe.js +598 -0
- package/dist/client/with-spawn.d.ts +27 -0
- package/dist/client/with-spawn.js +87 -0
- package/dist/config.d.ts +323 -0
- package/dist/config.js +593 -0
- package/dist/connection.d.ts +7 -0
- package/dist/connection.js +46 -0
- package/dist/constants.d.ts +50 -0
- package/dist/constants.js +74 -0
- package/dist/copilot-bridge.d.ts +22 -0
- package/dist/copilot-bridge.js +565 -0
- package/dist/daemon-adapter-versions.d.ts +52 -0
- package/dist/daemon-adapter-versions.js +170 -0
- package/dist/daemon.d.ts +275 -0
- package/dist/daemon.js +989 -0
- package/dist/ensemble/agent-types.d.ts +23 -0
- package/dist/ensemble/agent-types.js +132 -0
- package/dist/ensemble/loader.d.ts +14 -0
- package/dist/ensemble/loader.js +140 -0
- package/dist/ensemble/saver.d.ts +49 -0
- package/dist/ensemble/saver.js +201 -0
- package/dist/ensemble/schema.d.ts +71 -0
- package/dist/ensemble/schema.js +3 -0
- package/dist/git-info.d.ts +4 -0
- package/dist/git-info.js +29 -0
- package/dist/http/aggregate.d.ts +319 -0
- package/dist/http/aggregate.js +684 -0
- package/dist/http/auth.d.ts +67 -0
- package/dist/http/auth.js +177 -0
- package/dist/http/body.d.ts +71 -0
- package/dist/http/body.js +121 -0
- package/dist/http/catalog.d.ts +67 -0
- package/dist/http/catalog.js +209 -0
- package/dist/http/cors.d.ts +42 -0
- package/dist/http/cors.js +111 -0
- package/dist/http/dashboard-pair.d.ts +94 -0
- package/dist/http/dashboard-pair.js +148 -0
- package/dist/http/dashboard.d.ts +20 -0
- package/dist/http/dashboard.js +160 -0
- package/dist/http/event-bus.d.ts +217 -0
- package/dist/http/event-bus.js +365 -0
- package/dist/http/event-id.d.ts +77 -0
- package/dist/http/event-id.js +117 -0
- package/dist/http/event-types.d.ts +348 -0
- package/dist/http/event-types.js +36 -0
- package/dist/http/fixtures/chat-stress.d.ts +8 -0
- package/dist/http/fixtures/chat-stress.js +63 -0
- package/dist/http/fixtures/conductor-leaving.d.ts +8 -0
- package/dist/http/fixtures/conductor-leaving.js +80 -0
- package/dist/http/fixtures/constants.d.ts +10 -0
- package/dist/http/fixtures/constants.js +13 -0
- package/dist/http/fixtures/eight-player-broadcast.d.ts +10 -0
- package/dist/http/fixtures/eight-player-broadcast.js +81 -0
- package/dist/http/fixtures/empty-ensemble.d.ts +6 -0
- package/dist/http/fixtures/empty-ensemble.js +26 -0
- package/dist/http/fixtures/index.d.ts +55 -0
- package/dist/http/fixtures/index.js +110 -0
- package/dist/http/fixtures/single-conductor.d.ts +7 -0
- package/dist/http/fixtures/single-conductor.js +46 -0
- package/dist/http/fixtures/sse-reconnect.d.ts +8 -0
- package/dist/http/fixtures/sse-reconnect.js +77 -0
- package/dist/http/index.d.ts +21 -0
- package/dist/http/index.js +61 -0
- package/dist/http/port-file.d.ts +22 -0
- package/dist/http/port-file.js +132 -0
- package/dist/http/responses.d.ts +27 -0
- package/dist/http/responses.js +40 -0
- package/dist/http/ring-buffer.d.ts +41 -0
- package/dist/http/ring-buffer.js +80 -0
- package/dist/http/server.d.ts +122 -0
- package/dist/http/server.js +459 -0
- package/dist/http/snapshot.d.ts +85 -0
- package/dist/http/snapshot.js +180 -0
- package/dist/http/sse-handler.d.ts +87 -0
- package/dist/http/sse-handler.js +294 -0
- package/dist/http/writes.d.ts +55 -0
- package/dist/http/writes.js +240 -0
- package/dist/palette/index.d.ts +138 -0
- package/dist/palette/index.js +221 -0
- package/dist/reconcile/orphans.d.ts +255 -0
- package/dist/reconcile/orphans.js +340 -0
- package/dist/scripts/258-spotcheck.js +303 -0
- package/dist/scripts/check-components-css-sync.js +199 -0
- package/dist/scripts/run-shard.js +121 -0
- package/dist/scripts/verify-daemon-isolation-guard.js +128 -0
- package/dist/server-tools.d.ts +87 -0
- package/dist/server-tools.js +146 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +366 -0
- package/dist/spawn.d.ts +296 -0
- package/dist/spawn.js +747 -0
- package/dist/tools/agent-types.d.ts +2 -0
- package/dist/tools/agent-types.js +21 -0
- package/dist/tools/attachment-info.d.ts +4 -0
- package/dist/tools/attachment-info.js +48 -0
- package/dist/tools/broadcast.d.ts +4 -0
- package/dist/tools/broadcast.js +76 -0
- package/dist/tools/cancel-stage.d.ts +3 -0
- package/dist/tools/cancel-stage.js +20 -0
- package/dist/tools/clear-state.d.ts +3 -0
- package/dist/tools/clear-state.js +37 -0
- package/dist/tools/coat-check-evict.d.ts +4 -0
- package/dist/tools/coat-check-evict.js +43 -0
- package/dist/tools/coat-check-get.d.ts +4 -0
- package/dist/tools/coat-check-get.js +56 -0
- package/dist/tools/coat-check-list.d.ts +4 -0
- package/dist/tools/coat-check-list.js +60 -0
- package/dist/tools/coat-check-put.d.ts +4 -0
- package/dist/tools/coat-check-put.js +53 -0
- package/dist/tools/cue.d.ts +44 -0
- package/dist/tools/cue.js +201 -0
- package/dist/tools/destroy.d.ts +4 -0
- package/dist/tools/destroy.js +188 -0
- package/dist/tools/detach.d.ts +4 -0
- package/dist/tools/detach.js +45 -0
- package/dist/tools/encore.d.ts +4 -0
- package/dist/tools/encore.js +31 -0
- package/dist/tools/ensemble.d.ts +32 -0
- package/dist/tools/ensemble.js +198 -0
- package/dist/tools/evaluate-gate.d.ts +3 -0
- package/dist/tools/evaluate-gate.js +32 -0
- package/dist/tools/fetch-state.d.ts +13 -0
- package/dist/tools/fetch-state.js +78 -0
- package/dist/tools/gates.d.ts +3 -0
- package/dist/tools/gates.js +41 -0
- package/dist/tools/helpers.d.ts +21 -0
- package/dist/tools/helpers.js +25 -0
- package/dist/tools/hosts.d.ts +4 -0
- package/dist/tools/hosts.js +40 -0
- package/dist/tools/listen.d.ts +3 -0
- package/dist/tools/listen.js +22 -0
- package/dist/tools/load-lineup.d.ts +5 -0
- package/dist/tools/load-lineup.js +381 -0
- package/dist/tools/migrate.d.ts +4 -0
- package/dist/tools/migrate.js +60 -0
- package/dist/tools/pause-ensemble.d.ts +4 -0
- package/dist/tools/pause-ensemble.js +58 -0
- package/dist/tools/pause.d.ts +4 -0
- package/dist/tools/pause.js +36 -0
- package/dist/tools/play.d.ts +4 -0
- package/dist/tools/play.js +57 -0
- package/dist/tools/quality-gate.d.ts +3 -0
- package/dist/tools/quality-gate.js +26 -0
- package/dist/tools/recall.d.ts +3 -0
- package/dist/tools/recall.js +32 -0
- package/dist/tools/recruit.d.ts +38 -0
- package/dist/tools/recruit.js +447 -0
- package/dist/tools/release.d.ts +4 -0
- package/dist/tools/release.js +98 -0
- package/dist/tools/report.d.ts +3 -0
- package/dist/tools/report.js +29 -0
- package/dist/tools/resolve.d.ts +1 -0
- package/dist/tools/resolve.js +7 -0
- package/dist/tools/restart.d.ts +35 -0
- package/dist/tools/restart.js +131 -0
- package/dist/tools/restore.d.ts +4 -0
- package/dist/tools/restore.js +107 -0
- package/dist/tools/resume-ensemble.d.ts +4 -0
- package/dist/tools/resume-ensemble.js +79 -0
- package/dist/tools/save-lineup.d.ts +4 -0
- package/dist/tools/save-lineup.js +36 -0
- package/dist/tools/save-state.d.ts +3 -0
- package/dist/tools/save-state.js +57 -0
- package/dist/tools/schedule.d.ts +4 -0
- package/dist/tools/schedule.js +152 -0
- package/dist/tools/schedules.d.ts +4 -0
- package/dist/tools/schedules.js +54 -0
- package/dist/tools/set-ensemble-description.d.ts +4 -0
- package/dist/tools/set-ensemble-description.js +37 -0
- package/dist/tools/set-name.d.ts +4 -0
- package/dist/tools/set-name.js +45 -0
- package/dist/tools/set-part.d.ts +3 -0
- package/dist/tools/set-part.js +20 -0
- package/dist/tools/shutdown.d.ts +4 -0
- package/dist/tools/shutdown.js +54 -0
- package/dist/tools/stage.d.ts +3 -0
- package/dist/tools/stage.js +28 -0
- package/dist/tools/stages.d.ts +3 -0
- package/dist/tools/stages.js +35 -0
- package/dist/tools/stop.d.ts +4 -0
- package/dist/tools/stop.js +29 -0
- package/dist/tools/unschedule.d.ts +4 -0
- package/dist/tools/unschedule.js +35 -0
- package/dist/tools/who-am-i.d.ts +3 -0
- package/dist/tools/who-am-i.js +34 -0
- package/dist/tools/worktree.d.ts +4 -0
- package/dist/tools/worktree.js +181 -0
- package/dist/tui/App.d.ts +85 -0
- package/dist/tui/App.js +1791 -0
- package/dist/tui/bootstrap-types.d.ts +46 -0
- package/dist/tui/bootstrap-types.js +7 -0
- package/dist/tui/client.d.ts +6 -0
- package/dist/tui/client.js +9 -0
- package/dist/tui/commands.d.ts +71 -0
- package/dist/tui/commands.js +1375 -0
- package/dist/tui/components/ActivityLog.d.ts +16 -0
- package/dist/tui/components/ActivityLog.js +36 -0
- package/dist/tui/components/ChatView.d.ts +35 -0
- package/dist/tui/components/ChatView.js +54 -0
- package/dist/tui/components/CommandOverlay.d.ts +15 -0
- package/dist/tui/components/CommandOverlay.js +34 -0
- package/dist/tui/components/CommandPalette.d.ts +21 -0
- package/dist/tui/components/CommandPalette.js +67 -0
- package/dist/tui/components/ConductorChat.d.ts +16 -0
- package/dist/tui/components/ConductorChat.js +32 -0
- package/dist/tui/components/ConversationStream.d.ts +114 -0
- package/dist/tui/components/ConversationStream.js +307 -0
- package/dist/tui/components/CreateEnsembleWizard.d.ts +19 -0
- package/dist/tui/components/CreateEnsembleWizard.js +223 -0
- package/dist/tui/components/DestroyConfirmModal.d.ts +17 -0
- package/dist/tui/components/DestroyConfirmModal.js +62 -0
- package/dist/tui/components/EnsembleListView.d.ts +14 -0
- package/dist/tui/components/EnsembleListView.js +32 -0
- package/dist/tui/components/EnsemblePanel.d.ts +12 -0
- package/dist/tui/components/EnsemblePanel.js +40 -0
- package/dist/tui/components/ErrorView.d.ts +31 -0
- package/dist/tui/components/ErrorView.js +129 -0
- package/dist/tui/components/HomeView.d.ts +54 -0
- package/dist/tui/components/HomeView.js +306 -0
- package/dist/tui/components/InputBar.d.ts +13 -0
- package/dist/tui/components/InputBar.js +58 -0
- package/dist/tui/components/LoadLineupModal.d.ts +18 -0
- package/dist/tui/components/LoadLineupModal.js +79 -0
- package/dist/tui/components/MainView.d.ts +21 -0
- package/dist/tui/components/MainView.js +107 -0
- package/dist/tui/components/NewEnsembleModal.d.ts +9 -0
- package/dist/tui/components/NewEnsembleModal.js +73 -0
- package/dist/tui/components/Picker.d.ts +23 -0
- package/dist/tui/components/Picker.js +70 -0
- package/dist/tui/components/PlayerDetailView.d.ts +26 -0
- package/dist/tui/components/PlayerDetailView.js +118 -0
- package/dist/tui/components/PromptArea.d.ts +50 -0
- package/dist/tui/components/PromptArea.js +303 -0
- package/dist/tui/components/RecruitWizard.d.ts +17 -0
- package/dist/tui/components/RecruitWizard.js +221 -0
- package/dist/tui/components/RestoreConfirmModal.d.ts +18 -0
- package/dist/tui/components/RestoreConfirmModal.js +71 -0
- package/dist/tui/components/ScheduleOverlay.d.ts +13 -0
- package/dist/tui/components/ScheduleOverlay.js +113 -0
- package/dist/tui/components/ScheduleWizard.d.ts +19 -0
- package/dist/tui/components/ScheduleWizard.js +259 -0
- package/dist/tui/components/Splash.d.ts +23 -0
- package/dist/tui/components/Splash.js +221 -0
- package/dist/tui/components/StatusBar.d.ts +48 -0
- package/dist/tui/components/StatusBar.js +128 -0
- package/dist/tui/components/StatusOverlay.d.ts +15 -0
- package/dist/tui/components/StatusOverlay.js +76 -0
- package/dist/tui/components/TitleBar.d.ts +10 -0
- package/dist/tui/components/TitleBar.js +21 -0
- package/dist/tui/components/TopBar.d.ts +12 -0
- package/dist/tui/components/TopBar.js +15 -0
- package/dist/tui/core-api.d.ts +26 -0
- package/dist/tui/core-api.js +67 -0
- package/dist/tui/hooks/useEnsembleDiscovery.d.ts +3 -0
- package/dist/tui/hooks/useEnsembleDiscovery.js +30 -0
- package/dist/tui/hooks/useMaestroPoller.d.ts +3 -0
- package/dist/tui/hooks/useMaestroPoller.js +36 -0
- package/dist/tui/hooks/useSendCommand.d.ts +7 -0
- package/dist/tui/hooks/useSendCommand.js +29 -0
- package/dist/tui/index.d.ts +15 -0
- package/dist/tui/index.js +156 -0
- package/dist/tui/ink-context.d.ts +18 -0
- package/dist/tui/ink-context.js +59 -0
- package/dist/tui/ink-loader.d.ts +26 -0
- package/dist/tui/ink-loader.js +42 -0
- package/dist/tui/removed-commands.d.ts +9 -0
- package/dist/tui/removed-commands.js +22 -0
- package/dist/tui/sse-handler.d.ts +52 -0
- package/dist/tui/sse-handler.js +157 -0
- package/dist/tui/store.d.ts +598 -0
- package/dist/tui/store.js +753 -0
- package/dist/tui/utils/format.d.ts +56 -0
- package/dist/tui/utils/format.js +155 -0
- package/dist/tui/utils/fullscreen.d.ts +23 -0
- package/dist/tui/utils/fullscreen.js +71 -0
- package/dist/tui/utils/history.d.ts +10 -0
- package/dist/tui/utils/history.js +85 -0
- package/dist/tui/utils/platform.d.ts +45 -0
- package/dist/tui/utils/platform.js +258 -0
- package/dist/tui/utils/theme.d.ts +21 -0
- package/dist/tui/utils/theme.js +24 -0
- package/dist/types.d.ts +1020 -0
- package/dist/types.js +39 -0
- package/dist/utils/attachment-format.d.ts +22 -0
- package/dist/utils/attachment-format.js +32 -0
- package/dist/utils/default-part.d.ts +43 -0
- package/dist/utils/default-part.js +104 -0
- package/dist/utils/duration.d.ts +30 -0
- package/dist/utils/duration.js +69 -0
- package/dist/utils/ensemble-ops.d.ts +61 -0
- package/dist/utils/ensemble-ops.js +77 -0
- package/dist/utils/format-hosts.d.ts +21 -0
- package/dist/utils/format-hosts.js +73 -0
- package/dist/utils/hosts.d.ts +113 -0
- package/dist/utils/hosts.js +265 -0
- package/dist/utils/parent-death-watchdog.d.ts +1 -0
- package/dist/utils/parent-death-watchdog.js +47 -0
- package/dist/utils/query-timeout.d.ts +103 -0
- package/dist/utils/query-timeout.js +113 -0
- package/dist/utils/recall-format.d.ts +78 -0
- package/dist/utils/recall-format.js +105 -0
- package/dist/utils/restore-format.d.ts +49 -0
- package/dist/utils/restore-format.js +91 -0
- package/dist/utils/safe-path.d.ts +10 -0
- package/dist/utils/safe-path.js +43 -0
- package/dist/utils/sdk-probe.d.ts +9 -0
- package/dist/utils/sdk-probe.js +45 -0
- package/dist/utils/search-attributes.d.ts +76 -0
- package/dist/utils/search-attributes.js +86 -0
- package/dist/utils/validation.d.ts +113 -0
- package/dist/utils/validation.js +163 -0
- package/dist/utils/visibility-deadline.d.ts +186 -0
- package/dist/utils/visibility-deadline.js +158 -0
- package/dist/utils/worktree.d.ts +103 -0
- package/dist/utils/worktree.js +327 -0
- package/dist/worker.d.ts +14 -0
- package/dist/worker.js +146 -0
- package/dist/workflows/attachment-math.d.ts +56 -0
- package/dist/workflows/attachment-math.js +47 -0
- package/dist/workflows/index.d.ts +3 -0
- package/dist/workflows/index.js +11 -0
- package/dist/workflows/maestro-signals.d.ts +217 -0
- package/dist/workflows/maestro-signals.js +155 -0
- package/dist/workflows/maestro.d.ts +3 -0
- package/dist/workflows/maestro.js +812 -0
- package/dist/workflows/scheduler-signals.d.ts +10 -0
- package/dist/workflows/scheduler-signals.js +14 -0
- package/dist/workflows/scheduler.d.ts +17 -0
- package/dist/workflows/scheduler.js +143 -0
- package/dist/workflows/session.d.ts +2 -0
- package/dist/workflows/session.js +1638 -0
- package/dist/workflows/signals.d.ts +297 -0
- package/dist/workflows/signals.js +239 -0
- package/examples/agents/tempo-composer.md +56 -0
- package/examples/agents/tempo-conductor.md +117 -0
- package/examples/agents/tempo-critic.md +73 -0
- package/examples/agents/tempo-improv.md +74 -0
- package/examples/agents/tempo-liner.md +75 -0
- package/examples/agents/tempo-roadie.md +61 -0
- package/examples/agents/tempo-soloist.md +71 -0
- package/examples/agents/tempo-tuner.md +94 -0
- package/examples/ensembles/tempo-big-band.yaml +146 -0
- package/examples/ensembles/tempo-dev-team.yaml +58 -0
- package/examples/ensembles/tempo-headless-jam.yaml +77 -0
- package/examples/ensembles/tempo-jam-session.yaml +41 -0
- package/examples/ensembles/tempo-mock-jam.yaml +79 -0
- package/examples/ensembles/tempo-review-squad.yaml +32 -0
- package/package.json +172 -0
- package/packaging/launchd/com.agent.tempo.plist +46 -0
- package/packaging/systemd/agent-tempo.service +32 -0
- package/packaging/windows/install-task.ps1 +71 -0
- package/scenarios/conductor-recruit-mock.yaml +33 -0
- package/scenarios/echo-roundtrip.yaml +15 -0
- package/scenarios/multi-player-handoff.yaml +38 -0
- package/scenarios/recruit-cascade.yaml +38 -0
- package/scenarios/two-player-conversation.yaml +33 -0
- package/workflow-bundle.js +14146 -0
|
@@ -0,0 +1,710 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.ClaudeCodeHeadlessAttachment = exports.CLAUDE_CODE_PERMISSION_MODES = exports.claudeCodeHeadlessDescriptor = void 0;
|
|
37
|
+
exports.encodeCwd = encodeCwd;
|
|
38
|
+
/**
|
|
39
|
+
* Headless Claude Code adapter — SDK class.
|
|
40
|
+
*
|
|
41
|
+
* Issue #520. Drives the host's installed `claude` CLI (the official Claude
|
|
42
|
+
* Code binary) as a per-turn `claude -p` subprocess. The whole point: tap
|
|
43
|
+
* subscription extra-usage credits via the host's existing OAuth login —
|
|
44
|
+
* the only ToS-clean way for a third-party tool to reach that pool per
|
|
45
|
+
* Anthropic's authentication policy.
|
|
46
|
+
*
|
|
47
|
+
* Mirrors the claude-api / opencode SDK-class adapters: detached Node
|
|
48
|
+
* subprocess, dual-purpose entry point (`require.main === module`),
|
|
49
|
+
* `claimAttachment` + heartbeat lifecycle inherited from `SdkAttachment`.
|
|
50
|
+
*
|
|
51
|
+
* Class hierarchy: `ClaudeCodeHeadlessAttachment extends SdkAttachment extends BaseAttachment`.
|
|
52
|
+
*
|
|
53
|
+
* **Commit progression for #520**:
|
|
54
|
+
* - PR-1: scaffold — directory layout, descriptor, class skeleton, recruit
|
|
55
|
+
* pre-flight, AgentType extension, registry registration.
|
|
56
|
+
* - **PR-2 (this commit)**: lifecycle + subprocess spawn — `run()` connects
|
|
57
|
+
* Temporal, claims attachment, hydrates session UUID via the shared
|
|
58
|
+
* `sessionId` metadata field (architect-ratified post-spike — see PR-3
|
|
59
|
+
* §16 spike-findings appendix), drives the poll loop. `onSuperseded()`
|
|
60
|
+
* scaffold for the in-flight `claude` subprocess SIGTERM (target hooks
|
|
61
|
+
* in PR-3). `invokeSdk()` still a stub — calling it throws so the
|
|
62
|
+
* adapter exits loudly on the first message rather than silently
|
|
63
|
+
* dropping it.
|
|
64
|
+
* - PR-3: tool-use loop — stream-json frame parser, --mcp-config inline
|
|
65
|
+
* JSON synthesis, error-mapper translating subprocess fail modes into
|
|
66
|
+
* the shared `ApiErrorCategory` classifier (per architect's
|
|
67
|
+
* ratification of Delta #3).
|
|
68
|
+
* - PR-4: tests + docs + example lineup.
|
|
69
|
+
*
|
|
70
|
+
* Design reference: `docs/design/520-claude-code-headless-adapter.md` —
|
|
71
|
+
* §0 (TL;DR), §2 (adapter precedents), §3 (spawn integration), §5
|
|
72
|
+
* (streaming + state), §6 (wire-protocol), §7 (engineer-facing skeleton).
|
|
73
|
+
*/
|
|
74
|
+
const fs = __importStar(require("fs"));
|
|
75
|
+
const os = __importStar(require("os"));
|
|
76
|
+
const path = __importStar(require("path"));
|
|
77
|
+
const crypto = __importStar(require("crypto"));
|
|
78
|
+
const child_process_1 = require("child_process");
|
|
79
|
+
const client_1 = require("@temporalio/client");
|
|
80
|
+
const base_1 = require("../sdk/base");
|
|
81
|
+
const config_1 = require("../../config");
|
|
82
|
+
const connection_1 = require("../../connection");
|
|
83
|
+
const signals_1 = require("../../workflows/signals");
|
|
84
|
+
const stream_json_1 = require("./stream-json");
|
|
85
|
+
const error_mapper_1 = require("./error-mapper");
|
|
86
|
+
// #536 — pure prompt-build helpers (system-prompt injection +
|
|
87
|
+
// MAESTRO_ACK augmentation). Extracted so the per-turn driver below
|
|
88
|
+
// stays focused on subprocess I/O.
|
|
89
|
+
const prompt_1 = require("./prompt");
|
|
90
|
+
/**
|
|
91
|
+
* Descriptor for the claude-code-headless adapter. Colocated with the
|
|
92
|
+
* class so `adapter.ts` has no import dependency on `index.ts` (avoids
|
|
93
|
+
* the circular module-graph cycle QA flagged on copilot's PR-B).
|
|
94
|
+
*
|
|
95
|
+
* Design reference: `docs/design/520-claude-code-headless-adapter.md` §2.
|
|
96
|
+
*/
|
|
97
|
+
exports.claudeCodeHeadlessDescriptor = {
|
|
98
|
+
adapterId: 'claude-code-headless',
|
|
99
|
+
adapterClass: 'sdk',
|
|
100
|
+
// `claude -p` blocks until the result frame — processingStart/End pairing
|
|
101
|
+
// is mandatory and provided by SdkAttachment.deliver().
|
|
102
|
+
blocksOnLLMTurn: true,
|
|
103
|
+
// SDK class — 30s cadence per design § / lifecycle-rebuild-v2 §4.3.
|
|
104
|
+
// Inherited from BaseAttachment's heartbeat loop via the descriptor.
|
|
105
|
+
heartbeatMs: 30_000,
|
|
106
|
+
};
|
|
107
|
+
// Re-export the canonical permission-mode type from `./types` so existing
|
|
108
|
+
// consumers that import it from `./adapter` (or from the barrel) keep
|
|
109
|
+
// working unchanged. Single source of truth lives in `./types.ts` —
|
|
110
|
+
// addresses QA Nit 3 from PR-1's review.
|
|
111
|
+
var types_1 = require("./types");
|
|
112
|
+
Object.defineProperty(exports, "CLAUDE_CODE_PERMISSION_MODES", { enumerable: true, get: function () { return types_1.CLAUDE_CODE_PERMISSION_MODES; } });
|
|
113
|
+
/**
|
|
114
|
+
* Unbuffered stderr logger. `fs.writeSync(2, ...)` bypasses Node.js stream
|
|
115
|
+
* buffering so log lines appear immediately even when stderr is redirected
|
|
116
|
+
* to a file. Same pattern claude-api / opencode use.
|
|
117
|
+
*/
|
|
118
|
+
const log = (...args) => {
|
|
119
|
+
const msg = `[agent-tempo:claude-code-headless] ${args.map((a) => {
|
|
120
|
+
if (typeof a === 'string')
|
|
121
|
+
return a;
|
|
122
|
+
if (a instanceof Error)
|
|
123
|
+
return a.stack ? `${a.message}\n${a.stack}` : a.message;
|
|
124
|
+
try {
|
|
125
|
+
return JSON.stringify(a);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return String(a);
|
|
129
|
+
}
|
|
130
|
+
}).join(' ')}\n`;
|
|
131
|
+
fs.writeSync(2, msg);
|
|
132
|
+
};
|
|
133
|
+
/** Idle poll cadence — short enough for snappy cue delivery, loose on Temporal. */
|
|
134
|
+
const POLL_INTERVAL_MS = 2000;
|
|
135
|
+
/** Workflow-register poll bounds — same as claude-api/opencode. */
|
|
136
|
+
const WORKFLOW_REGISTER_ATTEMPTS = 30;
|
|
137
|
+
const WORKFLOW_REGISTER_INTERVAL_MS = 1000;
|
|
138
|
+
/** Workflow status check cadence (every N polls). */
|
|
139
|
+
const WORKFLOW_STATUS_CHECK_INTERVAL = 15;
|
|
140
|
+
/** Per-turn timeout — `claude -p` tool-use chains can run minutes. */
|
|
141
|
+
const TURN_TIMEOUT_MS = 5 * 60 * 1000;
|
|
142
|
+
/** SIGTERM grace before SIGKILL escalation on the in-flight `claude` subprocess. */
|
|
143
|
+
const SIGTERM_GRACE_MS = 5_000;
|
|
144
|
+
/**
|
|
145
|
+
* SDK-class adapter that drives `claude -p` as a per-turn subprocess.
|
|
146
|
+
*
|
|
147
|
+
* **PR-2 status**: lifecycle + spawn scaffold complete. `run()` boots the
|
|
148
|
+
* full V2 lifecycle, hydrates the per-cwd session UUID via the shared
|
|
149
|
+
* `sessionId` metadata field, and drives the poll loop. `onSuperseded()`
|
|
150
|
+
* SIGTERMs `this.childProcess` (which PR-3 populates inside `invokeSdk`).
|
|
151
|
+
* `invokeSdk()` still throws — calling it errors the turn loudly until
|
|
152
|
+
* PR-3 wires the per-turn `claude -p` invocation.
|
|
153
|
+
*
|
|
154
|
+
* Lifecycle inherited from `SdkAttachment` / `BaseAttachment`: claim,
|
|
155
|
+
* heartbeat, phase watcher, `processingStart`/`End` pairing,
|
|
156
|
+
* `markDelivered`. No reconnect opt-in (matches claude-api / opencode —
|
|
157
|
+
* the daemon's `reconcile-on-boot` recovers from lease loss).
|
|
158
|
+
*/
|
|
159
|
+
class ClaudeCodeHeadlessAttachment extends base_1.SdkAttachment {
|
|
160
|
+
descriptor = exports.claudeCodeHeadlessDescriptor;
|
|
161
|
+
/** `--permission-mode` flag value. Resolved at construction; ENV fallback. */
|
|
162
|
+
permissionMode;
|
|
163
|
+
/** Whether to use `--dangerously-skip-permissions` instead of permissionMode. */
|
|
164
|
+
dangerouslySkipPermissions;
|
|
165
|
+
/**
|
|
166
|
+
* In-flight per-turn `claude -p` subprocess. Set by PR-3's `invokeSdk`
|
|
167
|
+
* before each turn; cleared after exit. `onSuperseded` reads this to
|
|
168
|
+
* SIGTERM the child on lease revocation.
|
|
169
|
+
*/
|
|
170
|
+
childProcess = null;
|
|
171
|
+
/**
|
|
172
|
+
* Per-cwd Claude Code session UUID. Used as `--session-id` on the first
|
|
173
|
+
* turn (to PIN the UUID) and `--resume` alone on subsequent turns
|
|
174
|
+
* (mutually exclusive per CLI v2.1.126 — see §16.9). Hydrated from
|
|
175
|
+
* `SessionMetadata.sessionId` on `run()` — generated fresh + stashed if
|
|
176
|
+
* absent. The same field is shared with the interactive Claude Code
|
|
177
|
+
* adapter (architect-ratified Option (a) post-spike — see PR-3 §16).
|
|
178
|
+
*/
|
|
179
|
+
sessionId = null;
|
|
180
|
+
/** Cached for the per-turn telemetry log. Populated in `run()`. */
|
|
181
|
+
playerName = '';
|
|
182
|
+
constructor(opts = {}) {
|
|
183
|
+
super();
|
|
184
|
+
this.permissionMode = opts.permissionMode
|
|
185
|
+
?? process.env[config_1.ENV.PERMISSION_MODE]
|
|
186
|
+
?? 'acceptEdits';
|
|
187
|
+
this.dangerouslySkipPermissions = opts.dangerouslySkipPermissions === true;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Lease-revocation hook — fired by `SdkAttachment` when the base-class
|
|
191
|
+
* phase watcher detects another claimant stole the attachment.
|
|
192
|
+
*
|
|
193
|
+
* Two-step graceful → forced fallback per design §5.7: SIGTERM first
|
|
194
|
+
* (lets `claude` flush any in-flight stream-json frames + tear down its
|
|
195
|
+
* MCP child cleanly); SIGKILL after {@link SIGTERM_GRACE_MS} grace if it
|
|
196
|
+
* doesn't exit. Identical pattern to opencode/adapter.ts:160-173.
|
|
197
|
+
*
|
|
198
|
+
* Idempotent — racing signals (lease revoke + cleanup) are safe.
|
|
199
|
+
*/
|
|
200
|
+
onSuperseded() {
|
|
201
|
+
const child = this.childProcess;
|
|
202
|
+
this.childProcess = null;
|
|
203
|
+
if (!child) {
|
|
204
|
+
// No in-flight subprocess to kill — common case when superseded
|
|
205
|
+
// fires while the adapter is idle in the poll loop.
|
|
206
|
+
log('lease revoked — no in-flight claude subprocess');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
log('lease revoked — SIGTERM in-flight claude subprocess');
|
|
210
|
+
try {
|
|
211
|
+
child.kill('SIGTERM');
|
|
212
|
+
}
|
|
213
|
+
catch (err) {
|
|
214
|
+
log('SIGTERM threw:', err?.message ?? err);
|
|
215
|
+
}
|
|
216
|
+
setTimeout(() => {
|
|
217
|
+
if (child.exitCode === null && !child.killed) {
|
|
218
|
+
log(`SIGTERM grace (${SIGTERM_GRACE_MS}ms) expired — escalating to SIGKILL`);
|
|
219
|
+
try {
|
|
220
|
+
child.kill('SIGKILL');
|
|
221
|
+
}
|
|
222
|
+
catch {
|
|
223
|
+
// Already gone — fine.
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}, SIGTERM_GRACE_MS).unref();
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Subprocess entry point. Connects Temporal, waits for the session
|
|
230
|
+
* workflow to register, hydrates the per-cwd session UUID via metadata,
|
|
231
|
+
* claims the attachment via V2 lifecycle, and drives the poll loop.
|
|
232
|
+
*
|
|
233
|
+
* Design reference: §3.6 (env hygiene), §5.1 (session continuity), §7
|
|
234
|
+
* (engineer-facing skeleton).
|
|
235
|
+
*/
|
|
236
|
+
async run() {
|
|
237
|
+
const config = (0, config_1.getConfig)();
|
|
238
|
+
const isConductor = process.env[config_1.ENV.CONDUCTOR] === 'true';
|
|
239
|
+
const requestedName = process.env[config_1.ENV.PLAYER_NAME] || '';
|
|
240
|
+
const playerIdForWorkflow = isConductor
|
|
241
|
+
? 'conductor'
|
|
242
|
+
: (requestedName && requestedName !== 'conductor' ? requestedName : '') || `claude-code-headless-${Date.now()}`;
|
|
243
|
+
const expectedWorkflowId = `agent-session-${config.ensemble}-${playerIdForWorkflow}`;
|
|
244
|
+
const workDir = process.cwd();
|
|
245
|
+
this.playerName = playerIdForWorkflow;
|
|
246
|
+
// §3.6 env-hygiene early warning. ANTHROPIC_API_KEY in the parent env
|
|
247
|
+
// would defeat the whole point of this adapter (subscription billing).
|
|
248
|
+
// The actual env-strip happens in PR-3's invokeSdk before each `claude
|
|
249
|
+
// -p` spawn; this is just a heads-up so operators don't burn an hour
|
|
250
|
+
// wondering why their Console workspace is being charged. The strip is
|
|
251
|
+
// load-bearing — log it loudly.
|
|
252
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
253
|
+
log('WARNING: ANTHROPIC_API_KEY is set in the adapter env. ' +
|
|
254
|
+
'The per-turn `claude` child will have it stripped (PR-3) so OAuth ' +
|
|
255
|
+
'subscription billing wins. If you intended Console billing, recruit ' +
|
|
256
|
+
'with `agent: "claude-api"` instead.');
|
|
257
|
+
}
|
|
258
|
+
if (process.env.CLAUDE_CODE_OAUTH_TOKEN) {
|
|
259
|
+
log('WARNING: CLAUDE_CODE_OAUTH_TOKEN is set in the adapter env. ' +
|
|
260
|
+
'The per-turn `claude` child will have it stripped (PR-3) — the ' +
|
|
261
|
+
'host\'s keychain OAuth wins. Set `setup-token` only if you want ' +
|
|
262
|
+
'long-lived non-keychain auth and recruit accordingly.');
|
|
263
|
+
}
|
|
264
|
+
log(`Starting claude-code-headless adapter in ${workDir} (ensemble: ${config.ensemble}, player: ${playerIdForWorkflow}, permissionMode: ${this.dangerouslySkipPermissions ? 'dangerously-skip-permissions' : this.permissionMode})`);
|
|
265
|
+
const connection = await (0, connection_1.createTemporalConnection)(config);
|
|
266
|
+
const client = new client_1.Client({
|
|
267
|
+
connection,
|
|
268
|
+
namespace: config.temporalNamespace,
|
|
269
|
+
});
|
|
270
|
+
this.configureV2(client, os.hostname());
|
|
271
|
+
// Wait for the session workflow to register in Temporal (the spawn
|
|
272
|
+
// activity is responsible for starting it; we know the ID deterministically).
|
|
273
|
+
log(`Waiting for workflow ${expectedWorkflowId} to register...`);
|
|
274
|
+
let handle = client.workflow.getHandle(expectedWorkflowId);
|
|
275
|
+
let pinnedRunId;
|
|
276
|
+
let workflowReady = false;
|
|
277
|
+
for (let attempt = 0; attempt < WORKFLOW_REGISTER_ATTEMPTS; attempt++) {
|
|
278
|
+
try {
|
|
279
|
+
const desc = await handle.describe();
|
|
280
|
+
if (desc.status.name === 'RUNNING') {
|
|
281
|
+
workflowReady = true;
|
|
282
|
+
pinnedRunId = desc.runId;
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
catch { /* not yet started */ }
|
|
287
|
+
await new Promise((r) => setTimeout(r, WORKFLOW_REGISTER_INTERVAL_MS));
|
|
288
|
+
if (attempt % 5 === 4)
|
|
289
|
+
log(`Still waiting for workflow... attempt ${attempt + 1}/${WORKFLOW_REGISTER_ATTEMPTS}`);
|
|
290
|
+
}
|
|
291
|
+
if (!workflowReady) {
|
|
292
|
+
log(`ERROR: Workflow ${expectedWorkflowId} did not register within ${WORKFLOW_REGISTER_ATTEMPTS}s — exiting`);
|
|
293
|
+
process.exit(1);
|
|
294
|
+
}
|
|
295
|
+
handle = client.workflow.getHandle(expectedWorkflowId, pinnedRunId);
|
|
296
|
+
log(`Workflow ready: ${expectedWorkflowId} (pinned runId ${pinnedRunId})`);
|
|
297
|
+
// Hydrate the per-cwd Claude Code session UUID. Architect-ratified
|
|
298
|
+
// Option (a) post-spike: reuse the existing `sessionId` metadata field
|
|
299
|
+
// (already typed for shared use across Copilot + Claude Code per
|
|
300
|
+
// types.ts JSDoc). Same UUID survives encore / restart / migrate-within-cwd
|
|
301
|
+
// for free since Claude Code's session JSONL is per-cwd, not per-adapter.
|
|
302
|
+
try {
|
|
303
|
+
const meta = await handle.query(signals_1.getMetadataQuery);
|
|
304
|
+
if (meta.sessionId) {
|
|
305
|
+
this.sessionId = meta.sessionId;
|
|
306
|
+
log(`Resuming Claude Code session ${this.sessionId} from workflow metadata`);
|
|
307
|
+
}
|
|
308
|
+
else {
|
|
309
|
+
this.sessionId = crypto.randomUUID();
|
|
310
|
+
await handle.signal(signals_1.updateMetadataSignal, { sessionId: this.sessionId });
|
|
311
|
+
log(`Created new Claude Code session ${this.sessionId}; stashed on workflow metadata`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch (err) {
|
|
315
|
+
log(`ERROR: session-UUID hydration failed: ${err?.message ?? err} — exiting`);
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
// Wire terminal-cleanup hook BEFORE claiming so a race between claim +
|
|
319
|
+
// lease loss can't drop the event.
|
|
320
|
+
let shuttingDown = false;
|
|
321
|
+
const cleanup = async () => {
|
|
322
|
+
if (shuttingDown)
|
|
323
|
+
return;
|
|
324
|
+
shuttingDown = true;
|
|
325
|
+
log('Cleanup running...');
|
|
326
|
+
// SIGTERM any in-flight subprocess via onSuperseded's machinery.
|
|
327
|
+
this.onSuperseded();
|
|
328
|
+
// Graceful detach — fires `adapterExited` so the workflow collapses
|
|
329
|
+
// draining → detached immediately. Same pattern claude-api uses.
|
|
330
|
+
try {
|
|
331
|
+
await this.detachGracefully('user-stop');
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
log('detachGracefully error:', err?.message ?? err);
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
this.onTerminal((reason) => {
|
|
338
|
+
log(`V2 terminal (${reason}) — triggering cleanup`);
|
|
339
|
+
cleanup().catch((err) => log('terminal cleanup error:', err?.message ?? err));
|
|
340
|
+
});
|
|
341
|
+
// V2 path: claim the attachment + start the base-class heartbeat &
|
|
342
|
+
// phase watcher loops. `startV2Lifecycle` returns its own pinned
|
|
343
|
+
// handle; we use that going forward so the heartbeat and delivery
|
|
344
|
+
// share a consistent handle.
|
|
345
|
+
try {
|
|
346
|
+
const expectedAttachmentId = process.env[config_1.ENV.ATTACHMENT_ID] || undefined;
|
|
347
|
+
handle = await this.startV2Lifecycle(expectedWorkflowId, expectedAttachmentId);
|
|
348
|
+
log(`V2 attachment claimed (attachmentId=${this.token?.attachmentId}${expectedAttachmentId ? ', renewed' : ''})`);
|
|
349
|
+
}
|
|
350
|
+
catch (err) {
|
|
351
|
+
log(`ERROR: V2 claimAttachment failed: ${err?.message ?? err}`);
|
|
352
|
+
await cleanup();
|
|
353
|
+
process.exit(1);
|
|
354
|
+
}
|
|
355
|
+
// PID file so callers can find / kill orphaned adapter processes.
|
|
356
|
+
const pidDir = path.join(workDir, 'logs');
|
|
357
|
+
const pidFile = path.join(pidDir, `${playerIdForWorkflow}.pid`);
|
|
358
|
+
try {
|
|
359
|
+
fs.mkdirSync(pidDir, { recursive: true });
|
|
360
|
+
fs.writeFileSync(pidFile, String(process.pid));
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
log(`Warning: PID file write failed: ${err?.message ?? err}`);
|
|
364
|
+
}
|
|
365
|
+
// Graceful shutdown handlers. The cleanup fn is idempotent so racing
|
|
366
|
+
// signals are safe.
|
|
367
|
+
const shutdown = async () => {
|
|
368
|
+
log('Shutting down (signal received)...');
|
|
369
|
+
await cleanup();
|
|
370
|
+
try {
|
|
371
|
+
fs.unlinkSync(pidFile);
|
|
372
|
+
}
|
|
373
|
+
catch { /* already gone */ }
|
|
374
|
+
process.exit(0);
|
|
375
|
+
};
|
|
376
|
+
process.on('SIGINT', shutdown);
|
|
377
|
+
process.on('SIGTERM', shutdown);
|
|
378
|
+
// Drive the poll loop until cleanup is requested.
|
|
379
|
+
await this.pollLoop(handle);
|
|
380
|
+
try {
|
|
381
|
+
fs.unlinkSync(pidFile);
|
|
382
|
+
}
|
|
383
|
+
catch { /* already gone */ }
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Poll the workflow for pending messages, drive each one through
|
|
387
|
+
* `SdkAttachment.deliver()`. Mirrors claude-api's loop shape; the LLM
|
|
388
|
+
* call lives in `invokeSdk` (PR-3).
|
|
389
|
+
*
|
|
390
|
+
* Periodic workflow-status checks detect external termination /
|
|
391
|
+
* destroy and exit cleanly so the daemon doesn't accumulate zombie
|
|
392
|
+
* adapter processes after a `destroy` from another player.
|
|
393
|
+
*/
|
|
394
|
+
async pollLoop(handle) {
|
|
395
|
+
let polling = true;
|
|
396
|
+
let processing = false;
|
|
397
|
+
let pollCount = 0;
|
|
398
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
399
|
+
while (polling && !this.shouldStop()) {
|
|
400
|
+
pollCount++;
|
|
401
|
+
// Periodic workflow-status check — detect external destroy / completion.
|
|
402
|
+
if (pollCount % WORKFLOW_STATUS_CHECK_INTERVAL === 0) {
|
|
403
|
+
try {
|
|
404
|
+
const desc = await handle.describe();
|
|
405
|
+
if (desc.status.name !== 'RUNNING') {
|
|
406
|
+
log(`Workflow status is ${desc.status.name} — exiting cleanly`);
|
|
407
|
+
polling = false;
|
|
408
|
+
break;
|
|
409
|
+
}
|
|
410
|
+
try {
|
|
411
|
+
const isDestroyed = await handle.query(signals_1.isDestroyedQuery);
|
|
412
|
+
if (isDestroyed) {
|
|
413
|
+
log('Workflow destroyed — exiting cleanly');
|
|
414
|
+
polling = false;
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
catch { /* isDestroyed query unavailable on pre-upgrade workflows — safe to skip */ }
|
|
419
|
+
}
|
|
420
|
+
catch (err) {
|
|
421
|
+
log(`Workflow describe failed: ${err?.message ?? err} — treating as terminated`);
|
|
422
|
+
polling = false;
|
|
423
|
+
break;
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (processing) {
|
|
427
|
+
await sleep(POLL_INTERVAL_MS);
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
let messages = [];
|
|
431
|
+
try {
|
|
432
|
+
messages = await handle.query(signals_1.pendingMessagesQuery);
|
|
433
|
+
}
|
|
434
|
+
catch (err) {
|
|
435
|
+
log(`pendingMessages query failed: ${err?.message ?? err}`);
|
|
436
|
+
await sleep(POLL_INTERVAL_MS);
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
if (messages.length === 0) {
|
|
440
|
+
await sleep(POLL_INTERVAL_MS);
|
|
441
|
+
continue;
|
|
442
|
+
}
|
|
443
|
+
processing = true;
|
|
444
|
+
try {
|
|
445
|
+
const ackIds = messages.map((m) => m.id);
|
|
446
|
+
// The whole batch is delivered as one `claude -p` invocation — the
|
|
447
|
+
// representative `messages[0]` only drives processingStart/End.
|
|
448
|
+
// QA flag from PR-2 review: closure-wrap so `invokeSdkWithBatch`
|
|
449
|
+
// sees `messages` via the captured argument (NOT via instance
|
|
450
|
+
// state — the prior comment claimed "via closure" but the method
|
|
451
|
+
// can't actually read closure-only vars). Mirrors opencode's
|
|
452
|
+
// pattern at `src/adapters/opencode/adapter.ts:443`.
|
|
453
|
+
await this.deliver(handle, messages[0],
|
|
454
|
+
/* prompt unused — invokeSdkWithBatch reads `messages` from the closure-captured arg */ '', TURN_TIMEOUT_MS, (timeoutPrompt, timeoutMs) => this.invokeSdkWithBatch(messages, timeoutPrompt, timeoutMs), ackIds);
|
|
455
|
+
}
|
|
456
|
+
catch (err) {
|
|
457
|
+
log(`deliver error: ${err?.message ?? err}`);
|
|
458
|
+
// Don't exit the loop — transient failures leave messages PENDING
|
|
459
|
+
// for the next poll. Only terminal events (lease loss, destroy)
|
|
460
|
+
// exit via onTerminal / status-check above.
|
|
461
|
+
}
|
|
462
|
+
finally {
|
|
463
|
+
processing = false;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
log('Poll loop exiting');
|
|
467
|
+
}
|
|
468
|
+
/** True once `onTerminal` fired and cleanup tore down the V2 token. */
|
|
469
|
+
shouldStop() {
|
|
470
|
+
return this.token === null;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Per-turn LLM dispatch. Spawns `claude -p` with the synthesized argv
|
|
474
|
+
* + inline `--mcp-config`, streams stdout through `StreamJsonReader`,
|
|
475
|
+
* and returns the closing `result` frame's assembled text + usage.
|
|
476
|
+
*
|
|
477
|
+
* Closure-captured `messages[]` carries the multi-cue batch (PR-2 QA
|
|
478
|
+
* flag — see `pollLoop` for the closure-wrapping rationale). The
|
|
479
|
+
* representative `_prompt` arg from `SdkAttachment.deliver()` is
|
|
480
|
+
* unused; we build the prompt argv from `messages` directly.
|
|
481
|
+
*
|
|
482
|
+
* `_timeoutMs` is passed through to a Promise.race that SIGTERMs the
|
|
483
|
+
* subprocess on timeout. The base `SdkAttachment.deliver()` doesn't
|
|
484
|
+
* enforce its own timeout — we do it here.
|
|
485
|
+
*
|
|
486
|
+
* Subprocess failures (exit != 0, no result frame, or
|
|
487
|
+
* `result.is_error`) flow through the architect-ratified classifier
|
|
488
|
+
* in `./error-mapper.ts`. The classifier output is logged but the
|
|
489
|
+
* adapter does NOT call `markDelivered` on failure — the message
|
|
490
|
+
* stays PENDING so the next poll picks it up. The adapter's own
|
|
491
|
+
* retry-budget logic (PR-3 follow-up; mirrors #521's claude-api fix)
|
|
492
|
+
* tracks consecutive failures and escalates to detach when N=10
|
|
493
|
+
* `retriable-with-backoff` failures pile up.
|
|
494
|
+
*/
|
|
495
|
+
async invokeSdkWithBatch(messages, _prompt, timeoutMs) {
|
|
496
|
+
if (!this.sessionId) {
|
|
497
|
+
throw new Error('invokeSdkWithBatch called before run() initialized sessionId');
|
|
498
|
+
}
|
|
499
|
+
const sessionId = this.sessionId;
|
|
500
|
+
const t0 = Date.now();
|
|
501
|
+
// Build the prompt — concatenate every queued cue with attribution.
|
|
502
|
+
// Mirrors opencode's `[from ${m.from}]: ${m.text}` shape so operators
|
|
503
|
+
// who switch between adapters see consistent transcript framing.
|
|
504
|
+
// #536 — `buildPromptText` additionally appends MAESTRO_ACK to any
|
|
505
|
+
// message with `isMaestro: true`, mirroring copilot's poll-loop
|
|
506
|
+
// pattern (see `src/adapters/copilot/adapter.ts:639-645`).
|
|
507
|
+
const promptText = (0, prompt_1.buildPromptText)(messages);
|
|
508
|
+
// Synthesize the inline --mcp-config JSON. Per design §4 the adapter
|
|
509
|
+
// does NOT translate tool schemas itself; instead `claude` spawns
|
|
510
|
+
// `node dist/server.js` as a stdio MCP child of THE child (a separate
|
|
511
|
+
// process from the adapter). The MCP server picks up the env vars
|
|
512
|
+
// and registers all tempo tools natively.
|
|
513
|
+
const mcpServerPath = path.resolve(__dirname, '..', '..', 'server.js');
|
|
514
|
+
const config = (0, config_1.getConfig)();
|
|
515
|
+
const mcpConfig = JSON.stringify({
|
|
516
|
+
mcpServers: {
|
|
517
|
+
'agent-tempo': {
|
|
518
|
+
type: 'stdio',
|
|
519
|
+
command: 'node',
|
|
520
|
+
args: [mcpServerPath],
|
|
521
|
+
env: {
|
|
522
|
+
[config_1.ENV.ENSEMBLE]: config.ensemble,
|
|
523
|
+
[config_1.ENV.PLAYER_NAME]: this.playerName,
|
|
524
|
+
[config_1.ENV.TEMPORAL_ADDRESS]: config.temporalAddress,
|
|
525
|
+
[config_1.ENV.TEMPORAL_NAMESPACE]: config.temporalNamespace,
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
},
|
|
529
|
+
});
|
|
530
|
+
// Build the per-turn argv. `--resume` only on subsequent turns —
|
|
531
|
+
// detect by checking the per-cwd JSONL session file (see design
|
|
532
|
+
// §5.1 and the §11.2 cwd-encoding spike check).
|
|
533
|
+
const sessionFile = path.join(os.homedir(), '.claude', 'projects', encodeCwd(process.cwd()), `${sessionId}.jsonl`);
|
|
534
|
+
const isResume = fs.existsSync(sessionFile);
|
|
535
|
+
// #536 — per-turn system-prompt injection. The shared template
|
|
536
|
+
// (also used by copilot via `sessionConfig.systemMessage`) tells
|
|
537
|
+
// the model to use MCP tools — including `cue` — to reply. Without
|
|
538
|
+
// this the model produced English-prose responses to stdout that
|
|
539
|
+
// the adapter captured and discarded; no cue-back ever surfaced.
|
|
540
|
+
const systemPrompt = (0, prompt_1.buildSdkSystemPrompt)({ ensemble: config.ensemble });
|
|
541
|
+
const args = (0, prompt_1.buildClaudeArgs)({
|
|
542
|
+
sessionId,
|
|
543
|
+
isResume,
|
|
544
|
+
mcpConfig,
|
|
545
|
+
systemPrompt,
|
|
546
|
+
promptText,
|
|
547
|
+
permissionMode: this.permissionMode,
|
|
548
|
+
dangerouslySkipPermissions: this.dangerouslySkipPermissions,
|
|
549
|
+
});
|
|
550
|
+
// Env hygiene per design §3.6. ANTHROPIC_API_KEY would defeat the
|
|
551
|
+
// adapter's whole point (subscription billing); CLAUDE_CODE_OAUTH_TOKEN
|
|
552
|
+
// would force long-lived OAuth instead of the host's keychain. Strip
|
|
553
|
+
// both. Also strip AGENT_TEMPO_* (adapter-internal — the MCP server
|
|
554
|
+
// child gets its own env block via --mcp-config).
|
|
555
|
+
const childEnv = { ...process.env };
|
|
556
|
+
delete childEnv.ANTHROPIC_API_KEY;
|
|
557
|
+
delete childEnv.CLAUDE_CODE_OAUTH_TOKEN;
|
|
558
|
+
for (const k of Object.keys(childEnv)) {
|
|
559
|
+
if (k.startsWith('AGENT_TEMPO_'))
|
|
560
|
+
delete childEnv[k];
|
|
561
|
+
}
|
|
562
|
+
// Windows: per architect's PR-3 reminder + the established pattern
|
|
563
|
+
// from spawnInTerminal / spawnOpenCodeAdapter, npm-installed binaries
|
|
564
|
+
// land as `.cmd` shims that Node's `CreateProcess` won't run directly
|
|
565
|
+
// and `shell: true` trips DEP0190. Wrap via `cmd.exe /c claude ...`
|
|
566
|
+
// explicitly. Non-Windows hosts spawn `claude` directly.
|
|
567
|
+
const isWindows = process.platform === 'win32';
|
|
568
|
+
const spawnCmd = isWindows ? 'cmd.exe' : 'claude';
|
|
569
|
+
const spawnArgs = isWindows ? ['/c', 'claude', ...args] : args;
|
|
570
|
+
log(`spawning claude -p (sessionId=${sessionId}, resume=${isResume}, permissionMode=${this.dangerouslySkipPermissions ? 'dangerously-skip-permissions' : this.permissionMode}, batch=${messages.length})`);
|
|
571
|
+
const child = (0, child_process_1.spawn)(spawnCmd, spawnArgs, {
|
|
572
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
573
|
+
env: childEnv,
|
|
574
|
+
// Don't inherit a controlling TTY — adapter runs headless.
|
|
575
|
+
detached: false,
|
|
576
|
+
});
|
|
577
|
+
this.childProcess = child;
|
|
578
|
+
const reader = new stream_json_1.StreamJsonReader({
|
|
579
|
+
onParseError: (line, err) => {
|
|
580
|
+
log(`malformed stream-json frame skipped: ${err.message} — first 120 bytes: ${line.slice(0, 120)}`);
|
|
581
|
+
},
|
|
582
|
+
});
|
|
583
|
+
child.stdout.on('data', (chunk) => reader.feed(chunk));
|
|
584
|
+
const stderrChunks = [];
|
|
585
|
+
let stderrBytes = 0;
|
|
586
|
+
const STDERR_CAP = 4096;
|
|
587
|
+
child.stderr.on('data', (chunk) => {
|
|
588
|
+
const s = chunk.toString('utf8');
|
|
589
|
+
if (stderrBytes < STDERR_CAP) {
|
|
590
|
+
stderrChunks.push(s);
|
|
591
|
+
stderrBytes += s.length;
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
// Wait for subprocess exit OR per-turn timeout. The timeout SIGTERMs
|
|
595
|
+
// the child via `onSuperseded`'s machinery (childProcess pointer is
|
|
596
|
+
// set above) — same path the lease-loss abort uses.
|
|
597
|
+
let timedOut = false;
|
|
598
|
+
let timer = null;
|
|
599
|
+
const exitCode = await new Promise((resolve) => {
|
|
600
|
+
timer = setTimeout(() => {
|
|
601
|
+
timedOut = true;
|
|
602
|
+
log(`turn timeout (${timeoutMs}ms) — SIGTERMing claude subprocess`);
|
|
603
|
+
try {
|
|
604
|
+
child.kill('SIGTERM');
|
|
605
|
+
}
|
|
606
|
+
catch (err) {
|
|
607
|
+
log('SIGTERM threw:', err?.message ?? err);
|
|
608
|
+
}
|
|
609
|
+
}, timeoutMs);
|
|
610
|
+
child.on('exit', (code) => resolve(code));
|
|
611
|
+
});
|
|
612
|
+
if (timer)
|
|
613
|
+
clearTimeout(timer);
|
|
614
|
+
// Flush any trailing stdout line that arrived without a newline.
|
|
615
|
+
reader.flush();
|
|
616
|
+
this.childProcess = null;
|
|
617
|
+
const turn = reader.snapshot();
|
|
618
|
+
const stderr = stderrChunks.join('');
|
|
619
|
+
// Telemetry — log `apiKeySource: 'none'` from init so operators can
|
|
620
|
+
// confirm OAuth subscription billing is in effect. Architect note
|
|
621
|
+
// from spike comment.
|
|
622
|
+
if (turn.initApiKeySource !== null) {
|
|
623
|
+
log(`init apiKeySource=${turn.initApiKeySource} model=${turn.initModel ?? 'unknown'} (apiKeySource='none' confirms OAuth subscription billing)`);
|
|
624
|
+
}
|
|
625
|
+
if (turn.pluginErrors.length > 0) {
|
|
626
|
+
log(`WARNING: plugin_errors observed: ${JSON.stringify(turn.pluginErrors)}`);
|
|
627
|
+
}
|
|
628
|
+
// Surface informational rate-limit transitions for ops visibility.
|
|
629
|
+
// Architect Constraint #1: status='allowed' is informational — log
|
|
630
|
+
// only the action-required transitions to keep the log signal clean.
|
|
631
|
+
for (const evt of turn.rateLimitEvents) {
|
|
632
|
+
const status = evt.rate_limit_info?.status;
|
|
633
|
+
const overage = evt.rate_limit_info?.overageStatus;
|
|
634
|
+
if (status === 'blocked') {
|
|
635
|
+
log(`WARNING: rate_limit_event status=${status} overageStatus=${overage} — see error-mapper for classifier dispatch`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
// Per-turn telemetry log (design §5.6). `total_cost_usd` is reported
|
|
639
|
+
// even on subscription billing — it reflects equivalent API cost,
|
|
640
|
+
// not actual subscription burn. Operators should know this.
|
|
641
|
+
log(`turn-usage adapter=claude-code-headless model=${turn.initModel ?? 'unknown'} ` +
|
|
642
|
+
`input=${turn.usage?.['input_tokens'] ?? 0} ` +
|
|
643
|
+
`output=${turn.usage?.['output_tokens'] ?? 0} ` +
|
|
644
|
+
`cache_read=${turn.usage?.['cache_read_input_tokens'] ?? 0} ` +
|
|
645
|
+
`cache_create=${turn.usage?.['cache_creation_input_tokens'] ?? 0} ` +
|
|
646
|
+
`cost_usd=${turn.totalCostUsd ?? 0} ` +
|
|
647
|
+
`elapsed_ms=${Date.now() - t0} ` +
|
|
648
|
+
`player=${this.playerName} ` +
|
|
649
|
+
`stop_reason=${turn.stopReason ?? 'none'}`);
|
|
650
|
+
// ── Success path ──
|
|
651
|
+
if (turn.resultFrameSeen &&
|
|
652
|
+
turn.resultIsError === false &&
|
|
653
|
+
exitCode === 0) {
|
|
654
|
+
return {
|
|
655
|
+
sdkResult: {
|
|
656
|
+
assistantText: turn.assembledText,
|
|
657
|
+
stopReason: turn.stopReason,
|
|
658
|
+
usage: turn.usage,
|
|
659
|
+
totalCostUsd: turn.totalCostUsd,
|
|
660
|
+
},
|
|
661
|
+
elapsedMs: Date.now() - t0,
|
|
662
|
+
};
|
|
663
|
+
}
|
|
664
|
+
// ── Failure path ── classify and surface a useful error.
|
|
665
|
+
const ctx = { exitCode: timedOut ? null : exitCode, stderr, turn };
|
|
666
|
+
const category = (0, error_mapper_1.mapSubprocessFailure)(ctx);
|
|
667
|
+
const description = (0, error_mapper_1.describeFailure)(ctx);
|
|
668
|
+
log(`classifier=${category}: ${description}`);
|
|
669
|
+
// Throwing here surfaces to `SdkAttachment.deliver()`'s try/finally
|
|
670
|
+
// so `processingEnd` still fires and the message stays PENDING (no
|
|
671
|
+
// markDelivered on failure). The classifier category is logged for
|
|
672
|
+
// future PR-3 follow-up: when #521's shared classifier lands, the
|
|
673
|
+
// adapter's retry-budget logic will read this category and escalate
|
|
674
|
+
// to detach after N=10 consecutive `retriable-with-backoff` failures.
|
|
675
|
+
throw new Error(`claude -p ${category}: ${description}`);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
exports.ClaudeCodeHeadlessAttachment = ClaudeCodeHeadlessAttachment;
|
|
679
|
+
/**
|
|
680
|
+
* Encode a cwd into Claude Code's per-cwd project-dir naming scheme.
|
|
681
|
+
* Confirmed empirically in the §11.2 spike check (issue #520) — every
|
|
682
|
+
* `:`, `/`, and `\` becomes `-`. Drive prefixes like `C:\` produce a
|
|
683
|
+
* double-dash (`C--`).
|
|
684
|
+
*
|
|
685
|
+
* Pinned by `tests/adapters/claude-code-headless/cwd-encoding.test.ts`
|
|
686
|
+
* against the captured fixture so a future Claude Code minor bump that
|
|
687
|
+
* changes the scheme breaks loudly here, not silently in resume.
|
|
688
|
+
*
|
|
689
|
+
* Exported for tests only — production callers go through the on-disk
|
|
690
|
+
* sessionFile-exists check in `invokeSdkWithBatch`.
|
|
691
|
+
*/
|
|
692
|
+
function encodeCwd(cwd) {
|
|
693
|
+
return cwd.replace(/[\/\\:]/g, '-');
|
|
694
|
+
}
|
|
695
|
+
// Self-exec entry point — same pattern as claude-api / opencode. When this
|
|
696
|
+
// file is launched as `node dist/adapters/claude-code-headless/adapter.js`
|
|
697
|
+
// (per the spawn helper in src/spawn.ts), boot the adapter. When imported
|
|
698
|
+
// by the registry during normal MCP-server startup, no-op.
|
|
699
|
+
if (require.main === module) {
|
|
700
|
+
const opts = {};
|
|
701
|
+
const pmode = process.env[config_1.ENV.PERMISSION_MODE];
|
|
702
|
+
if (pmode)
|
|
703
|
+
opts.permissionMode = pmode;
|
|
704
|
+
if (process.env[config_1.ENV.DANGEROUSLY_SKIP_PERMISSIONS] === '1')
|
|
705
|
+
opts.dangerouslySkipPermissions = true;
|
|
706
|
+
new ClaudeCodeHeadlessAttachment(opts).run().catch((err) => {
|
|
707
|
+
log('Fatal error:', err);
|
|
708
|
+
process.exit(1);
|
|
709
|
+
});
|
|
710
|
+
}
|