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,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compute the base directory for all worktrees in an ensemble.
|
|
3
|
+
* Convention: `{gitRoot}/../.ct-worktrees/{ensemble}/`
|
|
4
|
+
*/
|
|
5
|
+
export declare function worktreeBasePath(gitRoot: string, ensemble: string): string;
|
|
6
|
+
export interface CreateWorktreeOpts {
|
|
7
|
+
gitRoot: string;
|
|
8
|
+
ensemble: string;
|
|
9
|
+
playerName: string;
|
|
10
|
+
branch?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Tag returned by {@link switchWorktreeToBranch} and surfaced on
|
|
14
|
+
* {@link CreateWorktreeResult.switched} so the MCP tool's response text can
|
|
15
|
+
* report the actual state transition instead of silently reusing the request
|
|
16
|
+
* as ground truth (#261). Values:
|
|
17
|
+
*
|
|
18
|
+
* - `same` — the worktree was already on the requested branch. No-op.
|
|
19
|
+
* - `switched` — the requested branch existed locally; plain `git checkout`.
|
|
20
|
+
* - `created-from-main` — the requested branch did not exist locally;
|
|
21
|
+
* created it off `origin/main` via `git checkout -b`.
|
|
22
|
+
*/
|
|
23
|
+
export type WorktreeSwitchResult = 'same' | 'switched' | 'created-from-main';
|
|
24
|
+
export interface CreateWorktreeResult {
|
|
25
|
+
/** Absolute path to the worktree directory. */
|
|
26
|
+
path: string;
|
|
27
|
+
/** Branch name used for the worktree. */
|
|
28
|
+
branch: string;
|
|
29
|
+
/** Whether the worktree was newly created (false if it already existed). */
|
|
30
|
+
created: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* When `created === false` (reuse path), which git operation the helper ran
|
|
33
|
+
* to bring the worktree onto the requested branch. `undefined` on fresh
|
|
34
|
+
* creation — the #261 information is only meaningful for reuse.
|
|
35
|
+
*/
|
|
36
|
+
switched?: WorktreeSwitchResult;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Ensure the worktree at `wtPath` is checked out on `targetBranch`.
|
|
40
|
+
*
|
|
41
|
+
* Fix for #261: the prior reuse path returned the *requested* branch name in
|
|
42
|
+
* its result without ever consulting the worktree's actual HEAD, silently
|
|
43
|
+
* papering over mismatches when a worktree from a prior task was recycled for
|
|
44
|
+
* a new branch. This helper does the repointing that was missing — and
|
|
45
|
+
* refuses (rather than silently discarding) if the target worktree has
|
|
46
|
+
* uncommitted work on a different branch.
|
|
47
|
+
*
|
|
48
|
+
* Decision tree (mirrors the conductor's guidance on #261):
|
|
49
|
+
* 1. current branch === targetBranch → no-op, return `'same'`. The
|
|
50
|
+
* hot path. Deliberately does NOT run `status --porcelain`: if we're
|
|
51
|
+
* not flipping the branch, dirty work is fine.
|
|
52
|
+
* 2. `git status --porcelain` non-empty → throw `"uncommitted changes"`
|
|
53
|
+
* with path + current branch. Must precede any checkout so we never
|
|
54
|
+
* silently discard work on a branch flip.
|
|
55
|
+
* 3. target branch exists locally → `git checkout <target>`.
|
|
56
|
+
* Preserves the branch's recorded state; no `-B`, no force-reset.
|
|
57
|
+
* 4. target branch does not exist locally → `git checkout -b <target> origin/main`.
|
|
58
|
+
* Matches the semantics of the fresh-worktree `git worktree add -B`
|
|
59
|
+
* path — new branch rooted at the current main tip.
|
|
60
|
+
*
|
|
61
|
+
* Caller is expected to have already verified `wtPath` is an existing git
|
|
62
|
+
* worktree (this helper runs the git commands with `-C <wtPath>` and does no
|
|
63
|
+
* path-existence checks of its own).
|
|
64
|
+
*/
|
|
65
|
+
export declare function switchWorktreeToBranch(wtPath: string, targetBranch: string): WorktreeSwitchResult;
|
|
66
|
+
/**
|
|
67
|
+
* Create a git worktree for a player. If the worktree already exists
|
|
68
|
+
* at the expected path, returns it after repointing to the requested branch
|
|
69
|
+
* via {@link switchWorktreeToBranch} — the fix for #261, which previously
|
|
70
|
+
* reused the directory without ever consulting its actual HEAD.
|
|
71
|
+
*
|
|
72
|
+
* Branch defaults to `{ensemble}/{playerName}` if not specified.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createWorktree(opts: CreateWorktreeOpts): CreateWorktreeResult;
|
|
75
|
+
/**
|
|
76
|
+
* Install dependencies in a worktree directory.
|
|
77
|
+
*
|
|
78
|
+
* Detects the package manager (npm, yarn, pnpm) by lockfile presence.
|
|
79
|
+
* Failure or timeout is logged but does not throw — the recruit proceeds
|
|
80
|
+
* with whatever state the worktree is in.
|
|
81
|
+
*/
|
|
82
|
+
export declare function installDependencies(worktreePath: string, timeoutMs?: number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Remove a git worktree.
|
|
85
|
+
*
|
|
86
|
+
* Throws if the worktree directory survives the removal (#594). On Windows,
|
|
87
|
+
* `git worktree remove --force` deletes `.git/worktrees/<name>` metadata
|
|
88
|
+
* *first*, then `rmdir`s the directory — so when a native `.node` module
|
|
89
|
+
* inside the worktree is memory-mapped by a live process, the directory
|
|
90
|
+
* deletion fails while the metadata is already gone. The pre-#594 code
|
|
91
|
+
* swallowed that failure (log-only, no throw), so the caller reported
|
|
92
|
+
* success and Temporal state diverged from disk. Now the post-removal
|
|
93
|
+
* `existsSync` check turns a half-removal into a hard error the caller can
|
|
94
|
+
* surface.
|
|
95
|
+
*
|
|
96
|
+
* `gitRoot` scopes the `git worktree remove` invocation to the owning
|
|
97
|
+
* repository. Pre-#594 the command ran with no `cwd`, so it only worked when
|
|
98
|
+
* `process.cwd()` happened to be the right repo — fragile, and wrong outright
|
|
99
|
+
* when the conductor's cwd is a different checkout than the worktree's repo.
|
|
100
|
+
* Callers should pass `entry.gitRoot` from the `WorktreeEntry`; it defaults to
|
|
101
|
+
* `process.cwd()` for backward compatibility.
|
|
102
|
+
*/
|
|
103
|
+
export declare function removeWorktree(worktreePath: string, gitRoot?: string): void;
|
|
@@ -0,0 +1,327 @@
|
|
|
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.worktreeBasePath = worktreeBasePath;
|
|
37
|
+
exports.switchWorktreeToBranch = switchWorktreeToBranch;
|
|
38
|
+
exports.createWorktree = createWorktree;
|
|
39
|
+
exports.installDependencies = installDependencies;
|
|
40
|
+
exports.removeWorktree = removeWorktree;
|
|
41
|
+
/**
|
|
42
|
+
* Git worktree helpers for player isolation.
|
|
43
|
+
*
|
|
44
|
+
* Creates and manages git worktrees so each player can work on an
|
|
45
|
+
* isolated copy of the repository without conflicting with others.
|
|
46
|
+
*/
|
|
47
|
+
const child_process_1 = require("child_process");
|
|
48
|
+
const fs_1 = require("fs");
|
|
49
|
+
const path = __importStar(require("path"));
|
|
50
|
+
const validation_1 = require("./validation");
|
|
51
|
+
const log = (...args) => console.error('[agent-tempo:worktree]', ...args);
|
|
52
|
+
/**
|
|
53
|
+
* Compute the base directory for all worktrees in an ensemble.
|
|
54
|
+
* Convention: `{gitRoot}/../.ct-worktrees/{ensemble}/`
|
|
55
|
+
*/
|
|
56
|
+
function worktreeBasePath(gitRoot, ensemble) {
|
|
57
|
+
return path.join(path.dirname(gitRoot), '.ct-worktrees', ensemble);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Ensure the worktree at `wtPath` is checked out on `targetBranch`.
|
|
61
|
+
*
|
|
62
|
+
* Fix for #261: the prior reuse path returned the *requested* branch name in
|
|
63
|
+
* its result without ever consulting the worktree's actual HEAD, silently
|
|
64
|
+
* papering over mismatches when a worktree from a prior task was recycled for
|
|
65
|
+
* a new branch. This helper does the repointing that was missing — and
|
|
66
|
+
* refuses (rather than silently discarding) if the target worktree has
|
|
67
|
+
* uncommitted work on a different branch.
|
|
68
|
+
*
|
|
69
|
+
* Decision tree (mirrors the conductor's guidance on #261):
|
|
70
|
+
* 1. current branch === targetBranch → no-op, return `'same'`. The
|
|
71
|
+
* hot path. Deliberately does NOT run `status --porcelain`: if we're
|
|
72
|
+
* not flipping the branch, dirty work is fine.
|
|
73
|
+
* 2. `git status --porcelain` non-empty → throw `"uncommitted changes"`
|
|
74
|
+
* with path + current branch. Must precede any checkout so we never
|
|
75
|
+
* silently discard work on a branch flip.
|
|
76
|
+
* 3. target branch exists locally → `git checkout <target>`.
|
|
77
|
+
* Preserves the branch's recorded state; no `-B`, no force-reset.
|
|
78
|
+
* 4. target branch does not exist locally → `git checkout -b <target> origin/main`.
|
|
79
|
+
* Matches the semantics of the fresh-worktree `git worktree add -B`
|
|
80
|
+
* path — new branch rooted at the current main tip.
|
|
81
|
+
*
|
|
82
|
+
* Caller is expected to have already verified `wtPath` is an existing git
|
|
83
|
+
* worktree (this helper runs the git commands with `-C <wtPath>` and does no
|
|
84
|
+
* path-existence checks of its own).
|
|
85
|
+
*/
|
|
86
|
+
function switchWorktreeToBranch(wtPath, targetBranch) {
|
|
87
|
+
const current = (0, child_process_1.execFileSync)('git', ['-C', wtPath, 'branch', '--show-current'], {
|
|
88
|
+
encoding: 'utf8',
|
|
89
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
90
|
+
}).trim();
|
|
91
|
+
if (current === targetBranch) {
|
|
92
|
+
log(`Worktree at "${wtPath}" already on "${targetBranch}" — no-op`);
|
|
93
|
+
return 'same';
|
|
94
|
+
}
|
|
95
|
+
// Branch mismatch → dirty-tree guard before any checkout. `--porcelain`
|
|
96
|
+
// emits one line per change with no color/decoration; empty output means
|
|
97
|
+
// the working tree + index are clean (ignored files don't count).
|
|
98
|
+
const dirty = (0, child_process_1.execFileSync)('git', ['-C', wtPath, 'status', '--porcelain'], {
|
|
99
|
+
encoding: 'utf8',
|
|
100
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
101
|
+
});
|
|
102
|
+
if (dirty.trim().length > 0) {
|
|
103
|
+
throw new Error(`Worktree at "${wtPath}" has uncommitted changes on branch "${current}"; ` +
|
|
104
|
+
`cannot repoint to "${targetBranch}". Commit or discard changes first.`);
|
|
105
|
+
}
|
|
106
|
+
// Does the target branch already exist locally? `rev-parse --verify` exits
|
|
107
|
+
// 0 on hit, non-zero on miss.
|
|
108
|
+
let branchExistsLocally = false;
|
|
109
|
+
try {
|
|
110
|
+
(0, child_process_1.execFileSync)('git', ['-C', wtPath, 'rev-parse', '--verify', `refs/heads/${targetBranch}`], {
|
|
111
|
+
encoding: 'utf8',
|
|
112
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
113
|
+
});
|
|
114
|
+
branchExistsLocally = true;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// refs/heads/<target> doesn't exist — fall through to create-from-main.
|
|
118
|
+
}
|
|
119
|
+
if (branchExistsLocally) {
|
|
120
|
+
log(`Worktree at "${wtPath}" switching "${current}" → "${targetBranch}" (existing local branch)`);
|
|
121
|
+
try {
|
|
122
|
+
(0, child_process_1.execFileSync)('git', ['-C', wtPath, 'checkout', targetBranch], {
|
|
123
|
+
encoding: 'utf8',
|
|
124
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
const msg = err.stderr || err.stdout || err.message || String(err);
|
|
129
|
+
throw new Error(`Failed to switch "${wtPath}" to "${targetBranch}": ${msg.trim()}`);
|
|
130
|
+
}
|
|
131
|
+
return 'switched';
|
|
132
|
+
}
|
|
133
|
+
log(`Worktree at "${wtPath}" switching "${current}" → "${targetBranch}" (new local branch from origin/main)`);
|
|
134
|
+
try {
|
|
135
|
+
(0, child_process_1.execFileSync)('git', ['-C', wtPath, 'checkout', '-b', targetBranch, 'origin/main'], {
|
|
136
|
+
encoding: 'utf8',
|
|
137
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
const msg = err.stderr || err.stdout || err.message || String(err);
|
|
142
|
+
throw new Error(`Failed to create "${targetBranch}" from origin/main in "${wtPath}": ${msg.trim()}`);
|
|
143
|
+
}
|
|
144
|
+
return 'created-from-main';
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Create a git worktree for a player. If the worktree already exists
|
|
148
|
+
* at the expected path, returns it after repointing to the requested branch
|
|
149
|
+
* via {@link switchWorktreeToBranch} — the fix for #261, which previously
|
|
150
|
+
* reused the directory without ever consulting its actual HEAD.
|
|
151
|
+
*
|
|
152
|
+
* Branch defaults to `{ensemble}/{playerName}` if not specified.
|
|
153
|
+
*/
|
|
154
|
+
function createWorktree(opts) {
|
|
155
|
+
const { gitRoot, ensemble, playerName } = opts;
|
|
156
|
+
const branch = opts.branch || `${ensemble}/${playerName}`;
|
|
157
|
+
const basePath = worktreeBasePath(gitRoot, ensemble);
|
|
158
|
+
const wtPath = path.join(basePath, playerName);
|
|
159
|
+
// If worktree already exists, reuse it — but verify its HEAD matches the
|
|
160
|
+
// requested branch (repoint if not). This is the #261 fix: the previous
|
|
161
|
+
// early-return trusted `branch` from the request as ground truth, so a
|
|
162
|
+
// worktree left on a prior task's branch would be silently misreported.
|
|
163
|
+
if ((0, fs_1.existsSync)(path.join(wtPath, '.git'))) {
|
|
164
|
+
log(`Worktree already exists at "${wtPath}" — reusing, verifying branch`);
|
|
165
|
+
const switched = switchWorktreeToBranch(wtPath, branch);
|
|
166
|
+
return { path: wtPath, branch, created: false, switched };
|
|
167
|
+
}
|
|
168
|
+
// #594 defect 2: stale-orphan recovery. A half-removed worktree leaves the
|
|
169
|
+
// directory on disk with its `.git` file already deleted (`git worktree
|
|
170
|
+
// remove` deletes metadata before the rmdir, which then fails under a
|
|
171
|
+
// Windows file lock). The reuse guard above keys on `.git` presence, so it
|
|
172
|
+
// is skipped — and `git worktree add` below refuses a non-empty pre-existing
|
|
173
|
+
// directory with a confusing `fatal: '...' already exists`. Detect the
|
|
174
|
+
// orphan and clear it first, with a clear error if the lock is still held.
|
|
175
|
+
if ((0, fs_1.existsSync)(wtPath)) {
|
|
176
|
+
log(`Stale worktree directory at "${wtPath}" (no \`.git\`) — attempting cleanup`);
|
|
177
|
+
try {
|
|
178
|
+
(0, fs_1.rmSync)(wtPath, { recursive: true, force: true });
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
// Swallow — the existsSync re-check below is the authoritative gate.
|
|
182
|
+
log(`Warning: \`rmSync\` on stale worktree "${wtPath}" failed: ${err?.message ?? err}`);
|
|
183
|
+
}
|
|
184
|
+
if ((0, fs_1.existsSync)(wtPath)) {
|
|
185
|
+
throw new Error(`Stale worktree directory at "${wtPath}" could not be removed — kill any ` +
|
|
186
|
+
`processes running inside it (e.g. a dev server) and retry. On Windows, ` +
|
|
187
|
+
`memory-mapped native \`.node\` modules hold the lock until the owning ` +
|
|
188
|
+
`process exits.`);
|
|
189
|
+
}
|
|
190
|
+
// Directory cleared — prune any dangling git metadata so `git worktree add`
|
|
191
|
+
// doesn't trip over a stale registration for the same path/branch.
|
|
192
|
+
try {
|
|
193
|
+
(0, child_process_1.execFileSync)('git', ['worktree', 'prune'], {
|
|
194
|
+
cwd: gitRoot,
|
|
195
|
+
encoding: 'utf8',
|
|
196
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
// Best-effort — prune failure is non-fatal; the add below will surface
|
|
201
|
+
// any real conflict.
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// Ensure base directory exists
|
|
205
|
+
(0, fs_1.mkdirSync)(basePath, { recursive: true });
|
|
206
|
+
// Check if the branch already has a worktree (would cause git error)
|
|
207
|
+
try {
|
|
208
|
+
const existing = (0, child_process_1.execFileSync)('git', ['worktree', 'list', '--porcelain'], {
|
|
209
|
+
cwd: gitRoot,
|
|
210
|
+
encoding: 'utf8',
|
|
211
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
212
|
+
});
|
|
213
|
+
// Parse porcelain output: "branch refs/heads/{branch}" lines
|
|
214
|
+
const branchRef = `refs/heads/${branch}`;
|
|
215
|
+
if (existing.includes(`branch ${branchRef}`)) {
|
|
216
|
+
throw new Error(`Branch "${branch}" already has an active worktree. ` +
|
|
217
|
+
`Remove it first with \`git worktree remove\` or choose a different branch.`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
// Re-throw our own error, swallow git failures (e.g., no worktrees yet)
|
|
222
|
+
if (err.message?.includes('already has an active worktree'))
|
|
223
|
+
throw err;
|
|
224
|
+
}
|
|
225
|
+
// Create the worktree. Use -B to create/reset the branch.
|
|
226
|
+
try {
|
|
227
|
+
log(`Creating worktree: git worktree add -B ${branch} ${wtPath}`);
|
|
228
|
+
(0, child_process_1.execFileSync)('git', ['worktree', 'add', '-B', branch, wtPath], {
|
|
229
|
+
cwd: gitRoot,
|
|
230
|
+
encoding: 'utf8',
|
|
231
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
catch (err) {
|
|
235
|
+
const msg = err.stderr || err.stdout || err.message || String(err);
|
|
236
|
+
throw new Error(`Failed to create worktree at "${wtPath}": ${msg.trim()}`);
|
|
237
|
+
}
|
|
238
|
+
return { path: wtPath, branch, created: true };
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Install dependencies in a worktree directory.
|
|
242
|
+
*
|
|
243
|
+
* Detects the package manager (npm, yarn, pnpm) by lockfile presence.
|
|
244
|
+
* Failure or timeout is logged but does not throw — the recruit proceeds
|
|
245
|
+
* with whatever state the worktree is in.
|
|
246
|
+
*/
|
|
247
|
+
function installDependencies(worktreePath, timeoutMs = validation_1.WORKTREE_INSTALL_TIMEOUT) {
|
|
248
|
+
// Detect package manager by lockfile
|
|
249
|
+
let cmd;
|
|
250
|
+
let args;
|
|
251
|
+
if ((0, fs_1.existsSync)(path.join(worktreePath, 'pnpm-lock.yaml'))) {
|
|
252
|
+
cmd = 'pnpm';
|
|
253
|
+
args = ['install', '--frozen-lockfile'];
|
|
254
|
+
}
|
|
255
|
+
else if ((0, fs_1.existsSync)(path.join(worktreePath, 'yarn.lock'))) {
|
|
256
|
+
cmd = 'yarn';
|
|
257
|
+
args = ['install', '--frozen-lockfile'];
|
|
258
|
+
}
|
|
259
|
+
else if ((0, fs_1.existsSync)(path.join(worktreePath, 'package-lock.json')) || (0, fs_1.existsSync)(path.join(worktreePath, 'package.json'))) {
|
|
260
|
+
cmd = 'npm';
|
|
261
|
+
args = ['install'];
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
log(`No package.json found in "${worktreePath}" — skipping install`);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
try {
|
|
268
|
+
log(`Installing dependencies in "${worktreePath}": ${cmd} ${args.join(' ')}`);
|
|
269
|
+
(0, child_process_1.execFileSync)(cmd, args, {
|
|
270
|
+
cwd: worktreePath,
|
|
271
|
+
encoding: 'utf8',
|
|
272
|
+
timeout: timeoutMs,
|
|
273
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
274
|
+
});
|
|
275
|
+
log(`Dependencies installed successfully in "${worktreePath}"`);
|
|
276
|
+
}
|
|
277
|
+
catch (err) {
|
|
278
|
+
// Log warning but don't throw — recruit should still proceed
|
|
279
|
+
const msg = err.killed ? `Timed out after ${timeoutMs}ms` : (err.stderr || err.message || String(err));
|
|
280
|
+
log(`Warning: dependency install failed in "${worktreePath}": ${msg}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Remove a git worktree.
|
|
285
|
+
*
|
|
286
|
+
* Throws if the worktree directory survives the removal (#594). On Windows,
|
|
287
|
+
* `git worktree remove --force` deletes `.git/worktrees/<name>` metadata
|
|
288
|
+
* *first*, then `rmdir`s the directory — so when a native `.node` module
|
|
289
|
+
* inside the worktree is memory-mapped by a live process, the directory
|
|
290
|
+
* deletion fails while the metadata is already gone. The pre-#594 code
|
|
291
|
+
* swallowed that failure (log-only, no throw), so the caller reported
|
|
292
|
+
* success and Temporal state diverged from disk. Now the post-removal
|
|
293
|
+
* `existsSync` check turns a half-removal into a hard error the caller can
|
|
294
|
+
* surface.
|
|
295
|
+
*
|
|
296
|
+
* `gitRoot` scopes the `git worktree remove` invocation to the owning
|
|
297
|
+
* repository. Pre-#594 the command ran with no `cwd`, so it only worked when
|
|
298
|
+
* `process.cwd()` happened to be the right repo — fragile, and wrong outright
|
|
299
|
+
* when the conductor's cwd is a different checkout than the worktree's repo.
|
|
300
|
+
* Callers should pass `entry.gitRoot` from the `WorktreeEntry`; it defaults to
|
|
301
|
+
* `process.cwd()` for backward compatibility.
|
|
302
|
+
*/
|
|
303
|
+
function removeWorktree(worktreePath, gitRoot = process.cwd()) {
|
|
304
|
+
try {
|
|
305
|
+
(0, child_process_1.execFileSync)('git', ['worktree', 'remove', '--force', worktreePath], {
|
|
306
|
+
cwd: gitRoot,
|
|
307
|
+
encoding: 'utf8',
|
|
308
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
const msg = err.stderr || err.message || String(err);
|
|
313
|
+
log(`Warning: \`git worktree remove\` failed at "${worktreePath}": ${msg.trim()}`);
|
|
314
|
+
// Don't return here — fall through to the post-removal check. git may have
|
|
315
|
+
// deleted the metadata but failed the rmdir; the existsSync gate below is
|
|
316
|
+
// the real success criterion.
|
|
317
|
+
}
|
|
318
|
+
// #594 defect 1: post-removal verification. If the directory is still on
|
|
319
|
+
// disk, the removal half-succeeded — surface it instead of returning void.
|
|
320
|
+
if ((0, fs_1.existsSync)(worktreePath)) {
|
|
321
|
+
throw new Error(`Worktree directory "${worktreePath}" still exists after \`git worktree remove\`. ` +
|
|
322
|
+
`On Windows this usually means a process is holding a file lock — e.g. a dev ` +
|
|
323
|
+
`server with a memory-mapped native \`.node\` module. Stop any processes running ` +
|
|
324
|
+
`inside the worktree and retry.`);
|
|
325
|
+
}
|
|
326
|
+
log(`Removed worktree at "${worktreePath}"`);
|
|
327
|
+
}
|
package/dist/worker.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Worker } from '@temporalio/worker';
|
|
2
|
+
import { Config } from './config';
|
|
3
|
+
export interface DualWorkers {
|
|
4
|
+
/** Shared queue worker: workflows + delivery activities + schedule activities */
|
|
5
|
+
sharedWorker: Worker;
|
|
6
|
+
/** Per-host queue worker: spawnProcess activity only */
|
|
7
|
+
hostWorker: Worker;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Create dual workers:
|
|
11
|
+
* - Shared queue: workflows + all delivery activities (deliverCue, deliverReport, terminateSession, startRecruitedSession) + schedule activities
|
|
12
|
+
* - Per-host queue: spawnProcess only (routes recruit spawns to the correct machine)
|
|
13
|
+
*/
|
|
14
|
+
export declare function createWorkers(config: Config): Promise<DualWorkers>;
|
package/dist/worker.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
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.createWorkers = createWorkers;
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const os = __importStar(require("os"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const worker_1 = require("@temporalio/worker");
|
|
41
|
+
const client_1 = require("@temporalio/client");
|
|
42
|
+
const config_1 = require("./config");
|
|
43
|
+
const connection_1 = require("./connection");
|
|
44
|
+
const connection_2 = require("./connection");
|
|
45
|
+
const schedule_fire_1 = require("./activities/schedule-fire");
|
|
46
|
+
const outbox_1 = require("./activities/outbox");
|
|
47
|
+
const maestro_1 = require("./activities/maestro");
|
|
48
|
+
const log = (...args) => console.error('[agent-tempo:worker]', ...args);
|
|
49
|
+
const BUNDLE_PATH = path.resolve(__dirname, '..', 'workflow-bundle.js');
|
|
50
|
+
/**
|
|
51
|
+
* #274 — deliberately set worker identity so host-discovery (`listHosts` in
|
|
52
|
+
* `src/utils/hosts.ts`) can parse pollers back into `hostname:pid:version`
|
|
53
|
+
* tuples without guessing at the SDK default (`<pid>@<hostname>`, which
|
|
54
|
+
* loses the version axis and is only informally guaranteed).
|
|
55
|
+
*
|
|
56
|
+
* Format: `agent-tempo:<hostname>:<pid>:<version>`. Colons are safe
|
|
57
|
+
* because the middle segments have their own validation:
|
|
58
|
+
* - hostname passes `PLAYER_NAME_REGEX` on the signal side (≤64 chars,
|
|
59
|
+
* no colons by construction on any platform the daemon supports)
|
|
60
|
+
* - pid is numeric
|
|
61
|
+
* - version is a semver-ish string (no colons)
|
|
62
|
+
*
|
|
63
|
+
* Legacy identities (`<pid>@<hostname>`) from pre-#274 daemons remain
|
|
64
|
+
* parseable at the join site — see `parseIdentity` in
|
|
65
|
+
* `src/utils/hosts.ts` for the dual-format tolerance.
|
|
66
|
+
*/
|
|
67
|
+
function workerIdentity() {
|
|
68
|
+
// Lazy-require so the test build (which compiles worker.ts into
|
|
69
|
+
// `dist-test/src/` where `../package.json` doesn't resolve) doesn't
|
|
70
|
+
// throw MODULE_NOT_FOUND at module-load time when daemon tests
|
|
71
|
+
// transitively import this file. `createWorkers` is only called from
|
|
72
|
+
// production code paths, so this runs against the real `dist/`
|
|
73
|
+
// layout where `../package.json` is the repo root.
|
|
74
|
+
const { version } = require('../package.json');
|
|
75
|
+
return `agent-tempo:${os.hostname()}:${process.pid}:${version}`;
|
|
76
|
+
}
|
|
77
|
+
async function getWorkflowBundle() {
|
|
78
|
+
// Use pre-built bundle if it exists, otherwise bundle from source
|
|
79
|
+
if (fs.existsSync(BUNDLE_PATH)) {
|
|
80
|
+
log(`Loading pre-built workflow bundle from ${BUNDLE_PATH}`);
|
|
81
|
+
return { code: fs.readFileSync(BUNDLE_PATH, 'utf-8') };
|
|
82
|
+
}
|
|
83
|
+
log('No pre-built workflow bundle found — bundling from source (run `npm run build` to avoid this)');
|
|
84
|
+
const bundle = await (0, worker_1.bundleWorkflowCode)({
|
|
85
|
+
workflowsPath: path.resolve(__dirname, 'workflows', 'index'),
|
|
86
|
+
});
|
|
87
|
+
// Cache for subsequent workers
|
|
88
|
+
fs.writeFileSync(BUNDLE_PATH, bundle.code);
|
|
89
|
+
return bundle;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Create dual workers:
|
|
93
|
+
* - Shared queue: workflows + all delivery activities (deliverCue, deliverReport, terminateSession, startRecruitedSession) + schedule activities
|
|
94
|
+
* - Per-host queue: spawnProcess only (routes recruit spawns to the correct machine)
|
|
95
|
+
*/
|
|
96
|
+
async function createWorkers(config) {
|
|
97
|
+
const connection = await (0, connection_1.createTemporalNativeConnection)(config);
|
|
98
|
+
// Create a Client connection for activities that need to interact with Temporal
|
|
99
|
+
const clientConnection = await (0, connection_2.createTemporalConnection)(config);
|
|
100
|
+
const client = new client_1.Client({ connection: clientConnection, namespace: config.temporalNamespace });
|
|
101
|
+
const scheduleActivities = (0, schedule_fire_1.createScheduleActivities)(client);
|
|
102
|
+
const outboxActivities = (0, outbox_1.createOutboxActivities)(client, config);
|
|
103
|
+
const maestroActivities = (0, maestro_1.createMaestroActivities)(client);
|
|
104
|
+
const workflowBundle = await getWorkflowBundle();
|
|
105
|
+
const SHUTDOWN_GRACE_TIME = '10s';
|
|
106
|
+
const SHUTDOWN_FORCE_TIME = '15s';
|
|
107
|
+
const sharedWorker = await worker_1.Worker.create({
|
|
108
|
+
connection,
|
|
109
|
+
namespace: config.temporalNamespace,
|
|
110
|
+
taskQueue: config.taskQueue,
|
|
111
|
+
identity: workerIdentity(), // #274 — parseable agent-tempo:<host>:<pid>:<version>
|
|
112
|
+
workflowBundle,
|
|
113
|
+
shutdownGraceTime: SHUTDOWN_GRACE_TIME,
|
|
114
|
+
shutdownForceTime: SHUTDOWN_FORCE_TIME,
|
|
115
|
+
activities: {
|
|
116
|
+
...scheduleActivities,
|
|
117
|
+
...maestroActivities,
|
|
118
|
+
// Shared-queue delivery activities (everything except spawnProcess)
|
|
119
|
+
deliverCue: outboxActivities.deliverCue,
|
|
120
|
+
deliverReport: outboxActivities.deliverReport,
|
|
121
|
+
terminateSession: outboxActivities.terminateSession,
|
|
122
|
+
startRecruitedSession: outboxActivities.startRecruitedSession,
|
|
123
|
+
releasePlayer: outboxActivities.releasePlayer,
|
|
124
|
+
deliverDetach: outboxActivities.deliverDetach,
|
|
125
|
+
deliverDestroy: outboxActivities.deliverDestroy,
|
|
126
|
+
deliverRestart: outboxActivities.deliverRestart,
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
// Per-host worker — spawnProcess only, no workflow bundle
|
|
130
|
+
const hostConnection = await (0, connection_1.createTemporalNativeConnection)(config);
|
|
131
|
+
const hostWorker = await worker_1.Worker.create({
|
|
132
|
+
connection: hostConnection,
|
|
133
|
+
namespace: config.temporalNamespace,
|
|
134
|
+
taskQueue: (0, config_1.hostTaskQueue)(config.taskQueue, os.hostname()),
|
|
135
|
+
identity: workerIdentity(), // #274 — same format, both pollers under one identity
|
|
136
|
+
shutdownGraceTime: SHUTDOWN_GRACE_TIME,
|
|
137
|
+
shutdownForceTime: SHUTDOWN_FORCE_TIME,
|
|
138
|
+
activities: {
|
|
139
|
+
spawnProcess: outboxActivities.spawnProcess,
|
|
140
|
+
// #159 Gap 2: host-local OS-process kill. Must live on the per-host queue so it runs
|
|
141
|
+
// on the machine where the claude.exe / bridge process actually lives.
|
|
142
|
+
hardTerminateAttachment: outboxActivities.hardTerminateAttachment,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
return { sharedWorker, hostWorker };
|
|
146
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure attachment-math helpers for the session workflow.
|
|
3
|
+
*
|
|
4
|
+
* **Workflow-sandbox safe**: this file imports only types. No `@temporalio/*`
|
|
5
|
+
* runtime imports, no `Date.now()`, no random, no I/O — every caller passes
|
|
6
|
+
* `now` as a parameter so the same inputs always produce the same output.
|
|
7
|
+
* That makes it:
|
|
8
|
+
* - Cheap to unit-test from Mocha without `TestWorkflowEnvironment`, and
|
|
9
|
+
* - Safe to call from deterministic workflow code (caller is responsible
|
|
10
|
+
* for sourcing `now` via the SDK-intercepted `new Date().getTime()`).
|
|
11
|
+
*
|
|
12
|
+
* Extracted in PR #127-fix as a follow-up to PR-G (#125) architect review:
|
|
13
|
+
* the alternative was a ~60 LOC history-fill harness that would have tested
|
|
14
|
+
* Temporal's CAN-trigger heuristic rather than our extension logic, and
|
|
15
|
+
* would have been brittle to Temporal-SDK internals. Pure-function + direct
|
|
16
|
+
* unit tests is the durable choice.
|
|
17
|
+
*/
|
|
18
|
+
import type { Attachment } from '../types';
|
|
19
|
+
/**
|
|
20
|
+
* Produce a new {@link Attachment} whose lease window is extended so an
|
|
21
|
+
* adapter that was beating normally at the moment of `continueAsNew` has room
|
|
22
|
+
* to land its next heartbeat before the new execution's first main-loop tick
|
|
23
|
+
* reaps the lease.
|
|
24
|
+
*
|
|
25
|
+
* **Design rationale (session-lifecycle-rebuild-v2.md §2.3):** the CAN
|
|
26
|
+
* transition is not instantaneous. If we were to write the pre-CAN
|
|
27
|
+
* `expiresAt` verbatim into the new execution, a transition that takes
|
|
28
|
+
* ~100-500ms could leave the new run's first deadline race observing an
|
|
29
|
+
* already-expired lease and reaping a healthy attachment. Pushing
|
|
30
|
+
* `expiresAt` out to `now + extendMs` guarantees the adapter has room to land
|
|
31
|
+
* its next heartbeat.
|
|
32
|
+
*
|
|
33
|
+
* Why this is a total function (returns a new object unconditionally,
|
|
34
|
+
* rather than accepting `null` and returning `undefined`): null-handling is
|
|
35
|
+
* the caller's business — a workflow that has no current attachment simply
|
|
36
|
+
* skips the call. Keeping this function non-nullable keeps the unit tests
|
|
37
|
+
* focused on math rather than null-propagation.
|
|
38
|
+
*
|
|
39
|
+
* @param attachment - the pre-CAN attachment record. All non-timestamp
|
|
40
|
+
* fields (`attachmentId`, `hostname`, `adapterId`, `adapterClass`,
|
|
41
|
+
* `claimedAt`, `leaseMs`, `runId`) are carried forward verbatim.
|
|
42
|
+
* @param extendMs - how far past `now` to push `expiresAt`, in milliseconds.
|
|
43
|
+
* Post-#249 callers pass `attachment.leaseMs` (= 3 × heartbeatMs — covers one
|
|
44
|
+
* full lease window and therefore at least one full heartbeat interval for
|
|
45
|
+
* every adapter class). Pre-#249 callers passed a hardcoded 30_000 constant
|
|
46
|
+
* which under-covered the claude-code adapter's 60s cadence — the rename
|
|
47
|
+
* from `heartbeatMs` disambiguates that the parameter is a raw extension
|
|
48
|
+
* duration, not a cadence. The function does not validate — any non-negative
|
|
49
|
+
* integer is accepted.
|
|
50
|
+
* @param now - current time in epoch milliseconds. In workflow context
|
|
51
|
+
* callers pass `new Date().getTime()` (the Temporal SDK intercepts `new
|
|
52
|
+
* Date()` to return replay-consistent time). In unit tests callers pass
|
|
53
|
+
* an arbitrary fixed value.
|
|
54
|
+
* @returns a new `Attachment` object — the input is not mutated.
|
|
55
|
+
*/
|
|
56
|
+
export declare function extendAttachmentForCAN(attachment: Attachment, extendMs: number, now: number): Attachment;
|