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,207 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.probeClaudeBinary = probeClaudeBinary;
|
|
4
|
+
exports.probeClaudeAuth = probeClaudeAuth;
|
|
5
|
+
exports.parseAuthStatusOutput = parseAuthStatusOutput;
|
|
6
|
+
/**
|
|
7
|
+
* Pre-flight probes for the claude-code-headless adapter.
|
|
8
|
+
*
|
|
9
|
+
* Two checks, both invoked from `src/tools/recruit.ts` before submitting the
|
|
10
|
+
* spawn outbox entry; both also re-used by the daemon boot probe (PR-2) so
|
|
11
|
+
* cross-host recruit can fail fast against an unconfigured host.
|
|
12
|
+
*
|
|
13
|
+
* 1. **Binary probe** — `claude --version` exits 0 within 3s. Catches the
|
|
14
|
+
* "Claude Code not installed" case with an actionable error, distinct
|
|
15
|
+
* from "logged out" (#2 below).
|
|
16
|
+
* 2. **Auth probe** — `claude auth status` exits 0 within 5s and emits a
|
|
17
|
+
* JSON envelope with `loggedIn: true`. Confirms the host's Claude Code
|
|
18
|
+
* CLI has a usable OAuth session — which is the whole point of this
|
|
19
|
+
* adapter (subscription extra-usage credits, design §1).
|
|
20
|
+
*
|
|
21
|
+
* Both probes are pure observers — they make NO billed API call and NO
|
|
22
|
+
* subprocess that registers as an ensemble player. The auth probe is an
|
|
23
|
+
* official `claude auth` subcommand; the version probe is a one-line
|
|
24
|
+
* `--version` invocation.
|
|
25
|
+
*
|
|
26
|
+
* Spike findings (issue #520 §11.3, captured 2026-05-02): `claude auth
|
|
27
|
+
* status` outputs JSON in all logged-in states; exit code is 0 even when
|
|
28
|
+
* logged out, so the boolean `loggedIn` field is the source of truth.
|
|
29
|
+
*
|
|
30
|
+
* Design reference: `docs/design/520-claude-code-headless-adapter.md`
|
|
31
|
+
* §3.4 (recruit pre-flight contract)
|
|
32
|
+
* §11.3 (auth-status parser fixtures)
|
|
33
|
+
*/
|
|
34
|
+
const child_process_1 = require("child_process");
|
|
35
|
+
const VERSION_PROBE_TIMEOUT_MS = 3_000;
|
|
36
|
+
const AUTH_PROBE_TIMEOUT_MS = 5_000;
|
|
37
|
+
/**
|
|
38
|
+
* Probe whether `claude --version` is callable on the host PATH and returns
|
|
39
|
+
* a parseable version string. Bounded by {@link VERSION_PROBE_TIMEOUT_MS} so
|
|
40
|
+
* a hung binary can't stall the recruit pre-flight.
|
|
41
|
+
*
|
|
42
|
+
* Returns `{ ok: false, error }` for missing binary, hung process, or
|
|
43
|
+
* non-zero exit. The error string is operator-actionable (mentions both
|
|
44
|
+
* "install" and "PATH" so the user knows where to start).
|
|
45
|
+
*/
|
|
46
|
+
function probeClaudeBinary(claudeBin = 'claude') {
|
|
47
|
+
let result;
|
|
48
|
+
try {
|
|
49
|
+
result = (0, child_process_1.spawnSync)(claudeBin, ['--version'], {
|
|
50
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
51
|
+
timeout: VERSION_PROBE_TIMEOUT_MS,
|
|
52
|
+
// shell: false on Windows — npm-installed `claude` is a `.cmd` shim;
|
|
53
|
+
// spawnSync's `shell: false` path won't find it. Workaround: call via
|
|
54
|
+
// `cmd.exe /c` on Windows so the shim resolves.
|
|
55
|
+
shell: false,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return {
|
|
60
|
+
ok: false,
|
|
61
|
+
error: `\`${claudeBin} --version\` failed to spawn: ${err?.message ?? err}. Install Claude Code (https://claude.com/download) and ensure \`${claudeBin}\` is on PATH.`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
if (result.error && result.error.code === 'ENOENT') {
|
|
65
|
+
// Try Windows `.cmd` fallback — npm-installed CLI binaries land as `.cmd`
|
|
66
|
+
// shims that bare spawnSync without shell can't resolve.
|
|
67
|
+
if (process.platform === 'win32' && claudeBin === 'claude') {
|
|
68
|
+
const winResult = (0, child_process_1.spawnSync)('cmd.exe', ['/c', 'claude', '--version'], {
|
|
69
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
70
|
+
timeout: VERSION_PROBE_TIMEOUT_MS,
|
|
71
|
+
});
|
|
72
|
+
if (winResult.status === 0) {
|
|
73
|
+
const version = (winResult.stdout?.toString('utf8') ?? '').trim();
|
|
74
|
+
return { ok: true, version: parseVersion(version) };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
ok: false,
|
|
79
|
+
error: `\`${claudeBin}\` not found on PATH. Install Claude Code (https://claude.com/download) and verify \`which ${claudeBin}\` resolves.`,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
// spawnSync sets `signal: 'SIGTERM'` on timeout; status is null in that case.
|
|
83
|
+
if (result.signal === 'SIGTERM' || (result.status === null && result.signal !== null)) {
|
|
84
|
+
return {
|
|
85
|
+
ok: false,
|
|
86
|
+
error: `\`${claudeBin} --version\` timed out after ${VERSION_PROBE_TIMEOUT_MS}ms. The binary may be hung or stuck on a first-run prompt; try \`${claudeBin} --version\` interactively first.`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (result.status !== 0) {
|
|
90
|
+
const stderr = (result.stderr?.toString('utf8') ?? '').trim().slice(0, 200);
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
error: `\`${claudeBin} --version\` exited ${result.status}${stderr ? `: ${stderr}` : ''}.`,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const version = parseVersion((result.stdout?.toString('utf8') ?? '').trim());
|
|
97
|
+
return { ok: true, version };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Probe whether the host's Claude Code CLI is logged in to an Anthropic
|
|
101
|
+
* account. Calls `claude auth status` — an official supported subcommand
|
|
102
|
+
* that does NOT make a billed API call.
|
|
103
|
+
*
|
|
104
|
+
* Per spike findings (#520 §11.3), exit code is 0 in all cases — the
|
|
105
|
+
* boolean `loggedIn` field in the JSON envelope is the source of truth.
|
|
106
|
+
*
|
|
107
|
+
* Returns `{ loggedIn: false, error }` for: not-logged-in, malformed JSON,
|
|
108
|
+
* timeout, or spawn failure. Caller surfaces `error` actionably.
|
|
109
|
+
*/
|
|
110
|
+
function probeClaudeAuth(claudeBin = 'claude') {
|
|
111
|
+
let result;
|
|
112
|
+
try {
|
|
113
|
+
result = (0, child_process_1.spawnSync)(claudeBin, ['auth', 'status'], {
|
|
114
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
115
|
+
timeout: AUTH_PROBE_TIMEOUT_MS,
|
|
116
|
+
shell: false,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
return {
|
|
121
|
+
loggedIn: false,
|
|
122
|
+
error: `\`${claudeBin} auth status\` failed to spawn: ${err?.message ?? err}.`,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
// Windows .cmd shim fallback (mirrors probeClaudeBinary). Per QA Nit 2 from
|
|
126
|
+
// PR-1's review: explicitly check whether the cmd.exe fallback also failed,
|
|
127
|
+
// so the error copy stays "not found on PATH" instead of degrading to the
|
|
128
|
+
// generic "produced no output" the parser would otherwise emit on empty stdout.
|
|
129
|
+
if (result.error && result.error.code === 'ENOENT') {
|
|
130
|
+
if (process.platform === 'win32' && claudeBin === 'claude') {
|
|
131
|
+
result = (0, child_process_1.spawnSync)('cmd.exe', ['/c', 'claude', 'auth', 'status'], {
|
|
132
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
133
|
+
timeout: AUTH_PROBE_TIMEOUT_MS,
|
|
134
|
+
});
|
|
135
|
+
if (result.status !== 0 && (!result.stdout || result.stdout.length === 0)) {
|
|
136
|
+
const stderr = (result.stderr?.toString('utf8') ?? '').trim().slice(0, 200);
|
|
137
|
+
return {
|
|
138
|
+
loggedIn: false,
|
|
139
|
+
error: `\`${claudeBin}\` not found on PATH (cmd.exe shim also failed: ${stderr || `exit ${result.status}`}).`,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
return { loggedIn: false, error: `\`${claudeBin}\` not found on PATH.` };
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (result.signal === 'SIGTERM' || (result.status === null && result.signal !== null)) {
|
|
148
|
+
return {
|
|
149
|
+
loggedIn: false,
|
|
150
|
+
error: `\`${claudeBin} auth status\` timed out after ${AUTH_PROBE_TIMEOUT_MS}ms.`,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const stdout = (result.stdout?.toString('utf8') ?? '').trim();
|
|
154
|
+
return parseAuthStatusOutput(stdout, result.status, claudeBin);
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Parse a `claude auth status` stdout envelope. Exported for unit tests
|
|
158
|
+
* that load fixtures from `tests/adapters/fixtures/claude-code-headless/`.
|
|
159
|
+
*
|
|
160
|
+
* Per spike findings, the schema is JSON `{loggedIn, authMethod?, apiProvider?, ...}`.
|
|
161
|
+
* Logged-out variant is `{loggedIn: false}`. We tolerate trailing whitespace
|
|
162
|
+
* and missing optional fields.
|
|
163
|
+
*/
|
|
164
|
+
function parseAuthStatusOutput(stdout, exitStatus, claudeBin = 'claude') {
|
|
165
|
+
if (!stdout) {
|
|
166
|
+
return {
|
|
167
|
+
loggedIn: false,
|
|
168
|
+
error: `\`${claudeBin} auth status\` produced no output (exit=${exitStatus}).`,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
let parsed;
|
|
172
|
+
try {
|
|
173
|
+
parsed = JSON.parse(stdout);
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
return {
|
|
177
|
+
loggedIn: false,
|
|
178
|
+
error: `Failed to parse \`${claudeBin} auth status\` JSON output: ${err?.message ?? err}. First 200 bytes: ${stdout.slice(0, 200)}`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
182
|
+
return {
|
|
183
|
+
loggedIn: false,
|
|
184
|
+
error: `\`${claudeBin} auth status\` returned non-object JSON: ${stdout.slice(0, 200)}`,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const obj = parsed;
|
|
188
|
+
const loggedIn = obj.loggedIn === true;
|
|
189
|
+
const authMethod = typeof obj.authMethod === 'string' ? obj.authMethod : undefined;
|
|
190
|
+
const apiProvider = typeof obj.apiProvider === 'string' ? obj.apiProvider : undefined;
|
|
191
|
+
if (!loggedIn) {
|
|
192
|
+
return {
|
|
193
|
+
loggedIn: false,
|
|
194
|
+
error: `\`${claudeBin}\` is installed but not logged in. Run \`${claudeBin} auth login\` (subscription) or \`${claudeBin} auth setup-token\` (CI/long-lived OAuth), or recruit with \`agent: 'claude-api'\` to use a Console API key instead.`,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return { loggedIn: true, authMethod, apiProvider };
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Parse the version string from `claude --version` stdout. The CLI prints
|
|
201
|
+
* `"2.1.126 (Claude Code)"` — we keep just the dotted-number prefix so
|
|
202
|
+
* downstream comparators work cleanly.
|
|
203
|
+
*/
|
|
204
|
+
function parseVersion(raw) {
|
|
205
|
+
const m = raw.match(/^(\d+\.\d+\.\d+(?:[-+][0-9a-zA-Z.]+)?)/);
|
|
206
|
+
return m ? m[1] : raw || undefined;
|
|
207
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure prompt-building helpers for the claude-code-headless adapter.
|
|
3
|
+
*
|
|
4
|
+
* Issue #536 root cause: `invokeSdkWithBatch` in `adapter.ts` was
|
|
5
|
+
* inlining both the per-message attribution prompt AND the per-turn
|
|
6
|
+
* argv composition, with no `--append-system-prompt` and no
|
|
7
|
+
* MAESTRO_ACK augmentation. The model received only
|
|
8
|
+
* `[from X]: <text>` framing, no MCP-tool guidance, and replied with
|
|
9
|
+
* stdout prose that the adapter captured but had nowhere to deliver
|
|
10
|
+
* — so cues from the dashboard saw zero cue-back replies.
|
|
11
|
+
*
|
|
12
|
+
* This module factors the two prompt-build steps out of the adapter
|
|
13
|
+
* for two reasons:
|
|
14
|
+
*
|
|
15
|
+
* 1. **Testability.** Both helpers are pure — no Temporal client,
|
|
16
|
+
* no subprocess, no filesystem. The test in
|
|
17
|
+
* `tests/adapters/claude-code-headless/prompt.test.ts` exercises
|
|
18
|
+
* every `--append-system-prompt` invariant + every MAESTRO_ACK
|
|
19
|
+
* conditional shape directly, instead of having to stub a
|
|
20
|
+
* whole subprocess + spawn pipeline.
|
|
21
|
+
*
|
|
22
|
+
* 2. **Read-locality.** The `invokeSdkWithBatch` body in
|
|
23
|
+
* `adapter.ts` was already 80+ lines of mixed concerns
|
|
24
|
+
* (subprocess spawn, env hygiene, stream-json read loop,
|
|
25
|
+
* cleanup). Extracting the string composition keeps the per-
|
|
26
|
+
* turn driver focused on the I/O side.
|
|
27
|
+
*/
|
|
28
|
+
import type { Message } from '../../types';
|
|
29
|
+
import { buildSdkSystemPrompt } from '../sdk/system-prompt';
|
|
30
|
+
import type { ClaudeCodeHeadlessPermissionMode } from './types';
|
|
31
|
+
/**
|
|
32
|
+
* Compose the per-turn prompt text from the workflow's queued
|
|
33
|
+
* messages. Mirrors copilot's poll-loop pattern at
|
|
34
|
+
* `src/adapters/copilot/adapter.ts:639-645` — same conditional
|
|
35
|
+
* MAESTRO_ACK augmentation per `m.isMaestro`, same `\n\n` join.
|
|
36
|
+
*
|
|
37
|
+
* The attribution prefix is `[from X]:` (matches the pre-#536
|
|
38
|
+
* shape in `invokeSdkWithBatch`); copilot's `[Message from X]:` is
|
|
39
|
+
* stylistic drift from a different vintage but is left unchanged
|
|
40
|
+
* here since #536 is scoped to the cue-back framing fix, not a
|
|
41
|
+
* cross-adapter prompt-styling unification.
|
|
42
|
+
*
|
|
43
|
+
* @returns Empty string when `messages` is empty (no `\n\n` floor).
|
|
44
|
+
*/
|
|
45
|
+
export declare function buildPromptText(messages: Message[]): string;
|
|
46
|
+
export interface BuildClaudeArgsOpts {
|
|
47
|
+
/** Deterministic session UUID — pinned via `--session-id` on first
|
|
48
|
+
* turn, found via `--resume` on subsequent turns. */
|
|
49
|
+
sessionId: string;
|
|
50
|
+
/** True when the per-cwd JSONL session file already exists.
|
|
51
|
+
* Toggles `--resume <id>` vs `--session-id <id>` (mutually
|
|
52
|
+
* exclusive in `claude -p` v2.1.126+). */
|
|
53
|
+
isResume: boolean;
|
|
54
|
+
/** Already-stringified inline `--mcp-config` JSON. The adapter
|
|
55
|
+
* computes this from `getConfig()` at call time; the helper just
|
|
56
|
+
* threads the bytes. */
|
|
57
|
+
mcpConfig: string;
|
|
58
|
+
/** Resolved permission mode (default `'acceptEdits'`). Ignored
|
|
59
|
+
* when `dangerouslySkipPermissions` is true — they're mutually
|
|
60
|
+
* exclusive per #520 and rejected at recruit-tool layer. */
|
|
61
|
+
permissionMode: ClaudeCodeHeadlessPermissionMode;
|
|
62
|
+
/** When true, emit `--dangerously-skip-permissions` and skip
|
|
63
|
+
* `--permission-mode`. */
|
|
64
|
+
dangerouslySkipPermissions: boolean;
|
|
65
|
+
/** Per-turn system-prompt content. Pass the result of
|
|
66
|
+
* `buildSdkSystemPrompt({ ensemble })` for the canonical #536
|
|
67
|
+
* framing. */
|
|
68
|
+
systemPrompt: string;
|
|
69
|
+
/** Final positional argument — the prompt text the model receives
|
|
70
|
+
* for this turn. Pass the result of `buildPromptText(messages)`. */
|
|
71
|
+
promptText: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compose the `claude -p` argv for a single turn. Pure function so
|
|
75
|
+
* tests can pin every flag invariant without mocking `spawn`.
|
|
76
|
+
*
|
|
77
|
+
* #536 change: emits `--append-system-prompt <systemPrompt>` to
|
|
78
|
+
* inject the canonical "use your MCP tools to reply" framing into
|
|
79
|
+
* the model's per-request system prompt. The flag is in the request
|
|
80
|
+
* itself, so it dodges the MCP-startup race the priming-turn pattern
|
|
81
|
+
* would otherwise mitigate (per the issue body's "MCP startup race —
|
|
82
|
+
* secondary" footnote).
|
|
83
|
+
*
|
|
84
|
+
* Invariant ordering (kept stable so transcripts and CI snapshots
|
|
85
|
+
* compare cleanly across releases):
|
|
86
|
+
* `-p` → `--output-format` → `--verbose` → `--strict-mcp-config`
|
|
87
|
+
* → `--mcp-config` → `--append-system-prompt`
|
|
88
|
+
* → (`--resume` | `--session-id`)
|
|
89
|
+
* → (`--dangerously-skip-permissions` | `--permission-mode`)
|
|
90
|
+
* → `<promptText>`
|
|
91
|
+
*/
|
|
92
|
+
export declare function buildClaudeArgs(opts: BuildClaudeArgsOpts): string[];
|
|
93
|
+
export { buildSdkSystemPrompt };
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildSdkSystemPrompt = void 0;
|
|
4
|
+
exports.buildPromptText = buildPromptText;
|
|
5
|
+
exports.buildClaudeArgs = buildClaudeArgs;
|
|
6
|
+
const system_prompt_1 = require("../sdk/system-prompt");
|
|
7
|
+
Object.defineProperty(exports, "buildSdkSystemPrompt", { enumerable: true, get: function () { return system_prompt_1.buildSdkSystemPrompt; } });
|
|
8
|
+
/**
|
|
9
|
+
* Compose the per-turn prompt text from the workflow's queued
|
|
10
|
+
* messages. Mirrors copilot's poll-loop pattern at
|
|
11
|
+
* `src/adapters/copilot/adapter.ts:639-645` — same conditional
|
|
12
|
+
* MAESTRO_ACK augmentation per `m.isMaestro`, same `\n\n` join.
|
|
13
|
+
*
|
|
14
|
+
* The attribution prefix is `[from X]:` (matches the pre-#536
|
|
15
|
+
* shape in `invokeSdkWithBatch`); copilot's `[Message from X]:` is
|
|
16
|
+
* stylistic drift from a different vintage but is left unchanged
|
|
17
|
+
* here since #536 is scoped to the cue-back framing fix, not a
|
|
18
|
+
* cross-adapter prompt-styling unification.
|
|
19
|
+
*
|
|
20
|
+
* @returns Empty string when `messages` is empty (no `\n\n` floor).
|
|
21
|
+
*/
|
|
22
|
+
function buildPromptText(messages) {
|
|
23
|
+
return messages
|
|
24
|
+
.map((m) => {
|
|
25
|
+
const line = `[from ${m.from}]: ${m.text}`;
|
|
26
|
+
return m.isMaestro ? line + system_prompt_1.MAESTRO_ACK : line;
|
|
27
|
+
})
|
|
28
|
+
.join('\n\n');
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compose the `claude -p` argv for a single turn. Pure function so
|
|
32
|
+
* tests can pin every flag invariant without mocking `spawn`.
|
|
33
|
+
*
|
|
34
|
+
* #536 change: emits `--append-system-prompt <systemPrompt>` to
|
|
35
|
+
* inject the canonical "use your MCP tools to reply" framing into
|
|
36
|
+
* the model's per-request system prompt. The flag is in the request
|
|
37
|
+
* itself, so it dodges the MCP-startup race the priming-turn pattern
|
|
38
|
+
* would otherwise mitigate (per the issue body's "MCP startup race —
|
|
39
|
+
* secondary" footnote).
|
|
40
|
+
*
|
|
41
|
+
* Invariant ordering (kept stable so transcripts and CI snapshots
|
|
42
|
+
* compare cleanly across releases):
|
|
43
|
+
* `-p` → `--output-format` → `--verbose` → `--strict-mcp-config`
|
|
44
|
+
* → `--mcp-config` → `--append-system-prompt`
|
|
45
|
+
* → (`--resume` | `--session-id`)
|
|
46
|
+
* → (`--dangerously-skip-permissions` | `--permission-mode`)
|
|
47
|
+
* → `<promptText>`
|
|
48
|
+
*/
|
|
49
|
+
function buildClaudeArgs(opts) {
|
|
50
|
+
return [
|
|
51
|
+
'-p',
|
|
52
|
+
'--output-format', 'stream-json',
|
|
53
|
+
'--verbose',
|
|
54
|
+
'--strict-mcp-config',
|
|
55
|
+
'--mcp-config', opts.mcpConfig,
|
|
56
|
+
// #536 — per-turn system-prompt injection. Without this, the
|
|
57
|
+
// model received only `[from X]: <text>` framing and had no
|
|
58
|
+
// reason to call the `cue` MCP tool to reply.
|
|
59
|
+
'--append-system-prompt', opts.systemPrompt,
|
|
60
|
+
// Mutually exclusive — `claude -p` v2.1.126 rejects the combo
|
|
61
|
+
// `--session-id X --resume X` with: *"--session-id can only be
|
|
62
|
+
// used with --continue or --resume if --fork-session is also
|
|
63
|
+
// specified."* Spike-confirmed during PR-4 §8.4 manual smoke;
|
|
64
|
+
// see #520 design doc §16.9. First turn uses `--session-id`
|
|
65
|
+
// to PIN the deterministic UUID; subsequent turns use `--resume`
|
|
66
|
+
// alone (the resume target IS the same UUID — the JSONL
|
|
67
|
+
// filename embeds it, so claude finds the right session).
|
|
68
|
+
...(opts.isResume
|
|
69
|
+
? ['--resume', opts.sessionId]
|
|
70
|
+
: ['--session-id', opts.sessionId]),
|
|
71
|
+
...(opts.dangerouslySkipPermissions
|
|
72
|
+
? ['--dangerously-skip-permissions']
|
|
73
|
+
: ['--permission-mode', opts.permissionMode]),
|
|
74
|
+
// Trailing positional argument — the prompt text. The CLI accepts
|
|
75
|
+
// up to ARG_MAX bytes here (Windows: 32KB). Per #520 §11.5 spike
|
|
76
|
+
// check, typical multi-cue batches stay well under the limit.
|
|
77
|
+
opts.promptText,
|
|
78
|
+
];
|
|
79
|
+
}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stream-JSON frame parser for `claude -p --output-format stream-json`.
|
|
3
|
+
*
|
|
4
|
+
* Issue #520 PR-3. Parses the newline-delimited JSON envelope the Claude
|
|
5
|
+
* Code CLI emits during a per-turn invocation, accumulating the bits the
|
|
6
|
+
* adapter needs (assembled assistant text, stop reason, usage, cost, plus
|
|
7
|
+
* the fatal-/transient-classifier inputs).
|
|
8
|
+
*
|
|
9
|
+
* **Schema is grounded in the §11.1 spike fixtures** captured against
|
|
10
|
+
* `claude --version` 2.1.126 — see `tests/adapters/fixtures/claude-code-headless/`.
|
|
11
|
+
* Three deltas vs design §5.3 (documented in §16 spike-findings appendix):
|
|
12
|
+
*
|
|
13
|
+
* 1. **`result` frame has a `subtype: 'success' | 'error'`** — design listed
|
|
14
|
+
* `result` as a top-level type. Reality: `subtype` distinguishes success
|
|
15
|
+
* vs error envelopes. Bonus: `is_error: boolean` + `api_error_status:
|
|
16
|
+
* number | null` are clean classifier inputs (see {@link ResultFrame}).
|
|
17
|
+
* 2. **`system/hook_started` + `system/hook_response` + `system/status`** —
|
|
18
|
+
* not in design. Emitted whenever the host has Claude Code hooks
|
|
19
|
+
* configured (most operators do — SessionStart hooks for project
|
|
20
|
+
* context). The `output`/`stdout` fields can carry arbitrary user
|
|
21
|
+
* content, so we IGNORE them outright (the fixture corpus shows a
|
|
22
|
+
* 107KB SessionStart hook body in real captures).
|
|
23
|
+
* 3. **`rate_limit_event` is a top-level type** — design assumed it was
|
|
24
|
+
* a `system/api_retry` subtype. Reality: it's its own frame. AND it
|
|
25
|
+
* carries TWO signal modes (informational vs action-required) on the
|
|
26
|
+
* same wire shape, distinguished by `rate_limit_info.status`. See
|
|
27
|
+
* {@link RateLimitEvent}.
|
|
28
|
+
*
|
|
29
|
+
* Pure code; no I/O; trivially unit-testable with synthesized + captured
|
|
30
|
+
* fixtures. The error classifier (`./error-mapper.ts`) consumes the
|
|
31
|
+
* accumulator state to emit a single `ApiErrorCategory` per turn.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Permissive frame shape — `claude -p` may add fields between minor versions.
|
|
35
|
+
* Every concrete frame type is a discriminated subset.
|
|
36
|
+
*/
|
|
37
|
+
export interface BaseFrame {
|
|
38
|
+
type: string;
|
|
39
|
+
subtype?: string;
|
|
40
|
+
uuid?: string;
|
|
41
|
+
session_id?: string;
|
|
42
|
+
}
|
|
43
|
+
/** First frame of every turn. Used for telemetry — not classifier input. */
|
|
44
|
+
export interface SystemInitFrame extends BaseFrame {
|
|
45
|
+
type: 'system';
|
|
46
|
+
subtype: 'init';
|
|
47
|
+
/** `'none'` when running on OAuth (subscription billing — the v0.28 default). */
|
|
48
|
+
apiKeySource?: string;
|
|
49
|
+
cwd?: string;
|
|
50
|
+
model?: string;
|
|
51
|
+
permissionMode?: string;
|
|
52
|
+
claude_code_version?: string;
|
|
53
|
+
tools?: string[];
|
|
54
|
+
mcp_servers?: unknown[];
|
|
55
|
+
/** Non-empty array indicates a config error — log loudly. */
|
|
56
|
+
plugin_errors?: unknown[];
|
|
57
|
+
}
|
|
58
|
+
/** Hook lifecycle frames. Adapter IGNORES these — see Delta #2 above. */
|
|
59
|
+
export interface SystemHookFrame extends BaseFrame {
|
|
60
|
+
type: 'system';
|
|
61
|
+
subtype: 'hook_started' | 'hook_response';
|
|
62
|
+
hook_name?: string;
|
|
63
|
+
hook_event?: string;
|
|
64
|
+
/** May contain arbitrary user content (operator's hook output). Ignored. */
|
|
65
|
+
output?: string;
|
|
66
|
+
stdout?: string;
|
|
67
|
+
stderr?: string;
|
|
68
|
+
exit_code?: number;
|
|
69
|
+
outcome?: string;
|
|
70
|
+
}
|
|
71
|
+
/** Bare status heartbeat. Ignored. */
|
|
72
|
+
export interface SystemStatusFrame extends BaseFrame {
|
|
73
|
+
type: 'system';
|
|
74
|
+
subtype: 'status';
|
|
75
|
+
status?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Documented retry signal. May or may not actually fire on v2.x — see Delta #3. */
|
|
78
|
+
export interface SystemApiRetryFrame extends BaseFrame {
|
|
79
|
+
type: 'system';
|
|
80
|
+
subtype: 'api_retry';
|
|
81
|
+
attempt?: number;
|
|
82
|
+
max_retries?: number;
|
|
83
|
+
retry_delay_ms?: number;
|
|
84
|
+
error_status?: number;
|
|
85
|
+
/** Documented enum: `authentication_failed` | `oauth_org_not_allowed` | `billing_error` | `rate_limit` | `invalid_request` | `server_error` | `unknown` | `max_output_tokens`. */
|
|
86
|
+
error?: string;
|
|
87
|
+
}
|
|
88
|
+
/** Top-level rate-limit informational AND action-required signal — Delta #3. */
|
|
89
|
+
export interface RateLimitEvent extends BaseFrame {
|
|
90
|
+
type: 'rate_limit_event';
|
|
91
|
+
rate_limit_info?: {
|
|
92
|
+
/** `'allowed'` (informational, every turn) | `'blocked'` (action-required). */
|
|
93
|
+
status?: string;
|
|
94
|
+
rateLimitType?: string;
|
|
95
|
+
resetsAt?: number;
|
|
96
|
+
/** `'allowed'` | `'blocked'`. When BOTH this AND `status` are blocked → fatal (subscription + extra-usage exhausted). */
|
|
97
|
+
overageStatus?: string;
|
|
98
|
+
overageResetsAt?: number;
|
|
99
|
+
isUsingOverage?: boolean;
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Mid-turn assistant message. Content array may include text / thinking / tool_use blocks. */
|
|
103
|
+
export interface AssistantFrame extends BaseFrame {
|
|
104
|
+
type: 'assistant';
|
|
105
|
+
message?: {
|
|
106
|
+
role?: 'assistant';
|
|
107
|
+
content?: Array<{
|
|
108
|
+
type?: 'text' | 'thinking' | 'tool_use' | string;
|
|
109
|
+
text?: string;
|
|
110
|
+
id?: string;
|
|
111
|
+
name?: string;
|
|
112
|
+
input?: unknown;
|
|
113
|
+
}>;
|
|
114
|
+
stop_reason?: string | null;
|
|
115
|
+
usage?: Record<string, unknown>;
|
|
116
|
+
};
|
|
117
|
+
parent_tool_use_id?: string | null;
|
|
118
|
+
}
|
|
119
|
+
/** Tool result wrapped as user turn — telemetry only. */
|
|
120
|
+
export interface UserFrame extends BaseFrame {
|
|
121
|
+
type: 'user';
|
|
122
|
+
message?: {
|
|
123
|
+
role?: 'user';
|
|
124
|
+
content?: Array<{
|
|
125
|
+
type?: 'tool_result' | string;
|
|
126
|
+
tool_use_id?: string;
|
|
127
|
+
content?: unknown;
|
|
128
|
+
}>;
|
|
129
|
+
};
|
|
130
|
+
tool_use_result?: unknown;
|
|
131
|
+
}
|
|
132
|
+
/** Token-delta frame. Only emitted with `--include-partial-messages`. v1 ignores. */
|
|
133
|
+
export interface StreamEventFrame extends BaseFrame {
|
|
134
|
+
type: 'stream_event';
|
|
135
|
+
event?: unknown;
|
|
136
|
+
ttft_ms?: number;
|
|
137
|
+
}
|
|
138
|
+
/** Closing frame of every turn. Authoritative source for assembled text + usage + cost. */
|
|
139
|
+
export interface ResultFrame extends BaseFrame {
|
|
140
|
+
type: 'result';
|
|
141
|
+
/** `'success'` | `'error'` (and possibly more). Discriminates envelope shape. */
|
|
142
|
+
subtype?: string;
|
|
143
|
+
/** Clean fatal-vs-success boolean — primary classifier input per architect. */
|
|
144
|
+
is_error?: boolean;
|
|
145
|
+
/** HTTP status code on API errors. Reuse claude-api's HTTP-code classifier. */
|
|
146
|
+
api_error_status?: number | null;
|
|
147
|
+
/** Assembled assistant text — the canonical reply the adapter returns. */
|
|
148
|
+
result?: string;
|
|
149
|
+
/** `'end_turn'` | `'max_tokens'` | `'stop_sequence'` | … */
|
|
150
|
+
stop_reason?: string;
|
|
151
|
+
duration_ms?: number;
|
|
152
|
+
duration_api_ms?: number;
|
|
153
|
+
num_turns?: number;
|
|
154
|
+
/** Equivalent API cost (NOT real subscription burn). */
|
|
155
|
+
total_cost_usd?: number;
|
|
156
|
+
usage?: Record<string, unknown>;
|
|
157
|
+
modelUsage?: Record<string, unknown>;
|
|
158
|
+
permission_denials?: unknown[];
|
|
159
|
+
/** `'completed'` | `'aborted'` | … */
|
|
160
|
+
terminal_reason?: string;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Discriminated union of everything we recognize. The parser tolerates
|
|
164
|
+
* unknown `type` strings by passing them through as `BaseFrame`.
|
|
165
|
+
*/
|
|
166
|
+
export type StreamJsonFrame = SystemInitFrame | SystemHookFrame | SystemStatusFrame | SystemApiRetryFrame | RateLimitEvent | AssistantFrame | UserFrame | StreamEventFrame | ResultFrame | BaseFrame;
|
|
167
|
+
/**
|
|
168
|
+
* Per-turn accumulator. The parser folds each frame into this state; the
|
|
169
|
+
* adapter reads it after the subprocess exits to assemble the SDK return
|
|
170
|
+
* value AND to feed the error classifier.
|
|
171
|
+
*/
|
|
172
|
+
export interface TurnAccumulator {
|
|
173
|
+
/** Canonical assembled assistant text — set from `result.result` (preferred) or assistant-frame text fallback. */
|
|
174
|
+
assembledText: string;
|
|
175
|
+
/** `result.stop_reason`. */
|
|
176
|
+
stopReason: string | null;
|
|
177
|
+
/** `result.usage` — opaque token accounting. */
|
|
178
|
+
usage: Record<string, unknown> | null;
|
|
179
|
+
/** `result.total_cost_usd` — equivalent API cost (NOT real subscription burn). */
|
|
180
|
+
totalCostUsd: number | null;
|
|
181
|
+
/** `result.is_error` — primary classifier input. */
|
|
182
|
+
resultIsError: boolean | null;
|
|
183
|
+
/** `result.api_error_status` — HTTP code when is_error=true. */
|
|
184
|
+
resultApiErrorStatus: number | null;
|
|
185
|
+
/** `result.subtype` — `'success'` | `'error'` | … */
|
|
186
|
+
resultSubtype: string | null;
|
|
187
|
+
/** Did we see a `result` frame at all? `false` means subprocess exited before completing the turn. */
|
|
188
|
+
resultFrameSeen: boolean;
|
|
189
|
+
/** `system/api_retry` events observed on stdout — fed into the classifier. */
|
|
190
|
+
apiRetryEvents: SystemApiRetryFrame[];
|
|
191
|
+
/** `rate_limit_event` frames observed — separated by status for the classifier. */
|
|
192
|
+
rateLimitEvents: RateLimitEvent[];
|
|
193
|
+
/** Plugin-config errors from `system/init` — non-empty means config bug. */
|
|
194
|
+
pluginErrors: unknown[];
|
|
195
|
+
/** Model id from `system/init`, e.g. `'claude-opus-4-7[1m]'`. Telemetry only. */
|
|
196
|
+
initModel: string | null;
|
|
197
|
+
/** `apiKeySource` from `system/init` — `'none'` confirms OAuth subscription billing. */
|
|
198
|
+
initApiKeySource: string | null;
|
|
199
|
+
}
|
|
200
|
+
/** Build a fresh accumulator. */
|
|
201
|
+
export declare function newTurnAccumulator(): TurnAccumulator;
|
|
202
|
+
/**
|
|
203
|
+
* Fold one stream-json frame into the accumulator. Pure mutation — return
|
|
204
|
+
* the same instance for chaining.
|
|
205
|
+
*
|
|
206
|
+
* Unknown frame types are silently passed through (the parser is tolerant
|
|
207
|
+
* by design — Claude Code may add new frame types between minor versions
|
|
208
|
+
* and we don't want to crash on them; the adapter only ever acts on the
|
|
209
|
+
* categories we recognize).
|
|
210
|
+
*
|
|
211
|
+
* The hook + status frames are explicitly enumerated as IGNORED rather
|
|
212
|
+
* than falling through `default`, so future readers don't think the
|
|
213
|
+
* pass-through is accidental.
|
|
214
|
+
*/
|
|
215
|
+
export declare function applyFrame(state: TurnAccumulator, frame: StreamJsonFrame): TurnAccumulator;
|
|
216
|
+
/**
|
|
217
|
+
* Stateful line-buffered stream-json reader. Feed it raw stdout chunks;
|
|
218
|
+
* call `flush()` after subprocess exit to emit any trailing partial line.
|
|
219
|
+
*
|
|
220
|
+
* Exposed as a class so the adapter can wire it to the `claude -p`
|
|
221
|
+
* subprocess's `stdout.on('data', ...)` event without needing a
|
|
222
|
+
* Transform stream subclass — keeps the dep surface minimal.
|
|
223
|
+
*
|
|
224
|
+
* Malformed JSON lines are skipped with a logged warning (defensive —
|
|
225
|
+
* shouldn't happen in practice but a single bad line shouldn't crash
|
|
226
|
+
* the turn).
|
|
227
|
+
*/
|
|
228
|
+
export declare class StreamJsonReader {
|
|
229
|
+
private buffer;
|
|
230
|
+
private state;
|
|
231
|
+
private readonly onParseError?;
|
|
232
|
+
constructor(opts?: {
|
|
233
|
+
onParseError?: (line: string, err: Error) => void;
|
|
234
|
+
});
|
|
235
|
+
/** Feed a chunk of stdout. Triggers `applyFrame` for every complete line. */
|
|
236
|
+
feed(chunk: Buffer | string): void;
|
|
237
|
+
/** Process any trailing line that didn't end with a newline. Idempotent. */
|
|
238
|
+
flush(): void;
|
|
239
|
+
/** Snapshot of the current accumulator. Caller may freely mutate. */
|
|
240
|
+
snapshot(): TurnAccumulator;
|
|
241
|
+
private parseLine;
|
|
242
|
+
}
|