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,216 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Thin HTTP/SSE wrapper around `opencode serve`.
|
|
4
|
+
*
|
|
5
|
+
* Hand-rolled over native `fetch` rather than `@opencode-ai/sdk` per design
|
|
6
|
+
* §8.3 LoC tightening proposal #2 — the SDK is auto-generated from
|
|
7
|
+
* OpenAPI 3.1, so it pulls in OpenAPI runtime + per-endpoint typed clients
|
|
8
|
+
* for ~50 endpoints. Our hot path uses ~5 endpoints + the `/event` SSE
|
|
9
|
+
* stream; the SDK weight isn't worth it. The architectural shape of the
|
|
10
|
+
* adapter is identical either way.
|
|
11
|
+
*
|
|
12
|
+
* The SDK is still listed as an `optionalDependency` and `require.resolve`
|
|
13
|
+
* gates the recruit pre-flight (ADR 0015 §85) — operators install it as
|
|
14
|
+
* the signal that opencode integration is intended on this host. Adapter
|
|
15
|
+
* runtime, however, never imports it.
|
|
16
|
+
*
|
|
17
|
+
* Contract surface (5 methods + 1 generator):
|
|
18
|
+
* - `waitForHealth(timeoutMs)`
|
|
19
|
+
* - `getHealth()`
|
|
20
|
+
* - `createSession()`
|
|
21
|
+
* - `promptAsync(sessionId, body)`
|
|
22
|
+
* - `abortSession(sessionId)`
|
|
23
|
+
* - `deleteSession(sessionId)`
|
|
24
|
+
* - `subscribeEvents(abortSignal)` — async generator yielding parsed events
|
|
25
|
+
*
|
|
26
|
+
* Design reference: docs/design/449-opencode-adapter.md §5.3, §8.1.
|
|
27
|
+
*/
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.OpenCodeServerBridge = void 0;
|
|
30
|
+
/** Default health-probe poll interval. Tight loop — opencode boots in <1s. */
|
|
31
|
+
const HEALTH_POLL_INTERVAL_MS = 200;
|
|
32
|
+
class OpenCodeServerBridge {
|
|
33
|
+
baseUrl;
|
|
34
|
+
log;
|
|
35
|
+
fetchImpl;
|
|
36
|
+
constructor(opts) {
|
|
37
|
+
this.baseUrl = opts.baseUrl.replace(/\/$/, '');
|
|
38
|
+
this.log = opts.log ?? ((..._args) => { });
|
|
39
|
+
this.fetchImpl = opts.fetchImpl ?? fetch;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Poll `GET /global/health` until 200 or `timeoutMs` elapses. Throws on
|
|
43
|
+
* timeout — caller is the adapter `run()` and a missing health probe
|
|
44
|
+
* means opencode didn't boot.
|
|
45
|
+
*/
|
|
46
|
+
async waitForHealth(timeoutMs) {
|
|
47
|
+
const deadline = Date.now() + timeoutMs;
|
|
48
|
+
let lastErr = null;
|
|
49
|
+
while (Date.now() < deadline) {
|
|
50
|
+
try {
|
|
51
|
+
const res = await this.fetchImpl(`${this.baseUrl}/global/health`);
|
|
52
|
+
if (res.ok)
|
|
53
|
+
return;
|
|
54
|
+
lastErr = new Error(`/global/health returned ${res.status}`);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
// Connection refused while opencode is still booting — keep polling.
|
|
58
|
+
lastErr = err;
|
|
59
|
+
}
|
|
60
|
+
await sleep(HEALTH_POLL_INTERVAL_MS);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`opencode serve did not become healthy within ${timeoutMs}ms${lastErr ? ` (last error: ${lastErr?.message ?? lastErr})` : ''}`);
|
|
63
|
+
}
|
|
64
|
+
/** `GET /global/health` — version + healthy flag. */
|
|
65
|
+
async getHealth() {
|
|
66
|
+
const res = await this.fetchImpl(`${this.baseUrl}/global/health`);
|
|
67
|
+
if (!res.ok) {
|
|
68
|
+
throw new Error(`/global/health returned ${res.status} ${res.statusText}`);
|
|
69
|
+
}
|
|
70
|
+
return (await res.json());
|
|
71
|
+
}
|
|
72
|
+
/** `POST /session` — create a new session; returns the session id + meta. */
|
|
73
|
+
async createSession() {
|
|
74
|
+
const res = await this.fetchImpl(`${this.baseUrl}/session`, {
|
|
75
|
+
method: 'POST',
|
|
76
|
+
headers: { 'content-type': 'application/json' },
|
|
77
|
+
body: '{}',
|
|
78
|
+
});
|
|
79
|
+
if (!res.ok) {
|
|
80
|
+
const body = await res.text().catch(() => '');
|
|
81
|
+
throw new Error(`POST /session returned ${res.status} ${res.statusText}${body ? ': ' + body : ''}`);
|
|
82
|
+
}
|
|
83
|
+
return (await res.json());
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* `POST /session/:id/prompt_async` — send a turn; returns 204 immediately
|
|
87
|
+
* and the turn streams over `/event` SSE. Caller is responsible for
|
|
88
|
+
* subscribing to events first.
|
|
89
|
+
*/
|
|
90
|
+
async promptAsync(sessionId, body) {
|
|
91
|
+
const res = await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/prompt_async`, {
|
|
92
|
+
method: 'POST',
|
|
93
|
+
headers: { 'content-type': 'application/json' },
|
|
94
|
+
body: JSON.stringify(body),
|
|
95
|
+
});
|
|
96
|
+
if (!res.ok) {
|
|
97
|
+
const text = await res.text().catch(() => '');
|
|
98
|
+
throw new Error(`prompt_async returned ${res.status} ${res.statusText}${text ? ': ' + text : ''}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* `POST /session/:id/abort` — graceful turn cancellation. The primary
|
|
103
|
+
* cancellation path on lease revocation; subprocess SIGTERM is the
|
|
104
|
+
* fallback only if this hangs.
|
|
105
|
+
*
|
|
106
|
+
* Best-effort — swallows non-2xx so the adapter's superseded path can
|
|
107
|
+
* still fall through to subprocess kill without surfacing an error.
|
|
108
|
+
*/
|
|
109
|
+
async abortSession(sessionId, opts) {
|
|
110
|
+
try {
|
|
111
|
+
await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/abort`, { method: 'POST', signal: opts?.signal });
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
this.log('abortSession suppressed error:', err?.message ?? err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* `DELETE /session/:id` — free server-side session resources. Called on
|
|
119
|
+
* graceful detach. Best-effort — swallows non-2xx.
|
|
120
|
+
*/
|
|
121
|
+
async deleteSession(sessionId) {
|
|
122
|
+
try {
|
|
123
|
+
await this.fetchImpl(`${this.baseUrl}/session/${encodeURIComponent(sessionId)}/`, { method: 'DELETE' });
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
this.log('deleteSession suppressed error:', err?.message ?? err);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* `GET /event` — SSE stream of session events. Returns an async
|
|
131
|
+
* generator that yields parsed `OpenCodeEvent` objects until the
|
|
132
|
+
* abort signal fires or the stream closes.
|
|
133
|
+
*
|
|
134
|
+
* The caller is responsible for filtering events by session id —
|
|
135
|
+
* `/event` is global per `opencode serve` instance, but the v1
|
|
136
|
+
* subprocess-per-player model means there's only ever one session
|
|
137
|
+
* per stream anyway. Phase 2 subprocess-shared optimization would
|
|
138
|
+
* make filtering meaningful.
|
|
139
|
+
*/
|
|
140
|
+
async *subscribeEvents(signal) {
|
|
141
|
+
const res = await this.fetchImpl(`${this.baseUrl}/event`, {
|
|
142
|
+
headers: { accept: 'text/event-stream' },
|
|
143
|
+
signal,
|
|
144
|
+
});
|
|
145
|
+
if (!res.ok || !res.body) {
|
|
146
|
+
throw new Error(`/event returned ${res.status} ${res.statusText}`);
|
|
147
|
+
}
|
|
148
|
+
const reader = res.body.getReader();
|
|
149
|
+
const decoder = new TextDecoder('utf-8');
|
|
150
|
+
let buffer = '';
|
|
151
|
+
try {
|
|
152
|
+
while (true) {
|
|
153
|
+
const { value, done } = await reader.read();
|
|
154
|
+
if (done)
|
|
155
|
+
return;
|
|
156
|
+
buffer += decoder.decode(value, { stream: true });
|
|
157
|
+
// SSE: events are separated by blank lines (\n\n). One event may
|
|
158
|
+
// span multiple `data:` lines; concatenate and parse as JSON.
|
|
159
|
+
let sep = buffer.indexOf('\n\n');
|
|
160
|
+
while (sep !== -1) {
|
|
161
|
+
const block = buffer.slice(0, sep);
|
|
162
|
+
buffer = buffer.slice(sep + 2);
|
|
163
|
+
const event = parseSseBlock(block);
|
|
164
|
+
if (event)
|
|
165
|
+
yield event;
|
|
166
|
+
sep = buffer.indexOf('\n\n');
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
// Release the reader so the underlying connection can close.
|
|
172
|
+
try {
|
|
173
|
+
reader.releaseLock();
|
|
174
|
+
}
|
|
175
|
+
catch { /* already released */ }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
exports.OpenCodeServerBridge = OpenCodeServerBridge;
|
|
180
|
+
/**
|
|
181
|
+
* Parse one SSE block (the text between two blank-line separators) into
|
|
182
|
+
* an `OpenCodeEvent`. Returns `null` on parse failure or empty `data`.
|
|
183
|
+
*
|
|
184
|
+
* Format per SSE spec:
|
|
185
|
+
* event: foo (optional — most OpenCode events use only `data:`)
|
|
186
|
+
* data: { ... }
|
|
187
|
+
* data: ... (continuation of data; concatenated with `\n`)
|
|
188
|
+
*/
|
|
189
|
+
function parseSseBlock(block) {
|
|
190
|
+
const dataLines = [];
|
|
191
|
+
for (const line of block.split('\n')) {
|
|
192
|
+
if (line.startsWith('data:')) {
|
|
193
|
+
dataLines.push(line.slice(5).trimStart());
|
|
194
|
+
}
|
|
195
|
+
// event: / id: / retry: lines ignored — agent-tempo only consumes data.
|
|
196
|
+
}
|
|
197
|
+
if (dataLines.length === 0)
|
|
198
|
+
return null;
|
|
199
|
+
const payload = dataLines.join('\n');
|
|
200
|
+
if (!payload)
|
|
201
|
+
return null;
|
|
202
|
+
try {
|
|
203
|
+
const parsed = JSON.parse(payload);
|
|
204
|
+
if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {
|
|
205
|
+
return parsed;
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Non-JSON event — opencode shouldn't emit these; ignore safely.
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
function sleep(ms) {
|
|
215
|
+
return new Promise((r) => setTimeout(r, ms));
|
|
216
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK-class adapter base.
|
|
3
|
+
*
|
|
4
|
+
* Class hierarchy per design §4.1: `SdkAttachment extends BaseAttachment`. Concrete
|
|
5
|
+
* SDK adapters (copilot, future `headless-claude`) extend this.
|
|
6
|
+
*
|
|
7
|
+
* PR-C commit 3 fills in the shared SDK lifecycle on top of the V2 attachment
|
|
8
|
+
* machinery landed in commit 2's `BaseAttachment`:
|
|
9
|
+
*
|
|
10
|
+
* - **Processing-signal pairing.** `deliver()` wraps each SDK turn in
|
|
11
|
+
* `processingStart` (update) → `invokeSdk()` (concrete) → `processingEnd`
|
|
12
|
+
* (update) → `markDelivered` (signal). Updates are synchronous (§7.1) — a
|
|
13
|
+
* dropped `processingStart` is observable, not silent.
|
|
14
|
+
* - **Split-brain cancellation.** When the base-class phase watcher fires
|
|
15
|
+
* `onLeaseRevoked`, `SdkAttachment` calls the concrete `onSuperseded()`
|
|
16
|
+
* hook. The concrete adapter (Copilot, headless-claude, …) aborts the
|
|
17
|
+
* in-flight `sendAndWait` via its SDK-specific mechanism and exits.
|
|
18
|
+
* Residual ghost-reply window is documented in §9.3.
|
|
19
|
+
*
|
|
20
|
+
* **This file runs in the Node.js adapter process, NOT the Temporal workflow
|
|
21
|
+
* sandbox.** Node.js timers are appropriate here; workflow-bundle code lives
|
|
22
|
+
* elsewhere (in `src/workflows/`).
|
|
23
|
+
*
|
|
24
|
+
* Design reference: docs/design/session-lifecycle-rebuild-v2.md §§4.1, 4.4, 6.1,
|
|
25
|
+
* 6.2, 7.1, 9.3.
|
|
26
|
+
*/
|
|
27
|
+
import type { WorkflowHandle } from '@temporalio/client';
|
|
28
|
+
import { BaseAttachment, type BaseAttachmentOptions } from '../base';
|
|
29
|
+
import type { Message, DetachReason } from '../../types';
|
|
30
|
+
/** Per-message result from `SdkAttachment.deliver()`. */
|
|
31
|
+
export interface SdkDeliverResult {
|
|
32
|
+
/** Whatever `invokeSdk()` returned — up to the concrete adapter to define. */
|
|
33
|
+
sdkResult: unknown;
|
|
34
|
+
/** Time spent inside `invokeSdk()` in milliseconds. */
|
|
35
|
+
elapsedMs: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Abstract base for SDK-class adapters.
|
|
39
|
+
*
|
|
40
|
+
* Owns processing-signal pairing and split-brain cancellation wiring. Concrete
|
|
41
|
+
* subclasses (`CopilotSdkAttachment`, future `HeadlessClaudeAttachment`) provide:
|
|
42
|
+
*
|
|
43
|
+
* - `invokeSdk(prompt, timeoutMs)` — the actual blocking SDK call.
|
|
44
|
+
* - `onSuperseded()` — abort the in-flight SDK call on lease revocation.
|
|
45
|
+
*
|
|
46
|
+
* Subclasses set up the V2 lifecycle by calling `startV2Lifecycle(workflowId)`
|
|
47
|
+
* on `BaseAttachment` (inherited from commit 2) to claim the attachment + start
|
|
48
|
+
* heartbeat + phase watcher. Then they drive a poll loop that calls
|
|
49
|
+
* `this.deliver(msg)` per message; `deliver()` handles the processing-signal
|
|
50
|
+
* pairing and the final `markDelivered` ack.
|
|
51
|
+
*/
|
|
52
|
+
export declare abstract class SdkAttachment extends BaseAttachment {
|
|
53
|
+
/** Subclass hook — cancel the in-flight SDK invocation (AbortController / session.cancel / disconnect). */
|
|
54
|
+
protected abstract onSuperseded(): void;
|
|
55
|
+
/**
|
|
56
|
+
* Whether we are currently inside an `invokeSdk` call. Read by `onSuperseded`
|
|
57
|
+
* implementations to decide whether cancellation actually has an effect.
|
|
58
|
+
*/
|
|
59
|
+
protected sdkInFlight: boolean;
|
|
60
|
+
constructor(options?: BaseAttachmentOptions);
|
|
61
|
+
/**
|
|
62
|
+
* Deliver one message through the SDK turn. Wire-protocol surface:
|
|
63
|
+
*
|
|
64
|
+
* 1. `processingStart` update — synchronous (§7.1). If the update rejects
|
|
65
|
+
* with `AttachmentMismatch` or `WorkflowGone`, we propagate the error
|
|
66
|
+
* without calling `invokeSdk` — lease revocation is already in flight
|
|
67
|
+
* via the phase watcher and the ghost-turn SHOULD be skipped.
|
|
68
|
+
* 2. `invokeSdk(prompt, timeoutMs)` — the concrete blocking call. Runs
|
|
69
|
+
* under `sdkInFlight = true` so `onSuperseded` can identify the target.
|
|
70
|
+
* 3. `processingEnd` update — synchronous, in a `finally` so any throw
|
|
71
|
+
* from `invokeSdk` still releases the in-flight marker on the workflow.
|
|
72
|
+
* Errors here are logged and swallowed: if the workflow is gone or the
|
|
73
|
+
* attachment was revoked, the processing set is meaningless.
|
|
74
|
+
* 4. `markDelivered` signal — fires only on successful `invokeSdk` return,
|
|
75
|
+
* so at-least-once delivery survives crashes mid-turn.
|
|
76
|
+
*
|
|
77
|
+
* @param pinned Pinned `WorkflowHandle` returned by `startV2Lifecycle()`.
|
|
78
|
+
* @param msg Representative message for the in-flight set — its id is
|
|
79
|
+
* used in `processingStart`/`processingEnd`.
|
|
80
|
+
* @param prompt Formatted prompt for the SDK (concrete subclass formats).
|
|
81
|
+
* @param timeoutMs SDK invocation timeout.
|
|
82
|
+
* @param invokeSdk Concrete SDK call. Receives formatted prompt + timeout.
|
|
83
|
+
* @param ackIds Message ids to mark delivered after the SDK turn completes.
|
|
84
|
+
* Defaults to `[msg.id]`. Copilot's bridge joins multiple
|
|
85
|
+
* pending messages into a single prompt and acks them all
|
|
86
|
+
* with one `markDelivered` signal — pass the full batch.
|
|
87
|
+
*/
|
|
88
|
+
protected deliver(pinned: WorkflowHandle, msg: Message, prompt: string, timeoutMs: number, invokeSdk: (prompt: string, timeoutMs: number) => Promise<unknown>, ackIds?: string[]): Promise<SdkDeliverResult>;
|
|
89
|
+
/**
|
|
90
|
+
* Subclass-facing convenience: call this from `startV2Lifecycle` path to
|
|
91
|
+
* fire `adapterExited` on clean shutdown and tear down the V2 machinery.
|
|
92
|
+
* Forwards to `BaseAttachment.stopV2Lifecycle` with graceful=true.
|
|
93
|
+
*/
|
|
94
|
+
protected detachGracefully(reason?: DetachReason): Promise<void>;
|
|
95
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SdkAttachment = void 0;
|
|
4
|
+
const base_1 = require("../base");
|
|
5
|
+
const signals_1 = require("../../workflows/signals");
|
|
6
|
+
const log = (...args) => console.error('[agent-tempo:sdk-adapter]', ...args);
|
|
7
|
+
/**
|
|
8
|
+
* Abstract base for SDK-class adapters.
|
|
9
|
+
*
|
|
10
|
+
* Owns processing-signal pairing and split-brain cancellation wiring. Concrete
|
|
11
|
+
* subclasses (`CopilotSdkAttachment`, future `HeadlessClaudeAttachment`) provide:
|
|
12
|
+
*
|
|
13
|
+
* - `invokeSdk(prompt, timeoutMs)` — the actual blocking SDK call.
|
|
14
|
+
* - `onSuperseded()` — abort the in-flight SDK call on lease revocation.
|
|
15
|
+
*
|
|
16
|
+
* Subclasses set up the V2 lifecycle by calling `startV2Lifecycle(workflowId)`
|
|
17
|
+
* on `BaseAttachment` (inherited from commit 2) to claim the attachment + start
|
|
18
|
+
* heartbeat + phase watcher. Then they drive a poll loop that calls
|
|
19
|
+
* `this.deliver(msg)` per message; `deliver()` handles the processing-signal
|
|
20
|
+
* pairing and the final `markDelivered` ack.
|
|
21
|
+
*/
|
|
22
|
+
class SdkAttachment extends base_1.BaseAttachment {
|
|
23
|
+
/**
|
|
24
|
+
* Whether we are currently inside an `invokeSdk` call. Read by `onSuperseded`
|
|
25
|
+
* implementations to decide whether cancellation actually has an effect.
|
|
26
|
+
*/
|
|
27
|
+
sdkInFlight = false;
|
|
28
|
+
constructor(options = {}) {
|
|
29
|
+
super(options);
|
|
30
|
+
// Wire the V2 lease-revoked signal (fired by BaseAttachment's phase watcher
|
|
31
|
+
// when `attachmentInfo.currentAttachment.attachmentId` diverges from our
|
|
32
|
+
// token) into the concrete subclass's cancel hook. BaseAttachment has
|
|
33
|
+
// already stopped the heartbeat + watcher at this point — our job is to
|
|
34
|
+
// abort the blocking SDK turn before it produces a ghost reply (§9.3).
|
|
35
|
+
this.onLeaseRevoked((reason) => {
|
|
36
|
+
log(`lease revoked (${reason}) — firing onSuperseded`);
|
|
37
|
+
try {
|
|
38
|
+
this.onSuperseded();
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
log('onSuperseded threw:', err?.message ?? err);
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Deliver one message through the SDK turn. Wire-protocol surface:
|
|
47
|
+
*
|
|
48
|
+
* 1. `processingStart` update — synchronous (§7.1). If the update rejects
|
|
49
|
+
* with `AttachmentMismatch` or `WorkflowGone`, we propagate the error
|
|
50
|
+
* without calling `invokeSdk` — lease revocation is already in flight
|
|
51
|
+
* via the phase watcher and the ghost-turn SHOULD be skipped.
|
|
52
|
+
* 2. `invokeSdk(prompt, timeoutMs)` — the concrete blocking call. Runs
|
|
53
|
+
* under `sdkInFlight = true` so `onSuperseded` can identify the target.
|
|
54
|
+
* 3. `processingEnd` update — synchronous, in a `finally` so any throw
|
|
55
|
+
* from `invokeSdk` still releases the in-flight marker on the workflow.
|
|
56
|
+
* Errors here are logged and swallowed: if the workflow is gone or the
|
|
57
|
+
* attachment was revoked, the processing set is meaningless.
|
|
58
|
+
* 4. `markDelivered` signal — fires only on successful `invokeSdk` return,
|
|
59
|
+
* so at-least-once delivery survives crashes mid-turn.
|
|
60
|
+
*
|
|
61
|
+
* @param pinned Pinned `WorkflowHandle` returned by `startV2Lifecycle()`.
|
|
62
|
+
* @param msg Representative message for the in-flight set — its id is
|
|
63
|
+
* used in `processingStart`/`processingEnd`.
|
|
64
|
+
* @param prompt Formatted prompt for the SDK (concrete subclass formats).
|
|
65
|
+
* @param timeoutMs SDK invocation timeout.
|
|
66
|
+
* @param invokeSdk Concrete SDK call. Receives formatted prompt + timeout.
|
|
67
|
+
* @param ackIds Message ids to mark delivered after the SDK turn completes.
|
|
68
|
+
* Defaults to `[msg.id]`. Copilot's bridge joins multiple
|
|
69
|
+
* pending messages into a single prompt and acks them all
|
|
70
|
+
* with one `markDelivered` signal — pass the full batch.
|
|
71
|
+
*/
|
|
72
|
+
async deliver(pinned, msg, prompt, timeoutMs, invokeSdk, ackIds) {
|
|
73
|
+
if (!this.token) {
|
|
74
|
+
throw new Error('SdkAttachment.deliver called with no attachment token — did startV2Lifecycle run?');
|
|
75
|
+
}
|
|
76
|
+
// (1) Announce in-flight work. Synchronous per §7.1 — if the workflow has
|
|
77
|
+
// been destroyed or the lease revoked, the update throws and we bail
|
|
78
|
+
// before burning an SDK turn.
|
|
79
|
+
await pinned.executeUpdate(signals_1.processingStartUpdate, {
|
|
80
|
+
args: [{
|
|
81
|
+
messageId: msg.id,
|
|
82
|
+
expectedAttachmentId: this.token.attachmentId,
|
|
83
|
+
}],
|
|
84
|
+
});
|
|
85
|
+
const t0 = Date.now();
|
|
86
|
+
let sdkResult;
|
|
87
|
+
this.sdkInFlight = true;
|
|
88
|
+
try {
|
|
89
|
+
// (2) Concrete SDK call. Blocks until the LLM turn completes or the
|
|
90
|
+
// concrete adapter aborts via `onSuperseded`.
|
|
91
|
+
sdkResult = await invokeSdk(prompt, timeoutMs);
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
this.sdkInFlight = false;
|
|
95
|
+
// (3) Always release the in-flight marker, even on throw. Swallow errors:
|
|
96
|
+
// if the workflow is gone or the lease was revoked during the turn, the
|
|
97
|
+
// in-flight set is already dead-lettered on the workflow side.
|
|
98
|
+
try {
|
|
99
|
+
await pinned.executeUpdate(signals_1.processingEndUpdate, {
|
|
100
|
+
args: [{
|
|
101
|
+
messageId: msg.id,
|
|
102
|
+
expectedAttachmentId: this.token.attachmentId,
|
|
103
|
+
}],
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
log(`processingEnd suppressed error: ${err?.message ?? err}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const elapsedMs = Date.now() - t0;
|
|
111
|
+
// (4) Ack delivery only after the SDK turn completed cleanly. If invokeSdk
|
|
112
|
+
// threw, we never reach here and messages stay pending for retry.
|
|
113
|
+
// C4 (PR-C dual-QA follow-up): use the typed signal constant so the
|
|
114
|
+
// ts-morph wire-protocol drift detector can see the reference — a string
|
|
115
|
+
// literal would be invisible to the static scan.
|
|
116
|
+
const toAck = ackIds ?? [msg.id];
|
|
117
|
+
try {
|
|
118
|
+
await pinned.signal(signals_1.markDeliveredSignal, toAck);
|
|
119
|
+
}
|
|
120
|
+
catch (err) {
|
|
121
|
+
log(`markDelivered suppressed error: ${err?.message ?? err}`);
|
|
122
|
+
}
|
|
123
|
+
return { sdkResult, elapsedMs };
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Subclass-facing convenience: call this from `startV2Lifecycle` path to
|
|
127
|
+
* fire `adapterExited` on clean shutdown and tear down the V2 machinery.
|
|
128
|
+
* Forwards to `BaseAttachment.stopV2Lifecycle` with graceful=true.
|
|
129
|
+
*/
|
|
130
|
+
async detachGracefully(reason = 'user-stop') {
|
|
131
|
+
await this.stopV2Lifecycle(reason, /* graceful */ true);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.SdkAttachment = SdkAttachment;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared SDK-class adapter system-prompt helpers (#536).
|
|
3
|
+
*
|
|
4
|
+
* Two SDK-class adapters in this repo currently mirror an *identical*
|
|
5
|
+
* "use your MCP tools to reply" framing onto the model — copilot
|
|
6
|
+
* (`src/adapters/copilot/adapter.ts:283-297`) and, post-#536,
|
|
7
|
+
* claude-code-headless (`src/adapters/claude-code-headless/adapter.ts`).
|
|
8
|
+
* Pre-#536 the framing only existed on copilot's side, hand-typed
|
|
9
|
+
* inline; this module factors it out so:
|
|
10
|
+
*
|
|
11
|
+
* - There is one canonical source for the prompt content (no copy
|
|
12
|
+
* drift when someone tweaks the wording in one place and forgets
|
|
13
|
+
* the other).
|
|
14
|
+
* - The MAESTRO_ACK augmentation that copilot's poll loop applies
|
|
15
|
+
* to human-from-dashboard messages is identifiable by name from
|
|
16
|
+
* either adapter's prompt-build site.
|
|
17
|
+
*
|
|
18
|
+
* **Why not `buildServerInstructions` from `src/server-tools.ts`?**
|
|
19
|
+
* The other two SDK-class adapters (claude-api, opencode) DO use
|
|
20
|
+
* `buildServerInstructions` for their per-turn system prompt. Copilot
|
|
21
|
+
* predates that helper and ships its own inline framing with a more
|
|
22
|
+
* explicit "tools available" enumeration. Issue #536 directs
|
|
23
|
+
* claude-code-headless to mirror **copilot's** content (so the two
|
|
24
|
+
* adapters speak the same dialect to the model), not the canonical
|
|
25
|
+
* helper. A future consolidation pass could migrate ALL four SDK
|
|
26
|
+
* adapters onto `buildServerInstructions` — out of scope here.
|
|
27
|
+
*/
|
|
28
|
+
/**
|
|
29
|
+
* SDK-class adapter system-prompt template, parameterized by ensemble.
|
|
30
|
+
*
|
|
31
|
+
* Lifted verbatim from `src/adapters/copilot/adapter.ts:283-297` (the
|
|
32
|
+
* pre-#536 inline `systemMessage.content`). Both copilot and
|
|
33
|
+
* claude-code-headless feed this into their per-turn invocation:
|
|
34
|
+
* - copilot via `sessionConfig.systemMessage` to the SDK's
|
|
35
|
+
* `createSession` call.
|
|
36
|
+
* - claude-code-headless via `--append-system-prompt <content>` on
|
|
37
|
+
* the per-turn `claude -p` argv.
|
|
38
|
+
*
|
|
39
|
+
* Returning a function (rather than a constant) preserves the
|
|
40
|
+
* `${ensemble}` interpolation hook — different ensembles see different
|
|
41
|
+
* names without templating in the call site.
|
|
42
|
+
*
|
|
43
|
+
* @param opts.ensemble Ensemble name shown to the model in the first
|
|
44
|
+
* line ("You are part of the …"). Pass `config.ensemble`.
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildSdkSystemPrompt(opts: {
|
|
47
|
+
ensemble: string;
|
|
48
|
+
}): string;
|
|
49
|
+
/**
|
|
50
|
+
* Per-message augmentation appended to messages whose `isMaestro`
|
|
51
|
+
* field is `true`. The maestro flag identifies messages originating
|
|
52
|
+
* from a human operator at the dashboard (vs. ensemble-internal
|
|
53
|
+
* cues from other player sessions).
|
|
54
|
+
*
|
|
55
|
+
* Lifted verbatim from `src/adapters/copilot/adapter.ts:462`. Both
|
|
56
|
+
* copilot's poll-loop prompt-build and claude-code-headless's
|
|
57
|
+
* per-turn `buildPromptText` apply this conditionally per
|
|
58
|
+
* `m.isMaestro` — a human-from-dashboard message gets the ack
|
|
59
|
+
* directive; an ensemble-internal cue does not.
|
|
60
|
+
*
|
|
61
|
+
* The leading `\n\n` separates the directive from the human's
|
|
62
|
+
* message text inside the same prompt frame.
|
|
63
|
+
*/
|
|
64
|
+
export declare const MAESTRO_ACK = "\n\n[IMPORTANT: This message is from a human (Maestro). Immediately cue the sender back with a brief acknowledgment and your planned next step before doing the work.]";
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared SDK-class adapter system-prompt helpers (#536).
|
|
4
|
+
*
|
|
5
|
+
* Two SDK-class adapters in this repo currently mirror an *identical*
|
|
6
|
+
* "use your MCP tools to reply" framing onto the model — copilot
|
|
7
|
+
* (`src/adapters/copilot/adapter.ts:283-297`) and, post-#536,
|
|
8
|
+
* claude-code-headless (`src/adapters/claude-code-headless/adapter.ts`).
|
|
9
|
+
* Pre-#536 the framing only existed on copilot's side, hand-typed
|
|
10
|
+
* inline; this module factors it out so:
|
|
11
|
+
*
|
|
12
|
+
* - There is one canonical source for the prompt content (no copy
|
|
13
|
+
* drift when someone tweaks the wording in one place and forgets
|
|
14
|
+
* the other).
|
|
15
|
+
* - The MAESTRO_ACK augmentation that copilot's poll loop applies
|
|
16
|
+
* to human-from-dashboard messages is identifiable by name from
|
|
17
|
+
* either adapter's prompt-build site.
|
|
18
|
+
*
|
|
19
|
+
* **Why not `buildServerInstructions` from `src/server-tools.ts`?**
|
|
20
|
+
* The other two SDK-class adapters (claude-api, opencode) DO use
|
|
21
|
+
* `buildServerInstructions` for their per-turn system prompt. Copilot
|
|
22
|
+
* predates that helper and ships its own inline framing with a more
|
|
23
|
+
* explicit "tools available" enumeration. Issue #536 directs
|
|
24
|
+
* claude-code-headless to mirror **copilot's** content (so the two
|
|
25
|
+
* adapters speak the same dialect to the model), not the canonical
|
|
26
|
+
* helper. A future consolidation pass could migrate ALL four SDK
|
|
27
|
+
* adapters onto `buildServerInstructions` — out of scope here.
|
|
28
|
+
*/
|
|
29
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
30
|
+
exports.MAESTRO_ACK = void 0;
|
|
31
|
+
exports.buildSdkSystemPrompt = buildSdkSystemPrompt;
|
|
32
|
+
/**
|
|
33
|
+
* SDK-class adapter system-prompt template, parameterized by ensemble.
|
|
34
|
+
*
|
|
35
|
+
* Lifted verbatim from `src/adapters/copilot/adapter.ts:283-297` (the
|
|
36
|
+
* pre-#536 inline `systemMessage.content`). Both copilot and
|
|
37
|
+
* claude-code-headless feed this into their per-turn invocation:
|
|
38
|
+
* - copilot via `sessionConfig.systemMessage` to the SDK's
|
|
39
|
+
* `createSession` call.
|
|
40
|
+
* - claude-code-headless via `--append-system-prompt <content>` on
|
|
41
|
+
* the per-turn `claude -p` argv.
|
|
42
|
+
*
|
|
43
|
+
* Returning a function (rather than a constant) preserves the
|
|
44
|
+
* `${ensemble}` interpolation hook — different ensembles see different
|
|
45
|
+
* names without templating in the call site.
|
|
46
|
+
*
|
|
47
|
+
* @param opts.ensemble Ensemble name shown to the model in the first
|
|
48
|
+
* line ("You are part of the …"). Pass `config.ensemble`.
|
|
49
|
+
*/
|
|
50
|
+
function buildSdkSystemPrompt(opts) {
|
|
51
|
+
return (`You are part of the "${opts.ensemble}" ensemble coordinated via Temporal. ` +
|
|
52
|
+
`You have MCP tools available — ALWAYS use these tools directly, NEVER try to run them as shell commands:\n` +
|
|
53
|
+
`- set_name: Set your player name (call this FIRST if instructed)\n` +
|
|
54
|
+
`- ensemble: List active sessions\n` +
|
|
55
|
+
`- cue: Send a message to another player\n` +
|
|
56
|
+
`- set_part: Update your status/description\n` +
|
|
57
|
+
`- listen: Check for pending messages\n` +
|
|
58
|
+
`- recruit: Spawn a new player session\n` +
|
|
59
|
+
`- report: Report to the conductor\n` +
|
|
60
|
+
`- stop: Stop a session\n\n` +
|
|
61
|
+
`When you receive a message from another session, treat it like a coworker asking for help — respond promptly using your MCP tools.`);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Per-message augmentation appended to messages whose `isMaestro`
|
|
65
|
+
* field is `true`. The maestro flag identifies messages originating
|
|
66
|
+
* from a human operator at the dashboard (vs. ensemble-internal
|
|
67
|
+
* cues from other player sessions).
|
|
68
|
+
*
|
|
69
|
+
* Lifted verbatim from `src/adapters/copilot/adapter.ts:462`. Both
|
|
70
|
+
* copilot's poll-loop prompt-build and claude-code-headless's
|
|
71
|
+
* per-turn `buildPromptText` apply this conditionally per
|
|
72
|
+
* `m.isMaestro` — a human-from-dashboard message gets the ack
|
|
73
|
+
* directive; an ensemble-internal cue does not.
|
|
74
|
+
*
|
|
75
|
+
* The leading `\n\n` separates the directive from the human's
|
|
76
|
+
* message text inside the same prompt frame.
|
|
77
|
+
*/
|
|
78
|
+
exports.MAESTRO_ACK = '\n\n[IMPORTANT: This message is from a human (Maestro). Immediately cue the sender back with a brief acknowledgment and your planned next step before doing the work.]';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared terminal-class error classifier for adapter code (#249 Bug 4).
|
|
3
|
+
*
|
|
4
|
+
* The Temporal TS SDK conflates two terminal sub-kinds on pinned-runId
|
|
5
|
+
* signal/query failures:
|
|
6
|
+
* (a) the closed run's specific runId no longer accepting traffic (CAN,
|
|
7
|
+
* true COMPLETE, TERMINATED, FAILED), and
|
|
8
|
+
* (b) the workflow id having been fully GC'd.
|
|
9
|
+
* Both surface as `WorkflowNotFoundError` with message
|
|
10
|
+
* "workflow execution already completed". This classifier says "yes, this is a
|
|
11
|
+
* terminal-class error" vs "transient, keep retrying" — it does NOT distinguish
|
|
12
|
+
* the sub-kinds. Callers that need sub-kind resolution consult
|
|
13
|
+
* `fetchHistory` (see {@link BaseAttachment.handleRunEndError}).
|
|
14
|
+
*
|
|
15
|
+
* **Extracted from `BaseAttachment.isTerminalErr` to break a code-duplication
|
|
16
|
+
* risk** — both the heartbeat/watcher ticks (in `base.ts`) and the delivery
|
|
17
|
+
* poller (in `claude-code/adapter.ts`) need to classify the same errors, and
|
|
18
|
+
* divergence between the two would re-create the #249 Bug 4 regression surface.
|
|
19
|
+
* One implementation, one import point.
|
|
20
|
+
*
|
|
21
|
+
* Uses name/message-sniffing rather than `instanceof` to tolerate the slightly
|
|
22
|
+
* different shapes errors take between `@temporalio/client` and the raw gRPC
|
|
23
|
+
* layer. The tradeoff is a narrow window where gRPC could add a new phrasing
|
|
24
|
+
* for the same error class — but that's caught by the existing adapter
|
|
25
|
+
* reconnect integration tests.
|
|
26
|
+
*/
|
|
27
|
+
export declare function isTerminalWorkflowError(err: unknown): boolean;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isTerminalWorkflowError = isTerminalWorkflowError;
|
|
4
|
+
/**
|
|
5
|
+
* Shared terminal-class error classifier for adapter code (#249 Bug 4).
|
|
6
|
+
*
|
|
7
|
+
* The Temporal TS SDK conflates two terminal sub-kinds on pinned-runId
|
|
8
|
+
* signal/query failures:
|
|
9
|
+
* (a) the closed run's specific runId no longer accepting traffic (CAN,
|
|
10
|
+
* true COMPLETE, TERMINATED, FAILED), and
|
|
11
|
+
* (b) the workflow id having been fully GC'd.
|
|
12
|
+
* Both surface as `WorkflowNotFoundError` with message
|
|
13
|
+
* "workflow execution already completed". This classifier says "yes, this is a
|
|
14
|
+
* terminal-class error" vs "transient, keep retrying" — it does NOT distinguish
|
|
15
|
+
* the sub-kinds. Callers that need sub-kind resolution consult
|
|
16
|
+
* `fetchHistory` (see {@link BaseAttachment.handleRunEndError}).
|
|
17
|
+
*
|
|
18
|
+
* **Extracted from `BaseAttachment.isTerminalErr` to break a code-duplication
|
|
19
|
+
* risk** — both the heartbeat/watcher ticks (in `base.ts`) and the delivery
|
|
20
|
+
* poller (in `claude-code/adapter.ts`) need to classify the same errors, and
|
|
21
|
+
* divergence between the two would re-create the #249 Bug 4 regression surface.
|
|
22
|
+
* One implementation, one import point.
|
|
23
|
+
*
|
|
24
|
+
* Uses name/message-sniffing rather than `instanceof` to tolerate the slightly
|
|
25
|
+
* different shapes errors take between `@temporalio/client` and the raw gRPC
|
|
26
|
+
* layer. The tradeoff is a narrow window where gRPC could add a new phrasing
|
|
27
|
+
* for the same error class — but that's caught by the existing adapter
|
|
28
|
+
* reconnect integration tests.
|
|
29
|
+
*/
|
|
30
|
+
function isTerminalWorkflowError(err) {
|
|
31
|
+
const e = err;
|
|
32
|
+
const name = e?.name ?? '';
|
|
33
|
+
const msg = e?.message ?? '';
|
|
34
|
+
return (name.includes('WorkflowNotFound') ||
|
|
35
|
+
name.includes('WorkflowExecutionAlreadyCompleted') ||
|
|
36
|
+
msg.includes('WorkflowGone') ||
|
|
37
|
+
msg.includes('NOT_FOUND') ||
|
|
38
|
+
msg.includes('workflow execution already completed'));
|
|
39
|
+
}
|