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
package/dist/types.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Shared types used by both workflow code (V8 sandbox) and Node.js server code.
|
|
3
|
+
// This file must NOT import from @temporalio/* — it's pure TypeScript types.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.ZERO_CHAT_HIGH_WATER = exports.MOCK_MODES = exports.AGENT_TYPES = void 0;
|
|
6
|
+
/**
|
|
7
|
+
* Agent runtime selector.
|
|
8
|
+
*
|
|
9
|
+
* - `'claude'` / `'copilot'` — production adapters; ship in the npm tarball.
|
|
10
|
+
* - `'mock'` — dev-mode-only adapter (ADR 0014 PR-2). Defense-in-depth gates
|
|
11
|
+
* (build-time exclusion, registry gate behind `isDevMode()`, recruit-time
|
|
12
|
+
* rejection, runtime banner) keep this off production paths. The string
|
|
13
|
+
* value lives in the type union so workflow / outbox / recruit code can
|
|
14
|
+
* discriminate without `any` casts even in production builds; the runtime
|
|
15
|
+
* gates are what actually prevent execution.
|
|
16
|
+
*
|
|
17
|
+
* Single source of truth: {@link AGENT_TYPES}. The CLI argv parser
|
|
18
|
+
* (`src/cli.ts`'s `--agent` validation) and the recruit MCP tool's
|
|
19
|
+
* `z.enum` import this tuple so adding a new adapter only requires
|
|
20
|
+
* editing one line — see #476 (the `claude-api` allowlist drift bug
|
|
21
|
+
* that motivated centralising this).
|
|
22
|
+
*/
|
|
23
|
+
exports.AGENT_TYPES = ['claude', 'copilot', 'mock', 'claude-api', 'opencode', 'claude-code-headless'];
|
|
24
|
+
/**
|
|
25
|
+
* Mock-adapter mode (ADR 0014 §4.2). Single source of truth shared by the
|
|
26
|
+
* adapter, the recruit tool's zod enum (`z.enum(MOCK_MODES)`), the spawn
|
|
27
|
+
* options, the recruit outbox entry, the lineup schema, and the lineup
|
|
28
|
+
* dispatcher. `'echo' | 'scripted'` shipped in PR-2; `'silent' | 'chaos'`
|
|
29
|
+
* landed in PR-3.
|
|
30
|
+
*
|
|
31
|
+
* Declared here rather than in `src/adapters/mock/` so non-dev-mode modules
|
|
32
|
+
* (recruit, spawn, schema) can reference the type without pulling the
|
|
33
|
+
* adapter source unit into their dep graph.
|
|
34
|
+
*/
|
|
35
|
+
exports.MOCK_MODES = ['echo', 'scripted', 'silent', 'chaos'];
|
|
36
|
+
/** Zero-value for ChatHighWater — use as default when no prior fetch. */
|
|
37
|
+
exports.ZERO_CHAT_HIGH_WATER = {
|
|
38
|
+
maestroRecv: 0, maestroSent: 0, conductorRecv: 0, conductorSent: 0,
|
|
39
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared attachment-info display formatter.
|
|
3
|
+
*
|
|
4
|
+
* Renders an {@link AttachmentInfo} snapshot into an array of plain strings
|
|
5
|
+
* suitable for either stdout (`agent-tempo attachment-info`) or the TUI
|
|
6
|
+
* overlay (`/attachment-info`). Pure — no Temporal, no stdout, no ANSI
|
|
7
|
+
* colors — so unit tests can assert exact lines without booting a client.
|
|
8
|
+
*
|
|
9
|
+
* Lives in `src/utils/` (not `src/cli/`) because both the CLI and TUI
|
|
10
|
+
* consume it; #264 carved it out of `src/cli/commands.ts` to eliminate the
|
|
11
|
+
* cross-surface drift where only the CLI rendered heartbeat age.
|
|
12
|
+
*
|
|
13
|
+
* `now` is injectable so tests can freeze the clock and assert the
|
|
14
|
+
* heartbeat-age string deterministically. Heartbeat age uses
|
|
15
|
+
* {@link formatDurationMs} (same helper the scheduler output uses) suffixed
|
|
16
|
+
* with "ago" — e.g. `5s ago`, `2m ago`. Clock-skew (heartbeat timestamp in
|
|
17
|
+
* the future) renders as `just now`; a malformed timestamp renders as
|
|
18
|
+
* `unknown`.
|
|
19
|
+
*/
|
|
20
|
+
import type { AttachmentInfo } from '../types';
|
|
21
|
+
export declare function formatAttachmentInfoForDisplay(name: string, info: AttachmentInfo, now?: number): string[];
|
|
22
|
+
export declare function formatHeartbeatAge(lastHeartbeatAt: string, now: number): string;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatAttachmentInfoForDisplay = formatAttachmentInfoForDisplay;
|
|
4
|
+
exports.formatHeartbeatAge = formatHeartbeatAge;
|
|
5
|
+
const duration_1 = require("./duration");
|
|
6
|
+
function formatAttachmentInfoForDisplay(name, info, now = Date.now()) {
|
|
7
|
+
const lines = [
|
|
8
|
+
`${name} — phase: ${info.phase}`,
|
|
9
|
+
` in-flight: ${info.inFlightCount}`,
|
|
10
|
+
];
|
|
11
|
+
if (info.currentAttachment) {
|
|
12
|
+
const a = info.currentAttachment;
|
|
13
|
+
lines.push(` attached on: ${a.hostname} (adapter: ${a.adapterId}/${a.adapterClass})`);
|
|
14
|
+
lines.push(` attachmentId: ${a.attachmentId}`);
|
|
15
|
+
lines.push(` lease expires: ${a.expiresAt}`);
|
|
16
|
+
lines.push(` heartbeat: ${formatHeartbeatAge(a.lastHeartbeatAt, now)}`);
|
|
17
|
+
}
|
|
18
|
+
if (info.preferredHost)
|
|
19
|
+
lines.push(` preferred host: ${info.preferredHost}`);
|
|
20
|
+
if (info.processingSince)
|
|
21
|
+
lines.push(` processing since: ${info.processingSince}`);
|
|
22
|
+
return lines;
|
|
23
|
+
}
|
|
24
|
+
function formatHeartbeatAge(lastHeartbeatAt, now) {
|
|
25
|
+
const then = Date.parse(lastHeartbeatAt);
|
|
26
|
+
if (!Number.isFinite(then))
|
|
27
|
+
return 'unknown';
|
|
28
|
+
const ageMs = now - then;
|
|
29
|
+
if (ageMs < 0)
|
|
30
|
+
return 'just now'; // adapter clock ran ahead of ours — degrade gracefully
|
|
31
|
+
return `${(0, duration_1.formatDurationMs)(ageMs)} ago`;
|
|
32
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Adapter types that are considered "headless" — i.e. they run without
|
|
3
|
+
* an interactive terminal. When a session has no explicit `part` and no
|
|
4
|
+
* player type, a headless adapter gets `'Headless <adapter> session'`
|
|
5
|
+
* instead of the generic `'Session in <basename>'`.
|
|
6
|
+
*
|
|
7
|
+
* Issue #537.
|
|
8
|
+
*/
|
|
9
|
+
export declare const HEADLESS_ADAPTERS: Set<string>;
|
|
10
|
+
/**
|
|
11
|
+
* Compute the default `part` text seeded into a fresh session workflow.
|
|
12
|
+
*
|
|
13
|
+
* Issue #450 — replaces the hardcoded `'Conductor session'` literal
|
|
14
|
+
* (which leaked through to non-conductor players via the rev3-cert
|
|
15
|
+
* deferred audit item R3.P2.5) and the role-agnostic
|
|
16
|
+
* `'Session in <basename>'` fallback with a single helper that picks a
|
|
17
|
+
* default reflecting the player's role whenever a player type is
|
|
18
|
+
* resolvable.
|
|
19
|
+
*
|
|
20
|
+
* Resolution order:
|
|
21
|
+
* 1. If `playerType` is set, derive from the suffix after stripping
|
|
22
|
+
* `tempo-` / `my-tempo-` / `la-tempo-`. Abbreviations live in
|
|
23
|
+
* `ROLE_ABBREVIATIONS`; everything else is title-cased:
|
|
24
|
+
* `tempo-conductor` → `'Conductor session'`
|
|
25
|
+
* `my-tempo-engineer` → `'Engineer session'`
|
|
26
|
+
* `my-tempo-qa` → `'QA session'`
|
|
27
|
+
* `my-tempo-devops` → `'DevOps session'`
|
|
28
|
+
* `la-tempo-advisor` → `'Advisor session'`
|
|
29
|
+
* `acme-reviewer` → `'Acme-reviewer session'` (no prefix match)
|
|
30
|
+
* 2. Else if `isConductor`, return `'Conductor session'` (the
|
|
31
|
+
* pre-#450 conductor literal — kept so untyped conductor sessions
|
|
32
|
+
* still read correctly).
|
|
33
|
+
* 3. Else if the adapter is headless (#537), return
|
|
34
|
+
* `'Headless <adapterType> session'`.
|
|
35
|
+
* 4. Else fall back to `'Session in <basename(workDir)>'`, or
|
|
36
|
+
* `'New session'` when no `workDir` is provided.
|
|
37
|
+
*/
|
|
38
|
+
export declare function defaultPart(opts: {
|
|
39
|
+
playerType?: string;
|
|
40
|
+
isConductor?: boolean;
|
|
41
|
+
workDir?: string;
|
|
42
|
+
adapterType?: string;
|
|
43
|
+
}): string;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.HEADLESS_ADAPTERS = void 0;
|
|
7
|
+
exports.defaultPart = defaultPart;
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Match the common agent-tempo agent-type prefixes so the suffix can be
|
|
11
|
+
* surfaced as a human-readable role:
|
|
12
|
+
* - `tempo-*` (shipped types: tempo-conductor, tempo-soloist, …)
|
|
13
|
+
* - `my-tempo-*` (per-user overrides under `~/.claude/agents/`)
|
|
14
|
+
* - `la-tempo-*` (workspace/project agents under `.claude/agents/`)
|
|
15
|
+
*
|
|
16
|
+
* Anything that doesn't match falls through and the full type name is
|
|
17
|
+
* title-cased instead, so a custom `acme-reviewer` type still reads as
|
|
18
|
+
* `'Acme-reviewer session'` rather than something nonsensical.
|
|
19
|
+
*/
|
|
20
|
+
const PLAYER_TYPE_PREFIX = /^(my-|la-)?tempo-/i;
|
|
21
|
+
/**
|
|
22
|
+
* Roles whose canonical capitalisation is not what naive title-casing
|
|
23
|
+
* produces (e.g. `qa` would become `'Qa'`). Keys are the lowercased
|
|
24
|
+
* suffix after `PLAYER_TYPE_PREFIX` is stripped; values are the
|
|
25
|
+
* display string spliced into `'<value> session'`.
|
|
26
|
+
*
|
|
27
|
+
* Add entries sparingly — most types follow the title-case rule and
|
|
28
|
+
* shouldn't need a special case.
|
|
29
|
+
*/
|
|
30
|
+
const ROLE_ABBREVIATIONS = {
|
|
31
|
+
qa: 'QA',
|
|
32
|
+
po: 'PO',
|
|
33
|
+
devops: 'DevOps',
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Adapter types that are considered "headless" — i.e. they run without
|
|
37
|
+
* an interactive terminal. When a session has no explicit `part` and no
|
|
38
|
+
* player type, a headless adapter gets `'Headless <adapter> session'`
|
|
39
|
+
* instead of the generic `'Session in <basename>'`.
|
|
40
|
+
*
|
|
41
|
+
* Issue #537.
|
|
42
|
+
*/
|
|
43
|
+
exports.HEADLESS_ADAPTERS = new Set([
|
|
44
|
+
'claude-code-headless',
|
|
45
|
+
'copilot',
|
|
46
|
+
'opencode',
|
|
47
|
+
'claude-api',
|
|
48
|
+
'mock',
|
|
49
|
+
]);
|
|
50
|
+
/**
|
|
51
|
+
* Compute the default `part` text seeded into a fresh session workflow.
|
|
52
|
+
*
|
|
53
|
+
* Issue #450 — replaces the hardcoded `'Conductor session'` literal
|
|
54
|
+
* (which leaked through to non-conductor players via the rev3-cert
|
|
55
|
+
* deferred audit item R3.P2.5) and the role-agnostic
|
|
56
|
+
* `'Session in <basename>'` fallback with a single helper that picks a
|
|
57
|
+
* default reflecting the player's role whenever a player type is
|
|
58
|
+
* resolvable.
|
|
59
|
+
*
|
|
60
|
+
* Resolution order:
|
|
61
|
+
* 1. If `playerType` is set, derive from the suffix after stripping
|
|
62
|
+
* `tempo-` / `my-tempo-` / `la-tempo-`. Abbreviations live in
|
|
63
|
+
* `ROLE_ABBREVIATIONS`; everything else is title-cased:
|
|
64
|
+
* `tempo-conductor` → `'Conductor session'`
|
|
65
|
+
* `my-tempo-engineer` → `'Engineer session'`
|
|
66
|
+
* `my-tempo-qa` → `'QA session'`
|
|
67
|
+
* `my-tempo-devops` → `'DevOps session'`
|
|
68
|
+
* `la-tempo-advisor` → `'Advisor session'`
|
|
69
|
+
* `acme-reviewer` → `'Acme-reviewer session'` (no prefix match)
|
|
70
|
+
* 2. Else if `isConductor`, return `'Conductor session'` (the
|
|
71
|
+
* pre-#450 conductor literal — kept so untyped conductor sessions
|
|
72
|
+
* still read correctly).
|
|
73
|
+
* 3. Else if the adapter is headless (#537), return
|
|
74
|
+
* `'Headless <adapterType> session'`.
|
|
75
|
+
* 4. Else fall back to `'Session in <basename(workDir)>'`, or
|
|
76
|
+
* `'New session'` when no `workDir` is provided.
|
|
77
|
+
*/
|
|
78
|
+
function defaultPart(opts) {
|
|
79
|
+
const playerType = opts.playerType?.trim();
|
|
80
|
+
if (playerType) {
|
|
81
|
+
const suffix = playerType.replace(PLAYER_TYPE_PREFIX, '');
|
|
82
|
+
if (suffix) {
|
|
83
|
+
const abbrev = ROLE_ABBREVIATIONS[suffix.toLowerCase()];
|
|
84
|
+
if (abbrev) {
|
|
85
|
+
return `${abbrev} session`;
|
|
86
|
+
}
|
|
87
|
+
const titled = suffix.charAt(0).toUpperCase() + suffix.slice(1);
|
|
88
|
+
return `${titled} session`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (opts.isConductor) {
|
|
92
|
+
return 'Conductor session';
|
|
93
|
+
}
|
|
94
|
+
// Issue #537 — headless adapters get a descriptive default when
|
|
95
|
+
// neither playerType nor isConductor identify the session.
|
|
96
|
+
const adapterType = opts.adapterType?.trim();
|
|
97
|
+
if (adapterType && exports.HEADLESS_ADAPTERS.has(adapterType)) {
|
|
98
|
+
return `Headless ${adapterType} session`;
|
|
99
|
+
}
|
|
100
|
+
if (opts.workDir && opts.workDir.trim()) {
|
|
101
|
+
return `Session in ${path_1.default.basename(opts.workDir)}`;
|
|
102
|
+
}
|
|
103
|
+
return 'New session';
|
|
104
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Parse a duration string like "30s", "10m", "2h", "1d" into milliseconds. */
|
|
2
|
+
export declare function parseDuration(dur: string): number | null;
|
|
3
|
+
/**
|
|
4
|
+
* Humanise a millisecond count as a short duration string: `30s` / `5m` /
|
|
5
|
+
* `2h` / `1d`. Picks the largest unit whose integer-or-fractional value is
|
|
6
|
+
* ≥ 1. Inverse (roughly) of {@link parseDuration}; matches the output shape
|
|
7
|
+
* several other surfaces emit (scheduler listings, attachment-info CLI).
|
|
8
|
+
*
|
|
9
|
+
* Consolidated here as part of #264 so the shared attachment-info formatter
|
|
10
|
+
* in `src/utils/attachment-format.ts` doesn't drag the CLI-local duplicate.
|
|
11
|
+
* Other local duplicates exist at `src/ensemble/saver.ts` and
|
|
12
|
+
* `src/tools/schedules.ts` — those can be migrated incrementally; leaving
|
|
13
|
+
* them alone keeps this PR's scope tight.
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatDurationMs(ms: number): string;
|
|
16
|
+
/**
|
|
17
|
+
* Render an ISO timestamp as a coarse "N{s,m,h,d} ago" string for human-
|
|
18
|
+
* readable listings. Returns `"just now"` for ≤1s, `"unknown"` if the
|
|
19
|
+
* timestamp can't be parsed.
|
|
20
|
+
*
|
|
21
|
+
* `now` is injectable for deterministic tests; defaults to `Date.now()`.
|
|
22
|
+
*
|
|
23
|
+
* **Why a second time helper exists** (the TUI has `formatRelativeTime`
|
|
24
|
+
* in `src/tui/utils/format.ts` doing roughly the same thing):
|
|
25
|
+
* `src/tui/` carries Ink/React transitive imports the headless tools layer
|
|
26
|
+
* mustn't take on. This helper has zero dependencies and is freely
|
|
27
|
+
* importable by any layer. Consolidation across the two homes is tracked
|
|
28
|
+
* as future deduplication work, not in scope here.
|
|
29
|
+
*/
|
|
30
|
+
export declare function formatTimeAgo(iso: string, now?: number): string;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseDuration = parseDuration;
|
|
4
|
+
exports.formatDurationMs = formatDurationMs;
|
|
5
|
+
exports.formatTimeAgo = formatTimeAgo;
|
|
6
|
+
/** Parse a duration string like "30s", "10m", "2h", "1d" into milliseconds. */
|
|
7
|
+
function parseDuration(dur) {
|
|
8
|
+
const match = dur.match(/^(\d+(?:\.\d+)?)\s*(s|m|h|d)$/i);
|
|
9
|
+
if (!match)
|
|
10
|
+
return null;
|
|
11
|
+
const value = parseFloat(match[1]);
|
|
12
|
+
switch (match[2].toLowerCase()) {
|
|
13
|
+
case 's': return value * 1000;
|
|
14
|
+
case 'm': return value * 60_000;
|
|
15
|
+
case 'h': return value * 3_600_000;
|
|
16
|
+
case 'd': return value * 86_400_000;
|
|
17
|
+
default: return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Humanise a millisecond count as a short duration string: `30s` / `5m` /
|
|
22
|
+
* `2h` / `1d`. Picks the largest unit whose integer-or-fractional value is
|
|
23
|
+
* ≥ 1. Inverse (roughly) of {@link parseDuration}; matches the output shape
|
|
24
|
+
* several other surfaces emit (scheduler listings, attachment-info CLI).
|
|
25
|
+
*
|
|
26
|
+
* Consolidated here as part of #264 so the shared attachment-info formatter
|
|
27
|
+
* in `src/utils/attachment-format.ts` doesn't drag the CLI-local duplicate.
|
|
28
|
+
* Other local duplicates exist at `src/ensemble/saver.ts` and
|
|
29
|
+
* `src/tools/schedules.ts` — those can be migrated incrementally; leaving
|
|
30
|
+
* them alone keeps this PR's scope tight.
|
|
31
|
+
*/
|
|
32
|
+
function formatDurationMs(ms) {
|
|
33
|
+
if (ms >= 86_400_000)
|
|
34
|
+
return `${ms / 86_400_000}d`;
|
|
35
|
+
if (ms >= 3_600_000)
|
|
36
|
+
return `${ms / 3_600_000}h`;
|
|
37
|
+
if (ms >= 60_000)
|
|
38
|
+
return `${ms / 60_000}m`;
|
|
39
|
+
return `${ms / 1000}s`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Render an ISO timestamp as a coarse "N{s,m,h,d} ago" string for human-
|
|
43
|
+
* readable listings. Returns `"just now"` for ≤1s, `"unknown"` if the
|
|
44
|
+
* timestamp can't be parsed.
|
|
45
|
+
*
|
|
46
|
+
* `now` is injectable for deterministic tests; defaults to `Date.now()`.
|
|
47
|
+
*
|
|
48
|
+
* **Why a second time helper exists** (the TUI has `formatRelativeTime`
|
|
49
|
+
* in `src/tui/utils/format.ts` doing roughly the same thing):
|
|
50
|
+
* `src/tui/` carries Ink/React transitive imports the headless tools layer
|
|
51
|
+
* mustn't take on. This helper has zero dependencies and is freely
|
|
52
|
+
* importable by any layer. Consolidation across the two homes is tracked
|
|
53
|
+
* as future deduplication work, not in scope here.
|
|
54
|
+
*/
|
|
55
|
+
function formatTimeAgo(iso, now = Date.now()) {
|
|
56
|
+
const t = Date.parse(iso);
|
|
57
|
+
if (!Number.isFinite(t))
|
|
58
|
+
return 'unknown';
|
|
59
|
+
const ms = now - t;
|
|
60
|
+
if (ms < 1000)
|
|
61
|
+
return 'just now';
|
|
62
|
+
if (ms < 60_000)
|
|
63
|
+
return `${Math.floor(ms / 1000)}s ago`;
|
|
64
|
+
if (ms < 3_600_000)
|
|
65
|
+
return `${Math.floor(ms / 60_000)}m ago`;
|
|
66
|
+
if (ms < 86_400_000)
|
|
67
|
+
return `${Math.floor(ms / 3_600_000)}h ago`;
|
|
68
|
+
return `${Math.floor(ms / 86_400_000)}d ago`;
|
|
69
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared ensemble-scope plumbing for the MCP tool handlers (`pause`, `play`,
|
|
3
|
+
* `shutdown`, `restore`, ensemble-scope `destroy`) and their `TempoClient`
|
|
4
|
+
* counterparts.
|
|
5
|
+
*
|
|
6
|
+
* All of these verbs need the same bits:
|
|
7
|
+
* 1. Toggle the maestro + scheduler pause signals, tolerating "workflow
|
|
8
|
+
* not running" on each because a bare-bones ensemble may lack either.
|
|
9
|
+
* 2. Fan out a signal (or update) across every session in the ensemble.
|
|
10
|
+
*
|
|
11
|
+
* Inlining these at each call site was pushing the diff past the architect's
|
|
12
|
+
* 500-line budget on PR #287 and bloating every new verb with near-identical
|
|
13
|
+
* try/catch scaffolding. This module is the single source of truth for both
|
|
14
|
+
* layers (tools + TempoClient) so a future signal-name rename or fan-out
|
|
15
|
+
* concurrency tweak only has to change here.
|
|
16
|
+
*/
|
|
17
|
+
import type { Client } from '@temporalio/client';
|
|
18
|
+
/**
|
|
19
|
+
* Result of a pause/unpause toggle. Each flag reflects whether the signal
|
|
20
|
+
* was actually delivered — `false` means the workflow wasn't running and
|
|
21
|
+
* the error was swallowed (the common bare-ensemble case).
|
|
22
|
+
*/
|
|
23
|
+
export interface MaestroSchedulerToggleResult {
|
|
24
|
+
maestro: boolean;
|
|
25
|
+
scheduler: boolean;
|
|
26
|
+
}
|
|
27
|
+
/** Pause the ensemble's maestro + scheduler. Best-effort on both. */
|
|
28
|
+
export declare function pauseMaestroAndScheduler(client: Client, ensemble: string): Promise<MaestroSchedulerToggleResult>;
|
|
29
|
+
/** Unpause the ensemble's maestro + scheduler. Best-effort on both. */
|
|
30
|
+
export declare function unpauseMaestroAndScheduler(client: Client, ensemble: string): Promise<MaestroSchedulerToggleResult>;
|
|
31
|
+
/**
|
|
32
|
+
* Fan-out a signal across every session in the ensemble. Per-session calls
|
|
33
|
+
* run in parallel via `Promise.allSettled` so a slow / failing session
|
|
34
|
+
* doesn't block the others — all Temporal ensembles are inherently
|
|
35
|
+
* unordered at this boundary (each session has its own workflow).
|
|
36
|
+
*
|
|
37
|
+
* `skip(playerId)` lets the caller exclude specific sessions (e.g. the
|
|
38
|
+
* caller's own session) without an extra pass.
|
|
39
|
+
*/
|
|
40
|
+
export interface FanoutSignalResult {
|
|
41
|
+
sent: number;
|
|
42
|
+
skipped: number;
|
|
43
|
+
failed: number;
|
|
44
|
+
perSession: Array<{
|
|
45
|
+
playerId: string;
|
|
46
|
+
workflowId: string;
|
|
47
|
+
outcome: 'sent';
|
|
48
|
+
} | {
|
|
49
|
+
playerId: string;
|
|
50
|
+
workflowId: string;
|
|
51
|
+
outcome: 'skipped';
|
|
52
|
+
} | {
|
|
53
|
+
playerId: string;
|
|
54
|
+
workflowId: string;
|
|
55
|
+
outcome: 'failed';
|
|
56
|
+
error: string;
|
|
57
|
+
}>;
|
|
58
|
+
}
|
|
59
|
+
export declare function signalAllSessions(client: Client, ensemble: string, signalName: string, payload: unknown, opts?: {
|
|
60
|
+
skip?: (playerId: string) => boolean;
|
|
61
|
+
}): Promise<FanoutSignalResult>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pauseMaestroAndScheduler = pauseMaestroAndScheduler;
|
|
4
|
+
exports.unpauseMaestroAndScheduler = unpauseMaestroAndScheduler;
|
|
5
|
+
exports.signalAllSessions = signalAllSessions;
|
|
6
|
+
const config_1 = require("../config");
|
|
7
|
+
const resolve_1 = require("../activities/resolve");
|
|
8
|
+
const maestro_signals_1 = require("../workflows/maestro-signals");
|
|
9
|
+
const scheduler_signals_1 = require("../workflows/scheduler-signals");
|
|
10
|
+
/** Pause the ensemble's maestro + scheduler. Best-effort on both. */
|
|
11
|
+
async function pauseMaestroAndScheduler(client, ensemble) {
|
|
12
|
+
return toggleMaestroAndScheduler(client, ensemble, true);
|
|
13
|
+
}
|
|
14
|
+
/** Unpause the ensemble's maestro + scheduler. Best-effort on both. */
|
|
15
|
+
async function unpauseMaestroAndScheduler(client, ensemble) {
|
|
16
|
+
return toggleMaestroAndScheduler(client, ensemble, false);
|
|
17
|
+
}
|
|
18
|
+
async function toggleMaestroAndScheduler(client, ensemble, paused) {
|
|
19
|
+
// Two independent RPCs — run them in parallel. Each catches its own
|
|
20
|
+
// error so one missing workflow doesn't block the other's state change.
|
|
21
|
+
const [maestro, scheduler] = await Promise.all([
|
|
22
|
+
safeSignal(client, (0, config_1.maestroWorkflowId)(ensemble), maestro_signals_1.maestroSetPausedSignal.name, paused),
|
|
23
|
+
safeSignal(client, (0, config_1.schedulerWorkflowId)(ensemble), scheduler_signals_1.setSchedulerPausedSignal.name, paused),
|
|
24
|
+
]);
|
|
25
|
+
return { maestro, scheduler };
|
|
26
|
+
}
|
|
27
|
+
async function safeSignal(client, workflowId, signalName, payload) {
|
|
28
|
+
try {
|
|
29
|
+
await client.workflow.getHandle(workflowId).signal(signalName, payload);
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
async function signalAllSessions(client, ensemble, signalName, payload, opts = {}) {
|
|
37
|
+
const sessions = await (0, resolve_1.scanEnsembleSessions)(client, ensemble);
|
|
38
|
+
const shouldSkip = opts.skip ?? (() => false);
|
|
39
|
+
const result = { sent: 0, skipped: 0, failed: 0, perSession: [] };
|
|
40
|
+
const settled = await Promise.allSettled(sessions.map(async (s) => {
|
|
41
|
+
if (shouldSkip(s.playerId)) {
|
|
42
|
+
return { session: s, outcome: 'skipped' };
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
await client.workflow.getHandle(s.workflowId).signal(signalName, payload);
|
|
46
|
+
return { session: s, outcome: 'sent' };
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
return {
|
|
50
|
+
session: s,
|
|
51
|
+
outcome: 'failed',
|
|
52
|
+
error: err instanceof Error ? err.message : String(err),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
}));
|
|
56
|
+
for (const r of settled) {
|
|
57
|
+
// `Promise.allSettled` only rejects if the mapper itself throws, and
|
|
58
|
+
// the mapper catches all signal errors internally — so every entry
|
|
59
|
+
// here will be `fulfilled`.
|
|
60
|
+
if (r.status !== 'fulfilled')
|
|
61
|
+
continue;
|
|
62
|
+
const v = r.value;
|
|
63
|
+
if (v.outcome === 'sent') {
|
|
64
|
+
result.sent++;
|
|
65
|
+
result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'sent' });
|
|
66
|
+
}
|
|
67
|
+
else if (v.outcome === 'skipped') {
|
|
68
|
+
result.skipped++;
|
|
69
|
+
result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'skipped' });
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
result.failed++;
|
|
73
|
+
result.perSession.push({ playerId: v.session.playerId, workflowId: v.session.workflowId, outcome: 'failed', error: v.error });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared formatter for the #274 `hosts` surface.
|
|
3
|
+
*
|
|
4
|
+
* Single source of truth consumed by:
|
|
5
|
+
* - `src/tools/hosts.ts` (MCP tool) — formatted text in `ok(...)` payload
|
|
6
|
+
* - `src/cli/commands.ts` (CLI `hosts` command) — stdout table
|
|
7
|
+
* - `src/tui/commands.ts` (TUI `/hosts` slash) — overlay content
|
|
8
|
+
*
|
|
9
|
+
* Pure: no Temporal, no I/O, no ANSI colors (the CLI can wrap lines in
|
|
10
|
+
* color downstream if desired; the formatter emits plain strings so
|
|
11
|
+
* tests can assert exact output without stripping escape codes).
|
|
12
|
+
*/
|
|
13
|
+
import type { HostInfo } from '../types';
|
|
14
|
+
export interface FormatHostsOpts {
|
|
15
|
+
/**
|
|
16
|
+
* Include hosts whose freshness is `'stale'`. Default `false`:
|
|
17
|
+
* CLI/TUI hide them by default; `--all` opts in.
|
|
18
|
+
*/
|
|
19
|
+
includeStale?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function formatHostList(hosts: HostInfo[], opts?: FormatHostsOpts): string;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatHostList = formatHostList;
|
|
4
|
+
function formatHostList(hosts, opts = {}) {
|
|
5
|
+
const includeStale = opts.includeStale ?? false;
|
|
6
|
+
const visible = includeStale ? hosts : hosts.filter((h) => h.freshness === 'live');
|
|
7
|
+
if (visible.length === 0) {
|
|
8
|
+
if (!includeStale && hosts.length > 0) {
|
|
9
|
+
return 'No live hosts connected. Pass `--all` to include stale hosts.';
|
|
10
|
+
}
|
|
11
|
+
return 'No hosts connected.';
|
|
12
|
+
}
|
|
13
|
+
const lines = [];
|
|
14
|
+
lines.push(`${visible.length} host${visible.length === 1 ? '' : 's'} connected:`);
|
|
15
|
+
lines.push('');
|
|
16
|
+
for (const host of visible) {
|
|
17
|
+
lines.push(...formatSingleHost(host));
|
|
18
|
+
lines.push('');
|
|
19
|
+
}
|
|
20
|
+
// Drop the final empty line so consumers don't have to `.trim()`.
|
|
21
|
+
if (lines[lines.length - 1] === '')
|
|
22
|
+
lines.pop();
|
|
23
|
+
return lines.join('\n');
|
|
24
|
+
}
|
|
25
|
+
function formatSingleHost(host) {
|
|
26
|
+
const lines = [];
|
|
27
|
+
const tag = host.freshness === 'live' ? '' : ' (stale)';
|
|
28
|
+
const recruit = host.recruitReady ? 'recruit-ready' : 'not recruit-ready';
|
|
29
|
+
lines.push(`**${host.hostname}**${tag} — ${recruit}`);
|
|
30
|
+
// Instance(s). One-liner per pid.
|
|
31
|
+
for (const inst of host.instances) {
|
|
32
|
+
const bits = [`pid ${inst.pid}`, `version ${inst.version}`];
|
|
33
|
+
const workerBits = [];
|
|
34
|
+
if (inst.hasWorkflowWorker)
|
|
35
|
+
workerBits.push('wf');
|
|
36
|
+
if (inst.hasActivityWorker)
|
|
37
|
+
workerBits.push('act');
|
|
38
|
+
if (inst.hasHostQueueWorker)
|
|
39
|
+
workerBits.push('host');
|
|
40
|
+
bits.push(`workers: ${workerBits.length > 0 ? workerBits.join('+') : 'none'}`);
|
|
41
|
+
if (inst.lastAccessTime)
|
|
42
|
+
bits.push(`last seen ${inst.lastAccessTime}`);
|
|
43
|
+
if (inst.legacy)
|
|
44
|
+
bits.push('legacy-identity');
|
|
45
|
+
lines.push(` - ${bits.join(' · ')}`);
|
|
46
|
+
}
|
|
47
|
+
// Profile (capability).
|
|
48
|
+
if (host.profile) {
|
|
49
|
+
const p = host.profile;
|
|
50
|
+
const profileBits = [];
|
|
51
|
+
if (p.platform)
|
|
52
|
+
profileBits.push(`platform: ${p.platform}`);
|
|
53
|
+
if (p.defaultAgent)
|
|
54
|
+
profileBits.push(`default agent: ${p.defaultAgent}`);
|
|
55
|
+
if (p.claudeBin)
|
|
56
|
+
profileBits.push(`claude bin: ${p.claudeBin}`);
|
|
57
|
+
if (profileBits.length > 0)
|
|
58
|
+
lines.push(` profile · ${profileBits.join(' · ')}`);
|
|
59
|
+
if (p.availableAgentTypes && p.availableAgentTypes.length > 0) {
|
|
60
|
+
lines.push(` available agents: ${p.availableAgentTypes.join(', ')}`);
|
|
61
|
+
}
|
|
62
|
+
if (p.availablePlayerTypes && p.availablePlayerTypes.length > 0) {
|
|
63
|
+
lines.push(` available player types: ${p.availablePlayerTypes.join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
if (host.profileStaleness === 'stale') {
|
|
66
|
+
lines.push(` ⚠ profile version disagrees with live identity — awaiting re-signal`);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
else if (host.profileStaleness === 'missing') {
|
|
70
|
+
lines.push(` (profile unavailable)`);
|
|
71
|
+
}
|
|
72
|
+
return lines;
|
|
73
|
+
}
|