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,67 @@
|
|
|
1
|
+
import { type PersistedConfig } from '../config';
|
|
2
|
+
/**
|
|
3
|
+
* Is the bind address effectively loopback? `0.0.0.0` is NOT loopback
|
|
4
|
+
* (it binds every interface, including external ones).
|
|
5
|
+
*/
|
|
6
|
+
export declare function isLoopbackBindAddr(bindAddr: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Parse an `Origin` header to a hostname. Returns `null` when the header
|
|
9
|
+
* is absent, empty, or unparseable as a URL — caller decides the policy.
|
|
10
|
+
*/
|
|
11
|
+
export declare function originHost(originHeader: string | undefined): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Decide whether bearer mode applies to this request, given the daemon's
|
|
14
|
+
* bind addr and the request's `Origin` header.
|
|
15
|
+
*
|
|
16
|
+
* - bind addr non-loopback → always bearer (`true`)
|
|
17
|
+
* - no Origin header on loopback bind → loopback mode (`false`)
|
|
18
|
+
* - Origin host is loopback on loopback bind → loopback mode (`false`)
|
|
19
|
+
* - Origin host is non-loopback OR unparseable on loopback bind → bearer (`true`)
|
|
20
|
+
*/
|
|
21
|
+
export declare function bearerRequired(bindAddr: string, originHeader: string | undefined): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Extract the Bearer token from an `Authorization` header. Returns `null`
|
|
24
|
+
* when the header is missing or doesn't start with the `Bearer ` prefix
|
|
25
|
+
* (case-sensitive per RFC 6750 §2.1). Whitespace inside the token is
|
|
26
|
+
* preserved — comparison is constant-time exact match.
|
|
27
|
+
*/
|
|
28
|
+
export declare function extractBearerToken(authHeader: string | undefined): string | null;
|
|
29
|
+
/**
|
|
30
|
+
* Constant-time token comparison.
|
|
31
|
+
*
|
|
32
|
+
* **Length-leak tradeoff** (PR-1 review followup): the leading
|
|
33
|
+
* length-mismatch short-circuit reveals the expected token length to a
|
|
34
|
+
* timing observer who can measure the difference between "rejected
|
|
35
|
+
* before constant-time compare" and "ran the full constant-time
|
|
36
|
+
* compare". Mitigations considered:
|
|
37
|
+
*
|
|
38
|
+
* 1. Pad the received token to a fixed length before comparison.
|
|
39
|
+
* Adds branching in the pad path that itself can leak via timing.
|
|
40
|
+
* 2. Use HMAC-then-compare to render length irrelevant at the cost of
|
|
41
|
+
* an extra hash per request.
|
|
42
|
+
*
|
|
43
|
+
* Neither is worth it for a token whose length is fixed by our own
|
|
44
|
+
* generator (`crypto.randomBytes(32).toString('base64url')` is always
|
|
45
|
+
* 43 chars). An attacker observing length learns nothing they can't
|
|
46
|
+
* trivially guess from inspecting the daemon's source. Without the
|
|
47
|
+
* length gate `crypto.timingSafeEqual` throws on mismatched lengths,
|
|
48
|
+
* which would force a try/catch in the hot path with worse timing
|
|
49
|
+
* properties. Document the assumption here so a future contributor
|
|
50
|
+
* reading "constant-time" doesn't assume length is also blinded.
|
|
51
|
+
*/
|
|
52
|
+
export declare function tokensMatch(received: string, expected: string): boolean;
|
|
53
|
+
/**
|
|
54
|
+
* Load (or auto-generate) the daemon's HTTP bearer token.
|
|
55
|
+
*
|
|
56
|
+
* - When `bearerRequired` is true and the persisted config has no
|
|
57
|
+
* `httpToken`, generate one (`crypto.randomBytes(32).toString('base64url')`)
|
|
58
|
+
* and persist it via `saveConfigFile` (which sets 0600 on POSIX).
|
|
59
|
+
* - When `bearerRequired` is false, return whatever is in the config
|
|
60
|
+
* without generating — operators may still want a token saved for
|
|
61
|
+
* future use, and we shouldn't write secrets the user didn't request.
|
|
62
|
+
*/
|
|
63
|
+
export declare function loadOrGenerateHttpToken(opts: {
|
|
64
|
+
bearerRequired: boolean;
|
|
65
|
+
load?: () => PersistedConfig;
|
|
66
|
+
save?: (cfg: PersistedConfig) => void;
|
|
67
|
+
}): string | null;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isLoopbackBindAddr = isLoopbackBindAddr;
|
|
37
|
+
exports.originHost = originHost;
|
|
38
|
+
exports.bearerRequired = bearerRequired;
|
|
39
|
+
exports.extractBearerToken = extractBearerToken;
|
|
40
|
+
exports.tokensMatch = tokensMatch;
|
|
41
|
+
exports.loadOrGenerateHttpToken = loadOrGenerateHttpToken;
|
|
42
|
+
/**
|
|
43
|
+
* Authentication for the daemon HTTP surface (SSE-PROTOCOL.md §3).
|
|
44
|
+
*
|
|
45
|
+
* **Two modes**:
|
|
46
|
+
*
|
|
47
|
+
* - **Loopback** (default, no auth) — bind addr is loopback AND the request
|
|
48
|
+
* has no `Origin` header (curl, supervisord) OR `Origin` resolves to a
|
|
49
|
+
* loopback host. Single-user dev workflows hit this path.
|
|
50
|
+
*
|
|
51
|
+
* - **Bearer** — required when bind addr is non-loopback (`0.0.0.0`) OR
|
|
52
|
+
* when the request's `Origin` is non-loopback. Defends against DNS
|
|
53
|
+
* rebinding even on a loopback-bound daemon: a malicious page on the
|
|
54
|
+
* user's machine resolving `evil.com` to `127.0.0.1` cannot read the
|
|
55
|
+
* daemon without the bearer token.
|
|
56
|
+
*
|
|
57
|
+
* `/v1/health` is **never authenticated** — it's the liveness probe used
|
|
58
|
+
* by reverse proxies, supervisord, and the TUI bootstrap state machine.
|
|
59
|
+
*
|
|
60
|
+
* **Token storage** (§3.1) — `~/.agent-tempo/config.json` field
|
|
61
|
+
* `httpToken`. Auto-generated on first daemon boot when bearer mode is
|
|
62
|
+
* required and no token is set: `crypto.randomBytes(32).toString('base64url')`,
|
|
63
|
+
* 0600 on POSIX. Rotation = delete the field; next daemon boot regenerates.
|
|
64
|
+
*/
|
|
65
|
+
const crypto = __importStar(require("crypto"));
|
|
66
|
+
const config_1 = require("../config");
|
|
67
|
+
/** Hostnames that count as loopback for §3 mode determination. */
|
|
68
|
+
const LOOPBACK_HOSTS = new Set(['127.0.0.1', '::1', '[::1]', 'localhost']);
|
|
69
|
+
/**
|
|
70
|
+
* Is the bind address effectively loopback? `0.0.0.0` is NOT loopback
|
|
71
|
+
* (it binds every interface, including external ones).
|
|
72
|
+
*/
|
|
73
|
+
function isLoopbackBindAddr(bindAddr) {
|
|
74
|
+
return LOOPBACK_HOSTS.has(bindAddr);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Parse an `Origin` header to a hostname. Returns `null` when the header
|
|
78
|
+
* is absent, empty, or unparseable as a URL — caller decides the policy.
|
|
79
|
+
*/
|
|
80
|
+
function originHost(originHeader) {
|
|
81
|
+
if (!originHeader)
|
|
82
|
+
return null;
|
|
83
|
+
try {
|
|
84
|
+
const url = new URL(originHeader);
|
|
85
|
+
return url.hostname;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Decide whether bearer mode applies to this request, given the daemon's
|
|
93
|
+
* bind addr and the request's `Origin` header.
|
|
94
|
+
*
|
|
95
|
+
* - bind addr non-loopback → always bearer (`true`)
|
|
96
|
+
* - no Origin header on loopback bind → loopback mode (`false`)
|
|
97
|
+
* - Origin host is loopback on loopback bind → loopback mode (`false`)
|
|
98
|
+
* - Origin host is non-loopback OR unparseable on loopback bind → bearer (`true`)
|
|
99
|
+
*/
|
|
100
|
+
function bearerRequired(bindAddr, originHeader) {
|
|
101
|
+
if (!isLoopbackBindAddr(bindAddr))
|
|
102
|
+
return true;
|
|
103
|
+
if (!originHeader)
|
|
104
|
+
return false;
|
|
105
|
+
const host = originHost(originHeader);
|
|
106
|
+
if (host == null)
|
|
107
|
+
return true; // unparseable Origin → fail safe
|
|
108
|
+
return !LOOPBACK_HOSTS.has(host);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Extract the Bearer token from an `Authorization` header. Returns `null`
|
|
112
|
+
* when the header is missing or doesn't start with the `Bearer ` prefix
|
|
113
|
+
* (case-sensitive per RFC 6750 §2.1). Whitespace inside the token is
|
|
114
|
+
* preserved — comparison is constant-time exact match.
|
|
115
|
+
*/
|
|
116
|
+
function extractBearerToken(authHeader) {
|
|
117
|
+
if (!authHeader)
|
|
118
|
+
return null;
|
|
119
|
+
const prefix = 'Bearer ';
|
|
120
|
+
if (!authHeader.startsWith(prefix))
|
|
121
|
+
return null;
|
|
122
|
+
return authHeader.slice(prefix.length);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Constant-time token comparison.
|
|
126
|
+
*
|
|
127
|
+
* **Length-leak tradeoff** (PR-1 review followup): the leading
|
|
128
|
+
* length-mismatch short-circuit reveals the expected token length to a
|
|
129
|
+
* timing observer who can measure the difference between "rejected
|
|
130
|
+
* before constant-time compare" and "ran the full constant-time
|
|
131
|
+
* compare". Mitigations considered:
|
|
132
|
+
*
|
|
133
|
+
* 1. Pad the received token to a fixed length before comparison.
|
|
134
|
+
* Adds branching in the pad path that itself can leak via timing.
|
|
135
|
+
* 2. Use HMAC-then-compare to render length irrelevant at the cost of
|
|
136
|
+
* an extra hash per request.
|
|
137
|
+
*
|
|
138
|
+
* Neither is worth it for a token whose length is fixed by our own
|
|
139
|
+
* generator (`crypto.randomBytes(32).toString('base64url')` is always
|
|
140
|
+
* 43 chars). An attacker observing length learns nothing they can't
|
|
141
|
+
* trivially guess from inspecting the daemon's source. Without the
|
|
142
|
+
* length gate `crypto.timingSafeEqual` throws on mismatched lengths,
|
|
143
|
+
* which would force a try/catch in the hot path with worse timing
|
|
144
|
+
* properties. Document the assumption here so a future contributor
|
|
145
|
+
* reading "constant-time" doesn't assume length is also blinded.
|
|
146
|
+
*/
|
|
147
|
+
function tokensMatch(received, expected) {
|
|
148
|
+
if (received.length !== expected.length)
|
|
149
|
+
return false;
|
|
150
|
+
const a = Buffer.from(received, 'utf8');
|
|
151
|
+
const b = Buffer.from(expected, 'utf8');
|
|
152
|
+
return crypto.timingSafeEqual(a, b);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Load (or auto-generate) the daemon's HTTP bearer token.
|
|
156
|
+
*
|
|
157
|
+
* - When `bearerRequired` is true and the persisted config has no
|
|
158
|
+
* `httpToken`, generate one (`crypto.randomBytes(32).toString('base64url')`)
|
|
159
|
+
* and persist it via `saveConfigFile` (which sets 0600 on POSIX).
|
|
160
|
+
* - When `bearerRequired` is false, return whatever is in the config
|
|
161
|
+
* without generating — operators may still want a token saved for
|
|
162
|
+
* future use, and we shouldn't write secrets the user didn't request.
|
|
163
|
+
*/
|
|
164
|
+
function loadOrGenerateHttpToken(opts) {
|
|
165
|
+
const load = opts.load ?? config_1.loadConfigFile;
|
|
166
|
+
const save = opts.save ?? config_1.saveConfigFile;
|
|
167
|
+
const cfg = load();
|
|
168
|
+
if (cfg.httpToken && typeof cfg.httpToken === 'string' && cfg.httpToken.length > 0) {
|
|
169
|
+
return cfg.httpToken;
|
|
170
|
+
}
|
|
171
|
+
if (!opts.bearerRequired)
|
|
172
|
+
return null;
|
|
173
|
+
// Auto-generate. base64url chars are safe inside Authorization values.
|
|
174
|
+
const token = crypto.randomBytes(32).toString('base64url');
|
|
175
|
+
save({ ...cfg, httpToken: token });
|
|
176
|
+
return token;
|
|
177
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared HTTP body-reading helpers.
|
|
3
|
+
*
|
|
4
|
+
* Extracted from `writes.ts` so catalog/write/dashboard handlers all
|
|
5
|
+
* use the same JSON parser + size cap. The cap is enforced before
|
|
6
|
+
* parsing so a 1 GiB upload can't OOM the daemon.
|
|
7
|
+
*
|
|
8
|
+
* Sentinels (rather than thrown errors) keep the parse path branch-free
|
|
9
|
+
* — handlers compare against `BODY_TOO_LARGE` / `BODY_INVALID_JSON` and
|
|
10
|
+
* map to the appropriate 4xx response.
|
|
11
|
+
*/
|
|
12
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
13
|
+
import { type AgentType } from '../types';
|
|
14
|
+
/** Hard cap on incoming JSON body size (1 MiB). */
|
|
15
|
+
export declare const WRITE_BODY_MAX: number;
|
|
16
|
+
export declare const BODY_TOO_LARGE: unique symbol;
|
|
17
|
+
export declare const BODY_INVALID_JSON: unique symbol;
|
|
18
|
+
export type ReadJsonBodyResult = Record<string, unknown> | typeof BODY_TOO_LARGE | typeof BODY_INVALID_JSON;
|
|
19
|
+
/**
|
|
20
|
+
* Read the request body up to {@link WRITE_BODY_MAX} bytes and parse
|
|
21
|
+
* as JSON. Returns the parsed object, an empty object for empty
|
|
22
|
+
* bodies, or one of the sentinel symbols for cap / parse failures.
|
|
23
|
+
*
|
|
24
|
+
* Note on the cap path: returning early from this function ends body
|
|
25
|
+
* consumption; Node's HTTP server tears down the upload when the
|
|
26
|
+
* handler ends. Explicit `req.destroy()` would race the response
|
|
27
|
+
* write — left alone.
|
|
28
|
+
*/
|
|
29
|
+
export declare function readJsonBody(req: IncomingMessage): Promise<ReadJsonBodyResult>;
|
|
30
|
+
/**
|
|
31
|
+
* Pluck a string field from a parsed JSON body. Returns `undefined`
|
|
32
|
+
* for absent or non-string values; with `requireNonEmpty: true`, also
|
|
33
|
+
* filters empty strings (used by routes that accept optional fields
|
|
34
|
+
* — empty strings shouldn't propagate to downstream Temporal calls
|
|
35
|
+
* as if the user typed something).
|
|
36
|
+
*/
|
|
37
|
+
export declare function stringField(body: Record<string, unknown>, key: string, opts?: {
|
|
38
|
+
requireNonEmpty?: boolean;
|
|
39
|
+
}): string | undefined;
|
|
40
|
+
/**
|
|
41
|
+
* Agent allowlists, derived from {@link AGENT_TYPES} (the SSOT in
|
|
42
|
+
* `src/types.ts`).
|
|
43
|
+
*
|
|
44
|
+
* `'mock'` is dev-mode-only — see ADR 0014 §7. Read at request time so
|
|
45
|
+
* toggling `AGENT_TEMPO_DEV_MODE` between requests is picked up without
|
|
46
|
+
* restart (parity with `src/tools/recruit.ts`).
|
|
47
|
+
*
|
|
48
|
+
* Deriving from `AGENT_TYPES` rather than hardcoding the list closes the
|
|
49
|
+
* #541 drift bug: every new adapter (`claude-api`, `opencode`,
|
|
50
|
+
* `claude-code-headless`, …) added to the SSOT is automatically accepted
|
|
51
|
+
* by the HTTP recruit endpoint, instead of being silently rejected by an
|
|
52
|
+
* allowlist that someone forgot to update.
|
|
53
|
+
*/
|
|
54
|
+
export declare const ALLOWED_AGENTS_DEV: readonly AgentType[];
|
|
55
|
+
export declare const ALLOWED_AGENTS_PROD: readonly AgentType[];
|
|
56
|
+
export declare function allowedAgentsForCurrentMode(): readonly AgentType[];
|
|
57
|
+
export declare function isAllowedAgent(s: string, allowed: readonly AgentType[]): s is AgentType;
|
|
58
|
+
/**
|
|
59
|
+
* Pluck a required `playerId` from a parsed body, validating shape.
|
|
60
|
+
*
|
|
61
|
+
* Returns the `playerId` string on success. On any failure (missing or
|
|
62
|
+
* malformed) writes the appropriate 400 response via `errorResponse` and
|
|
63
|
+
* returns `undefined`. **Callers MUST check the return value and bail
|
|
64
|
+
* out** — a missing `if (!playerId) return;` would silently skip the
|
|
65
|
+
* downstream client call and double-send to the response stream.
|
|
66
|
+
*
|
|
67
|
+
* Shared by every per-player route under `/v1/ensembles/:ensemble/<action>`
|
|
68
|
+
* (restart / destroy / detach / recall — `release` keeps an inline check
|
|
69
|
+
* because its `playerId` field is optional, not required).
|
|
70
|
+
*/
|
|
71
|
+
export declare function requirePlayerId(res: ServerResponse, body: Record<string, unknown>): string | undefined;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ALLOWED_AGENTS_PROD = exports.ALLOWED_AGENTS_DEV = exports.BODY_INVALID_JSON = exports.BODY_TOO_LARGE = exports.WRITE_BODY_MAX = void 0;
|
|
4
|
+
exports.readJsonBody = readJsonBody;
|
|
5
|
+
exports.stringField = stringField;
|
|
6
|
+
exports.allowedAgentsForCurrentMode = allowedAgentsForCurrentMode;
|
|
7
|
+
exports.isAllowedAgent = isAllowedAgent;
|
|
8
|
+
exports.requirePlayerId = requirePlayerId;
|
|
9
|
+
const types_1 = require("../types");
|
|
10
|
+
const config_1 = require("../config");
|
|
11
|
+
const responses_1 = require("./responses");
|
|
12
|
+
const validation_1 = require("../utils/validation");
|
|
13
|
+
/** Hard cap on incoming JSON body size (1 MiB). */
|
|
14
|
+
exports.WRITE_BODY_MAX = 1024 * 1024;
|
|
15
|
+
exports.BODY_TOO_LARGE = Symbol('body-too-large');
|
|
16
|
+
exports.BODY_INVALID_JSON = Symbol('body-invalid-json');
|
|
17
|
+
/**
|
|
18
|
+
* Read the request body up to {@link WRITE_BODY_MAX} bytes and parse
|
|
19
|
+
* as JSON. Returns the parsed object, an empty object for empty
|
|
20
|
+
* bodies, or one of the sentinel symbols for cap / parse failures.
|
|
21
|
+
*
|
|
22
|
+
* Note on the cap path: returning early from this function ends body
|
|
23
|
+
* consumption; Node's HTTP server tears down the upload when the
|
|
24
|
+
* handler ends. Explicit `req.destroy()` would race the response
|
|
25
|
+
* write — left alone.
|
|
26
|
+
*/
|
|
27
|
+
async function readJsonBody(req) {
|
|
28
|
+
const chunks = [];
|
|
29
|
+
let total = 0;
|
|
30
|
+
for await (const chunk of req) {
|
|
31
|
+
const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
32
|
+
total += buf.length;
|
|
33
|
+
if (total > exports.WRITE_BODY_MAX)
|
|
34
|
+
return exports.BODY_TOO_LARGE;
|
|
35
|
+
chunks.push(buf);
|
|
36
|
+
}
|
|
37
|
+
if (total === 0)
|
|
38
|
+
return {};
|
|
39
|
+
try {
|
|
40
|
+
const parsed = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
41
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
42
|
+
return exports.BODY_INVALID_JSON;
|
|
43
|
+
}
|
|
44
|
+
return parsed;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return exports.BODY_INVALID_JSON;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Pluck a string field from a parsed JSON body. Returns `undefined`
|
|
52
|
+
* for absent or non-string values; with `requireNonEmpty: true`, also
|
|
53
|
+
* filters empty strings (used by routes that accept optional fields
|
|
54
|
+
* — empty strings shouldn't propagate to downstream Temporal calls
|
|
55
|
+
* as if the user typed something).
|
|
56
|
+
*/
|
|
57
|
+
function stringField(body, key, opts = {}) {
|
|
58
|
+
const v = body[key];
|
|
59
|
+
if (typeof v !== 'string')
|
|
60
|
+
return undefined;
|
|
61
|
+
if (opts.requireNonEmpty && v.length === 0)
|
|
62
|
+
return undefined;
|
|
63
|
+
return v;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Dev-mode-only agent identifiers — must never appear in {@link ALLOWED_AGENTS_PROD}.
|
|
67
|
+
*
|
|
68
|
+
* Currently just `'mock'` (ADR 0014 §7). Listed explicitly so the prod
|
|
69
|
+
* allowlist below is "everything in {@link AGENT_TYPES} minus this set",
|
|
70
|
+
* which keeps the dev-only gate auditable and the derived prod list
|
|
71
|
+
* automatically picks up new adapters as they land in `AGENT_TYPES`
|
|
72
|
+
* (#541 — the drift bug this constant prevents).
|
|
73
|
+
*/
|
|
74
|
+
const DEV_ONLY_AGENTS = new Set(['mock']);
|
|
75
|
+
/**
|
|
76
|
+
* Agent allowlists, derived from {@link AGENT_TYPES} (the SSOT in
|
|
77
|
+
* `src/types.ts`).
|
|
78
|
+
*
|
|
79
|
+
* `'mock'` is dev-mode-only — see ADR 0014 §7. Read at request time so
|
|
80
|
+
* toggling `AGENT_TEMPO_DEV_MODE` between requests is picked up without
|
|
81
|
+
* restart (parity with `src/tools/recruit.ts`).
|
|
82
|
+
*
|
|
83
|
+
* Deriving from `AGENT_TYPES` rather than hardcoding the list closes the
|
|
84
|
+
* #541 drift bug: every new adapter (`claude-api`, `opencode`,
|
|
85
|
+
* `claude-code-headless`, …) added to the SSOT is automatically accepted
|
|
86
|
+
* by the HTTP recruit endpoint, instead of being silently rejected by an
|
|
87
|
+
* allowlist that someone forgot to update.
|
|
88
|
+
*/
|
|
89
|
+
exports.ALLOWED_AGENTS_DEV = types_1.AGENT_TYPES;
|
|
90
|
+
exports.ALLOWED_AGENTS_PROD = types_1.AGENT_TYPES.filter((a) => !DEV_ONLY_AGENTS.has(a));
|
|
91
|
+
function allowedAgentsForCurrentMode() {
|
|
92
|
+
return (0, config_1.isDevMode)() ? exports.ALLOWED_AGENTS_DEV : exports.ALLOWED_AGENTS_PROD;
|
|
93
|
+
}
|
|
94
|
+
function isAllowedAgent(s, allowed) {
|
|
95
|
+
return allowed.includes(s);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Pluck a required `playerId` from a parsed body, validating shape.
|
|
99
|
+
*
|
|
100
|
+
* Returns the `playerId` string on success. On any failure (missing or
|
|
101
|
+
* malformed) writes the appropriate 400 response via `errorResponse` and
|
|
102
|
+
* returns `undefined`. **Callers MUST check the return value and bail
|
|
103
|
+
* out** — a missing `if (!playerId) return;` would silently skip the
|
|
104
|
+
* downstream client call and double-send to the response stream.
|
|
105
|
+
*
|
|
106
|
+
* Shared by every per-player route under `/v1/ensembles/:ensemble/<action>`
|
|
107
|
+
* (restart / destroy / detach / recall — `release` keeps an inline check
|
|
108
|
+
* because its `playerId` field is optional, not required).
|
|
109
|
+
*/
|
|
110
|
+
function requirePlayerId(res, body) {
|
|
111
|
+
const playerId = stringField(body, 'playerId');
|
|
112
|
+
if (!playerId) {
|
|
113
|
+
(0, responses_1.errorResponse)(res, 400, { error: 'missing-field', field: 'playerId' });
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
if ((0, validation_1.validatePlayerName)(playerId) !== null) {
|
|
117
|
+
(0, responses_1.errorResponse)(res, 400, { error: 'invalid-player-name', field: 'playerId' });
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
return playerId;
|
|
121
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Daemon HTTP catalog routes — issue #400.
|
|
3
|
+
*
|
|
4
|
+
* Three endpoints exposing on-disk catalog data so the dashboard's
|
|
5
|
+
* Recruit + CreateEnsemble + Loadouts + PlayerTypes wizards can drop
|
|
6
|
+
* the hardcoded fallbacks shipped during PR-E + PR-F:
|
|
7
|
+
*
|
|
8
|
+
* - GET /v1/agent-types → `listAgentTypes()` from ensemble/agent-types.ts
|
|
9
|
+
* - GET /v1/lineups → `listLineups()` from ensemble/loader.ts
|
|
10
|
+
* - POST /v1/ensembles → recruit a conductor (+ lineup players)
|
|
11
|
+
*
|
|
12
|
+
* Auth + CORS gating happens in `server.ts` before the dispatcher
|
|
13
|
+
* reaches these handlers; no per-handler bearer check needed.
|
|
14
|
+
*
|
|
15
|
+
* Response shapes match the issue #400 wire spec; see also
|
|
16
|
+
* `docs/WIRE-PROTOCOL.md` for the full HTTP catalog.
|
|
17
|
+
*/
|
|
18
|
+
import type { IncomingMessage, ServerResponse } from 'http';
|
|
19
|
+
import type { TempoClient } from '../client/interface';
|
|
20
|
+
export interface AgentTypeRow {
|
|
21
|
+
name: string;
|
|
22
|
+
description?: string;
|
|
23
|
+
source: 'project' | 'user' | 'shipped';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* `listAgentTypes()` returns rows with `path` + `nativeResolvable` +
|
|
27
|
+
* optional `allowedTools` — the dashboard only needs name/description/
|
|
28
|
+
* source. Strip the rest so we don't leak filesystem paths over the
|
|
29
|
+
* wire (loopback bind is the common case but the API is also reachable
|
|
30
|
+
* over LAN behind bearer auth — same privacy contract as `HostProfile`
|
|
31
|
+
* stripping in `src/types.ts`).
|
|
32
|
+
*/
|
|
33
|
+
export declare function handleListAgentTypes(res: ServerResponse): void;
|
|
34
|
+
export interface LineupRow {
|
|
35
|
+
name: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
players: number;
|
|
38
|
+
source: 'saved' | 'shipped';
|
|
39
|
+
}
|
|
40
|
+
export declare function handleListLineups(res: ServerResponse): void;
|
|
41
|
+
/**
|
|
42
|
+
* POST `/v1/ensembles` — create a fresh ensemble.
|
|
43
|
+
*
|
|
44
|
+
* The bootstrap path is the daemon-side equivalent of the CLI's
|
|
45
|
+
* `agent-tempo up` codepath, but trimmed to the actions the daemon
|
|
46
|
+
* can run for a browser caller:
|
|
47
|
+
*
|
|
48
|
+
* 1. Validate the body (name regex, lineup exists if specified,
|
|
49
|
+
* startMode in {hold, release}).
|
|
50
|
+
* 2. Reject 409 if an ensemble with that name is already live.
|
|
51
|
+
* 3. Recruit the conductor (`isConductor: true`) — this bootstraps
|
|
52
|
+
* the maestro + scheduler + conductor-session workflows.
|
|
53
|
+
* 4. Recruit each lineup player. Inherits `host` + `held` from the
|
|
54
|
+
* top-level body when the lineup row doesn't specify its own.
|
|
55
|
+
* 5. Return 201 + the ensemble summary so the dashboard can
|
|
56
|
+
* navigate to `/ensemble/:name` without a follow-up snapshot
|
|
57
|
+
* fetch.
|
|
58
|
+
*
|
|
59
|
+
* Skipped vs CLI `up` (intentional):
|
|
60
|
+
* - No Temporal-server start: the daemon serving this request
|
|
61
|
+
* already proves Temporal is up.
|
|
62
|
+
* - No daemon start / agent-type install / MCP register: a browser
|
|
63
|
+
* caller doesn't go through that pre-flight.
|
|
64
|
+
* - No interactive "ensemble already exists" choice tree: HTTP is
|
|
65
|
+
* stateless; we 409 and let the dashboard surface a useful error.
|
|
66
|
+
*/
|
|
67
|
+
export declare function handleCreateEnsemble(req: IncomingMessage, res: ServerResponse, client: TempoClient): Promise<void>;
|