agent-tempo 1.2.0 → 1.4.0

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.
Files changed (281) hide show
  1. package/CLAUDE.md +253 -219
  2. package/LICENSE +21 -21
  3. package/README.md +293 -289
  4. package/assets/icon-dark.svg +9 -9
  5. package/assets/icon.svg +9 -9
  6. package/assets/logo-dark.svg +11 -11
  7. package/assets/logo-light.svg +11 -11
  8. package/dashboard/README.md +91 -91
  9. package/dashboard/dist/assets/{index-D6Xyje_n.js → index-jmYe6rmS.js} +2 -2
  10. package/dashboard/dist/assets/index-jmYe6rmS.js.map +1 -0
  11. package/dashboard/dist/index.html +20 -20
  12. package/dashboard/package.json +47 -47
  13. package/dist/activities/outbox.d.ts +30 -1
  14. package/dist/activities/outbox.js +96 -3
  15. package/dist/adapters/base.js +5 -0
  16. package/dist/adapters/copilot/adapter.js +12 -1
  17. package/dist/adapters/index.d.ts +1 -1
  18. package/dist/adapters/index.js +7 -0
  19. package/dist/adapters/pi/adapter.d.ts +2 -0
  20. package/dist/adapters/pi/adapter.js +43 -0
  21. package/dist/adapters/pi/index.d.ts +16 -0
  22. package/dist/adapters/pi/index.js +10 -0
  23. package/dist/cli/global-wrapper.d.ts +19 -0
  24. package/dist/cli/global-wrapper.js +169 -0
  25. package/dist/cli/help-text.js +97 -97
  26. package/dist/cli/startup.js +11 -0
  27. package/dist/cli/upgrade-command.js +81 -81
  28. package/dist/cli.js +12 -0
  29. package/dist/client/core.js +9 -2
  30. package/dist/client/interface.d.ts +6 -0
  31. package/dist/config.d.ts +79 -0
  32. package/dist/config.js +74 -0
  33. package/dist/daemon.js +37 -1
  34. package/dist/http/aggregate.d.ts +22 -1
  35. package/dist/http/aggregate.js +41 -0
  36. package/dist/http/auth.d.ts +94 -8
  37. package/dist/http/auth.js +93 -9
  38. package/dist/http/body.d.ts +4 -1
  39. package/dist/http/body.js +6 -3
  40. package/dist/http/event-bus.js +1 -0
  41. package/dist/http/event-types.d.ts +34 -2
  42. package/dist/http/event-types.js +1 -0
  43. package/dist/http/gate-audit.d.ts +12 -0
  44. package/dist/http/gate-audit.js +95 -0
  45. package/dist/http/gate-registry.d.ts +167 -0
  46. package/dist/http/gate-registry.js +163 -0
  47. package/dist/http/gate-routes.d.ts +48 -0
  48. package/dist/http/gate-routes.js +102 -0
  49. package/dist/http/ingest-registry.d.ts +30 -0
  50. package/dist/http/ingest-registry.js +108 -0
  51. package/dist/http/inner-loop-routes.d.ts +66 -0
  52. package/dist/http/inner-loop-routes.js +182 -0
  53. package/dist/http/inner-loop.d.ts +92 -0
  54. package/dist/http/inner-loop.js +155 -0
  55. package/dist/http/server.d.ts +38 -3
  56. package/dist/http/server.js +211 -6
  57. package/dist/http/snapshot.d.ts +6 -0
  58. package/dist/http/snapshot.js +6 -0
  59. package/dist/pi/cue-pump.d.ts +61 -0
  60. package/dist/pi/cue-pump.js +95 -0
  61. package/dist/pi/extension.d.ts +45 -0
  62. package/dist/pi/extension.js +407 -0
  63. package/dist/pi/gate-client.d.ts +54 -0
  64. package/dist/pi/gate-client.js +136 -0
  65. package/dist/pi/headless.d.ts +85 -0
  66. package/dist/pi/headless.js +224 -0
  67. package/dist/pi/index.d.ts +28 -0
  68. package/dist/pi/index.js +43 -0
  69. package/dist/pi/inner-loop-client.d.ts +67 -0
  70. package/dist/pi/inner-loop-client.js +164 -0
  71. package/dist/pi/inner-loop-publisher.d.ts +187 -0
  72. package/dist/pi/inner-loop-publisher.js +236 -0
  73. package/dist/pi/lazy-proxy.d.ts +37 -0
  74. package/dist/pi/lazy-proxy.js +55 -0
  75. package/dist/pi/mission-control/actions.d.ts +48 -0
  76. package/dist/pi/mission-control/actions.js +98 -0
  77. package/dist/pi/mission-control/board.d.ts +53 -0
  78. package/dist/pi/mission-control/board.js +104 -0
  79. package/dist/pi/mission-control/extension.d.ts +44 -0
  80. package/dist/pi/mission-control/extension.js +251 -0
  81. package/dist/pi/mission-control/index.d.ts +15 -0
  82. package/dist/pi/mission-control/index.js +32 -0
  83. package/dist/pi/mission-control/inner-tail.d.ts +48 -0
  84. package/dist/pi/mission-control/inner-tail.js +76 -0
  85. package/dist/pi/mission-control/pi-ui.d.ts +43 -0
  86. package/dist/pi/mission-control/pi-ui.js +10 -0
  87. package/dist/pi/mission-control/render.d.ts +6 -0
  88. package/dist/pi/mission-control/render.js +95 -0
  89. package/dist/pi/phase-driver.d.ts +74 -0
  90. package/dist/pi/phase-driver.js +122 -0
  91. package/dist/pi/pi-types.d.ts +208 -0
  92. package/dist/pi/pi-types.js +21 -0
  93. package/dist/pi/probe.d.ts +80 -0
  94. package/dist/pi/probe.js +154 -0
  95. package/dist/pi/render-tools.d.ts +17 -0
  96. package/dist/pi/render-tools.js +51 -0
  97. package/dist/pi/reset-pump.d.ts +47 -0
  98. package/dist/pi/reset-pump.js +85 -0
  99. package/dist/pi/tool-capability.d.ts +60 -0
  100. package/dist/pi/tool-capability.js +156 -0
  101. package/dist/pi/workflow-client.d.ts +158 -0
  102. package/dist/pi/workflow-client.js +289 -0
  103. package/dist/pi/zod-to-typebox.d.ts +74 -0
  104. package/dist/pi/zod-to-typebox.js +191 -0
  105. package/dist/scripts/verify-daemon-isolation-guard.js +24 -24
  106. package/dist/server-tools.d.ts +2 -0
  107. package/dist/server-tools.js +50 -46
  108. package/dist/server.js +4 -0
  109. package/dist/spawn.d.ts +55 -0
  110. package/dist/spawn.js +84 -12
  111. package/dist/tools/agent-types.d.ts +2 -2
  112. package/dist/tools/agent-types.js +22 -17
  113. package/dist/tools/attachment-info.d.ts +2 -2
  114. package/dist/tools/attachment-info.js +38 -33
  115. package/dist/tools/broadcast.d.ts +2 -2
  116. package/dist/tools/broadcast.js +69 -64
  117. package/dist/tools/cancel-stage.d.ts +2 -2
  118. package/dist/tools/cancel-stage.js +20 -15
  119. package/dist/tools/clear-state.d.ts +2 -2
  120. package/dist/tools/clear-state.js +25 -20
  121. package/dist/tools/coat-check-evict.d.ts +2 -2
  122. package/dist/tools/coat-check-evict.js +30 -25
  123. package/dist/tools/coat-check-get.d.ts +2 -2
  124. package/dist/tools/coat-check-get.js +39 -34
  125. package/dist/tools/coat-check-list.d.ts +2 -2
  126. package/dist/tools/coat-check-list.js +48 -43
  127. package/dist/tools/coat-check-put.d.ts +2 -2
  128. package/dist/tools/coat-check-put.js +41 -36
  129. package/dist/tools/cue.d.ts +2 -2
  130. package/dist/tools/cue.js +57 -52
  131. package/dist/tools/descriptor.d.ts +72 -0
  132. package/dist/tools/descriptor.js +39 -0
  133. package/dist/tools/destroy.d.ts +2 -2
  134. package/dist/tools/destroy.js +153 -148
  135. package/dist/tools/ensemble.d.ts +2 -2
  136. package/dist/tools/ensemble.js +71 -66
  137. package/dist/tools/evaluate-gate.d.ts +2 -2
  138. package/dist/tools/evaluate-gate.js +33 -27
  139. package/dist/tools/fetch-state.d.ts +2 -2
  140. package/dist/tools/fetch-state.js +43 -38
  141. package/dist/tools/gates.d.ts +2 -2
  142. package/dist/tools/gates.js +39 -34
  143. package/dist/tools/hosts.d.ts +2 -2
  144. package/dist/tools/hosts.js +25 -20
  145. package/dist/tools/listen.d.ts +2 -2
  146. package/dist/tools/listen.js +23 -18
  147. package/dist/tools/load-lineup.d.ts +2 -2
  148. package/dist/tools/load-lineup.js +324 -319
  149. package/dist/tools/migrate.d.ts +2 -2
  150. package/dist/tools/migrate.js +45 -40
  151. package/dist/tools/pause.d.ts +2 -2
  152. package/dist/tools/pause.js +34 -29
  153. package/dist/tools/play.d.ts +2 -2
  154. package/dist/tools/play.js +53 -48
  155. package/dist/tools/quality-gate.d.ts +2 -2
  156. package/dist/tools/quality-gate.js +26 -21
  157. package/dist/tools/recall.d.ts +2 -2
  158. package/dist/tools/recall.js +32 -27
  159. package/dist/tools/recruit.d.ts +2 -2
  160. package/dist/tools/recruit.js +325 -256
  161. package/dist/tools/release.d.ts +2 -2
  162. package/dist/tools/release.js +85 -80
  163. package/dist/tools/report.d.ts +2 -2
  164. package/dist/tools/report.js +28 -23
  165. package/dist/tools/reset.d.ts +3 -0
  166. package/dist/tools/reset.js +51 -0
  167. package/dist/tools/restart.d.ts +2 -2
  168. package/dist/tools/restart.js +51 -46
  169. package/dist/tools/restore.d.ts +2 -2
  170. package/dist/tools/restore.js +76 -71
  171. package/dist/tools/save-lineup.d.ts +2 -2
  172. package/dist/tools/save-lineup.js +32 -27
  173. package/dist/tools/save-state.d.ts +2 -2
  174. package/dist/tools/save-state.js +43 -38
  175. package/dist/tools/schedule.d.ts +2 -2
  176. package/dist/tools/schedule.js +133 -128
  177. package/dist/tools/schedules.d.ts +2 -2
  178. package/dist/tools/schedules.js +41 -36
  179. package/dist/tools/set-ensemble-description.d.ts +2 -2
  180. package/dist/tools/set-ensemble-description.js +26 -21
  181. package/dist/tools/set-name.d.ts +2 -2
  182. package/dist/tools/set-name.js +38 -33
  183. package/dist/tools/set-part.d.ts +2 -2
  184. package/dist/tools/set-part.js +20 -15
  185. package/dist/tools/shutdown.d.ts +2 -2
  186. package/dist/tools/shutdown.js +39 -34
  187. package/dist/tools/stage.d.ts +2 -2
  188. package/dist/tools/stage.js +28 -23
  189. package/dist/tools/stages.d.ts +2 -2
  190. package/dist/tools/stages.js +36 -31
  191. package/dist/tools/unschedule.d.ts +2 -2
  192. package/dist/tools/unschedule.js +30 -25
  193. package/dist/tools/who-am-i.d.ts +2 -2
  194. package/dist/tools/who-am-i.js +36 -31
  195. package/dist/tools/worktree.d.ts +2 -2
  196. package/dist/tools/worktree.js +134 -129
  197. package/dist/tui/index.js +6 -6
  198. package/dist/types.d.ts +47 -2
  199. package/dist/types.js +1 -1
  200. package/dist/utils/default-part.js +1 -0
  201. package/dist/utils/grpc-shutdown-guard.d.ts +52 -0
  202. package/dist/utils/grpc-shutdown-guard.js +88 -0
  203. package/dist/utils/sdk-probe.d.ts +23 -0
  204. package/dist/utils/sdk-probe.js +46 -7
  205. package/dist/worker.d.ts +3 -1
  206. package/dist/worker.js +6 -2
  207. package/dist/workflows/session.js +70 -2
  208. package/dist/workflows/signals.d.ts +32 -2
  209. package/dist/workflows/signals.js +25 -2
  210. package/examples/agents/tempo-composer.md +56 -56
  211. package/examples/agents/tempo-conductor.md +117 -117
  212. package/examples/agents/tempo-critic.md +73 -73
  213. package/examples/agents/tempo-improv.md +74 -74
  214. package/examples/agents/tempo-liner.md +75 -75
  215. package/examples/agents/tempo-roadie.md +61 -61
  216. package/examples/agents/tempo-soloist.md +71 -71
  217. package/examples/agents/tempo-tuner.md +94 -94
  218. package/examples/ensembles/tempo-big-band.yaml +146 -146
  219. package/examples/ensembles/tempo-dev-team.yaml +58 -58
  220. package/examples/ensembles/tempo-headless-jam.yaml +77 -77
  221. package/examples/ensembles/tempo-jam-session.yaml +41 -41
  222. package/examples/ensembles/tempo-mock-jam.yaml +79 -79
  223. package/examples/ensembles/tempo-review-squad.yaml +32 -32
  224. package/package.json +176 -173
  225. package/packaging/launchd/com.agent.tempo.plist +46 -46
  226. package/packaging/systemd/agent-tempo.service +32 -32
  227. package/packaging/windows/install-task.ps1 +71 -71
  228. package/scenarios/conductor-recruit-mock.yaml +33 -33
  229. package/scenarios/echo-roundtrip.yaml +15 -15
  230. package/scenarios/multi-player-handoff.yaml +38 -38
  231. package/scenarios/recruit-cascade.yaml +38 -38
  232. package/scenarios/two-player-conversation.yaml +33 -33
  233. package/workflow-bundle.js +97 -6
  234. package/dashboard/dist/assets/index-D6Xyje_n.js.map +0 -1
  235. package/dist/activities/claude-stop.d.ts +0 -21
  236. package/dist/activities/claude-stop.js +0 -94
  237. package/dist/channel.d.ts +0 -3
  238. package/dist/channel.js +0 -48
  239. package/dist/copilot-bridge.d.ts +0 -22
  240. package/dist/copilot-bridge.js +0 -565
  241. package/dist/scripts/258-spotcheck.js +0 -303
  242. package/dist/tools/detach.d.ts +0 -4
  243. package/dist/tools/detach.js +0 -45
  244. package/dist/tools/encore.d.ts +0 -4
  245. package/dist/tools/encore.js +0 -31
  246. package/dist/tools/helpers.d.ts +0 -21
  247. package/dist/tools/helpers.js +0 -25
  248. package/dist/tools/pause-ensemble.d.ts +0 -4
  249. package/dist/tools/pause-ensemble.js +0 -58
  250. package/dist/tools/resume-ensemble.d.ts +0 -4
  251. package/dist/tools/resume-ensemble.js +0 -79
  252. package/dist/tools/stop.d.ts +0 -4
  253. package/dist/tools/stop.js +0 -29
  254. package/dist/tui/client.d.ts +0 -6
  255. package/dist/tui/client.js +0 -9
  256. package/dist/tui/components/ActivityLog.d.ts +0 -16
  257. package/dist/tui/components/ActivityLog.js +0 -36
  258. package/dist/tui/components/CommandOverlay.d.ts +0 -15
  259. package/dist/tui/components/CommandOverlay.js +0 -34
  260. package/dist/tui/components/ConductorChat.d.ts +0 -16
  261. package/dist/tui/components/ConductorChat.js +0 -32
  262. package/dist/tui/components/EnsembleListView.d.ts +0 -14
  263. package/dist/tui/components/EnsembleListView.js +0 -32
  264. package/dist/tui/components/EnsemblePanel.d.ts +0 -12
  265. package/dist/tui/components/EnsemblePanel.js +0 -40
  266. package/dist/tui/components/InputBar.d.ts +0 -13
  267. package/dist/tui/components/InputBar.js +0 -58
  268. package/dist/tui/components/ScheduleOverlay.d.ts +0 -13
  269. package/dist/tui/components/ScheduleOverlay.js +0 -113
  270. package/dist/tui/components/TopBar.d.ts +0 -12
  271. package/dist/tui/components/TopBar.js +0 -15
  272. package/dist/tui/core-api.d.ts +0 -26
  273. package/dist/tui/core-api.js +0 -67
  274. package/dist/tui/hooks/useEnsembleDiscovery.d.ts +0 -3
  275. package/dist/tui/hooks/useEnsembleDiscovery.js +0 -30
  276. package/dist/tui/hooks/useMaestroPoller.d.ts +0 -3
  277. package/dist/tui/hooks/useMaestroPoller.js +0 -36
  278. package/dist/tui/hooks/useSendCommand.d.ts +0 -7
  279. package/dist/tui/hooks/useSendCommand.js +0 -29
  280. package/dist/utils/bg-preflight.d.ts +0 -25
  281. package/dist/utils/bg-preflight.js +0 -154
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerRestoreTool = registerRestoreTool;
3
+ exports.buildRestoreTool = buildRestoreTool;
4
4
  /**
5
5
  * `restore` — ensemble-wide revive (#287).
6
6
  *
@@ -28,80 +28,85 @@ const os_1 = require("os");
28
28
  const zod_1 = require("zod");
29
29
  const orphans_1 = require("../reconcile/orphans");
30
30
  const signals_1 = require("../workflows/signals");
31
- const helpers_1 = require("./helpers");
31
+ const descriptor_1 = require("./descriptor");
32
32
  const ensemble_ops_1 = require("../utils/ensemble-ops");
33
33
  const log = (...args) => console.error('[agent-tempo:restore]', ...args);
34
- function registerRestoreTool(server, client, config, getPlayerId) {
35
- (0, helpers_1.defineTool)(server, 'restore', 'Revive the ensemble after `shutdown`: reattach orphaned sessions and unpause the maestro + scheduler. Defaults to scanning the local host; pass `hostname` to target a remote machine in distributed setups (per-host task queues). Does NOT spawn a conductor terminal — use the CLI for that.', {
36
- // #306 follow-up: cross-host restore. The default (omitted) preserves
37
- // the original behavior scan the local daemon's host. When supplied,
38
- // we route the orphan-visibility query against the named host's
39
- // `AgentTempoAttachedHost`/`AgentTempoHostname` search attributes,
40
- // so an operator on host A can revive sessions parked on host B.
41
- // Surfaced from my own #306 review (regression risk #2): "MCP
42
- // restore hard-codes hostname: osHostname() — won't see orphans on
43
- // other hosts in distributed setups."
44
- hostname: zod_1.z.string().min(1).max(253).optional().describe('Target host whose orphans should be restored. Defaults to the local OS hostname. Use this when the conductor / TUI is on a different machine than the workers that owned the parked sessions.'),
45
- }, async (args) => {
46
- const { hostname: explicitHostname } = args;
47
- const targetHostname = explicitHostname ?? (0, os_1.hostname)();
48
- try {
49
- let summary;
34
+ function buildRestoreTool(client, config, getPlayerId) {
35
+ return {
36
+ name: 'restore',
37
+ description: 'Revive the ensemble after `shutdown`: reattach orphaned sessions and unpause the maestro + scheduler. Defaults to scanning the local host; pass `hostname` to target a remote machine in distributed setups (per-host task queues). Does NOT spawn a conductor terminal — use the CLI for that.',
38
+ params: {
39
+ // #306 follow-up: cross-host restore. The default (omitted) preserves
40
+ // the original behavior scan the local daemon's host. When supplied,
41
+ // we route the orphan-visibility query against the named host's
42
+ // `AgentTempoAttachedHost`/`AgentTempoHostname` search attributes,
43
+ // so an operator on host A can revive sessions parked on host B.
44
+ // Surfaced from my own #306 review (regression risk #2): "MCP
45
+ // restore hard-codes hostname: osHostname() won't see orphans on
46
+ // other hosts in distributed setups."
47
+ hostname: zod_1.z.string().min(1).max(253).optional().describe('Target host whose orphans should be restored. Defaults to the local OS hostname. Use this when the conductor / TUI is on a different machine than the workers that owned the parked sessions.'),
48
+ },
49
+ handler: async (args) => {
50
+ const { hostname: explicitHostname } = args;
51
+ const targetHostname = explicitHostname ?? (0, os_1.hostname)();
50
52
  try {
51
- summary = await (0, orphans_1.restoreOrphansOnce)(client, {
52
- hostname: targetHostname,
53
- invokerPlayerId: getPlayerId(),
54
- policy: 'auto',
55
- // #306: narrow to detached-only so a live attached/processing
56
- // session is never flagged as an orphan by user-invoked
57
- // `/restore`. Daemon reconcile-on-boot + CLI `up --resume`
58
- // keep the broad live-phase default (no PID memory after
59
- // crash must treat every live phase as presumed orphan).
60
- phases: ['detached'],
61
- }, log);
53
+ let summary;
54
+ try {
55
+ summary = await (0, orphans_1.restoreOrphansOnce)(client, {
56
+ hostname: targetHostname,
57
+ invokerPlayerId: getPlayerId(),
58
+ policy: 'auto',
59
+ // #306: narrow to detached-only so a live attached/processing
60
+ // session is never flagged as an orphan by user-invoked
61
+ // `/restore`. Daemon reconcile-on-boot + CLI `up --resume`
62
+ // keep the broad live-phase default (no PID memory after
63
+ // crash → must treat every live phase as presumed orphan).
64
+ phases: ['detached'],
65
+ }, log);
66
+ }
67
+ catch (err) {
68
+ return (0, descriptor_1.fail)(`Failed to scan for orphans: ${(0, descriptor_1.formatError)(err)}`);
69
+ }
70
+ // Maestro/scheduler hub unpause + per-session `setPaused=false`
71
+ // fan-out run in parallel — independent calls and a slow session
72
+ // shouldn't gate the hub toggle (or vice-versa).
73
+ const [toggle, sessions] = await Promise.all([
74
+ (0, ensemble_ops_1.unpauseMaestroAndScheduler)(client, config.ensemble),
75
+ (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, false),
76
+ ]);
77
+ const hostSuffix = explicitHostname !== undefined
78
+ ? ` (host: ${explicitHostname})`
79
+ : '';
80
+ const lines = [
81
+ `Ensemble **${config.ensemble}** restored${hostSuffix}.`,
82
+ `${summary.reattached} reattached, ${summary.skipped} skipped, ${summary.failed} failed`,
83
+ ];
84
+ if (summary.details.length > 0) {
85
+ lines.push(...summary.details.map((d) => ` - ${d.playerId} (${d.ensemble}): ${(0, orphans_1.formatRestoreOutcome)(d.outcome)}`));
86
+ }
87
+ if (sessions.sent > 0) {
88
+ lines.push(`${sessions.sent} session(s) resumed`);
89
+ }
90
+ const unpausedBits = [];
91
+ if (toggle.maestro)
92
+ unpausedBits.push('maestro');
93
+ if (toggle.scheduler)
94
+ unpausedBits.push('scheduler');
95
+ if (unpausedBits.length > 0)
96
+ lines.push(`Unpaused: ${unpausedBits.join(', ')}`);
97
+ if (sessions.failed > 0) {
98
+ const errs = sessions.perSession
99
+ .filter((p) => p.outcome === 'failed')
100
+ .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
101
+ lines.push(`Errors:\n${errs.join('\n')}`);
102
+ }
103
+ log(`Restore by ${getPlayerId()} in "${config.ensemble}" on host "${targetHostname}": ` +
104
+ `${summary.reattached}/${summary.skipped}/${summary.failed}`);
105
+ return (0, descriptor_1.ok)(lines.join('\n'));
62
106
  }
63
107
  catch (err) {
64
- return (0, helpers_1.fail)(`Failed to scan for orphans: ${(0, helpers_1.formatError)(err)}`);
108
+ return (0, descriptor_1.fail)(`Failed to restore ensemble: ${(0, descriptor_1.formatError)(err)}`);
65
109
  }
66
- // Maestro/scheduler hub unpause + per-session `setPaused=false`
67
- // fan-out run in parallel — independent calls and a slow session
68
- // shouldn't gate the hub toggle (or vice-versa).
69
- const [toggle, sessions] = await Promise.all([
70
- (0, ensemble_ops_1.unpauseMaestroAndScheduler)(client, config.ensemble),
71
- (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, false),
72
- ]);
73
- const hostSuffix = explicitHostname !== undefined
74
- ? ` (host: ${explicitHostname})`
75
- : '';
76
- const lines = [
77
- `Ensemble **${config.ensemble}** restored${hostSuffix}.`,
78
- `${summary.reattached} reattached, ${summary.skipped} skipped, ${summary.failed} failed`,
79
- ];
80
- if (summary.details.length > 0) {
81
- lines.push(...summary.details.map((d) => ` - ${d.playerId} (${d.ensemble}): ${(0, orphans_1.formatRestoreOutcome)(d.outcome)}`));
82
- }
83
- if (sessions.sent > 0) {
84
- lines.push(`${sessions.sent} session(s) resumed`);
85
- }
86
- const unpausedBits = [];
87
- if (toggle.maestro)
88
- unpausedBits.push('maestro');
89
- if (toggle.scheduler)
90
- unpausedBits.push('scheduler');
91
- if (unpausedBits.length > 0)
92
- lines.push(`Unpaused: ${unpausedBits.join(', ')}`);
93
- if (sessions.failed > 0) {
94
- const errs = sessions.perSession
95
- .filter((p) => p.outcome === 'failed')
96
- .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
97
- lines.push(`Errors:\n${errs.join('\n')}`);
98
- }
99
- log(`Restore by ${getPlayerId()} in "${config.ensemble}" on host "${targetHostname}": ` +
100
- `${summary.reattached}/${summary.skipped}/${summary.failed}`);
101
- return (0, helpers_1.ok)(lines.join('\n'));
102
- }
103
- catch (err) {
104
- return (0, helpers_1.fail)(`Failed to restore ensemble: ${(0, helpers_1.formatError)(err)}`);
105
- }
106
- });
110
+ },
111
+ };
107
112
  }
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { Client } from '@temporalio/client';
3
2
  import { Config } from '../config';
4
- export declare function registerSaveLineupTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string, isConductor: boolean): void;
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ export declare function buildSaveLineupTool(client: Client, config: Config, getPlayerId: () => string, isConductor: boolean): TempoToolDescriptor;
@@ -1,36 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerSaveLineupTool = registerSaveLineupTool;
3
+ exports.buildSaveLineupTool = buildSaveLineupTool;
4
4
  const zod_1 = require("zod");
5
5
  const saver_1 = require("../ensemble/saver");
6
6
  const safe_path_1 = require("../utils/safe-path");
7
- const helpers_1 = require("./helpers");
7
+ const descriptor_1 = require("./descriptor");
8
8
  const validation_1 = require("../utils/validation");
9
9
  const log = (...args) => console.error('[agent-tempo:save-lineup]', ...args);
10
- function registerSaveLineupTool(server, client, config, getPlayerId, isConductor) {
11
- (0, helpers_1.defineTool)(server, 'save_lineup', 'Save the current ensemble state as a YAML lineup. Only available to the conductor.', {
12
- name: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).optional().describe('Lineup name (defaults to ensemble name)'),
13
- path: zod_1.z.string().max(validation_1.PATH_MAX).optional().describe('Explicit file path to save to'),
14
- }, async (args) => {
15
- if (!isConductor) {
16
- return (0, helpers_1.fail)('Only the conductor can save ensemble lineups.');
17
- }
18
- const lineupName = args.name;
19
- const filePath = args.path;
20
- try {
21
- // Validate user-supplied path if provided
22
- let validatedPath = filePath;
23
- if (validatedPath) {
24
- validatedPath = (0, safe_path_1.safeLineupPath)(validatedPath, process.cwd());
10
+ function buildSaveLineupTool(client, config, getPlayerId, isConductor) {
11
+ return {
12
+ name: 'save_lineup',
13
+ description: 'Save the current ensemble state as a YAML lineup. Only available to the conductor.',
14
+ params: {
15
+ name: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).optional().describe('Lineup name (defaults to ensemble name)'),
16
+ path: zod_1.z.string().max(validation_1.PATH_MAX).optional().describe('Explicit file path to save to'),
17
+ },
18
+ handler: async (args) => {
19
+ if (!isConductor) {
20
+ return (0, descriptor_1.fail)('Only the conductor can save ensemble lineups.');
25
21
  }
26
- // Pass lineupName as optional name override for the output filename.
27
- // If no name or path is provided, saveLineup defaults to ensemble name.
28
- const outputPath = await (0, saver_1.saveLineup)(client, config.ensemble, validatedPath, lineupName);
29
- log(`Saved lineup to ${outputPath}`);
30
- return (0, helpers_1.ok)(`Ensemble lineup saved to **${outputPath}**.`);
31
- }
32
- catch (err) {
33
- return (0, helpers_1.fail)(`Failed to save ensemble: ${(0, helpers_1.formatError)(err)}`);
34
- }
35
- });
22
+ const lineupName = args.name;
23
+ const filePath = args.path;
24
+ try {
25
+ // Validate user-supplied path if provided
26
+ let validatedPath = filePath;
27
+ if (validatedPath) {
28
+ validatedPath = (0, safe_path_1.safeLineupPath)(validatedPath, process.cwd());
29
+ }
30
+ // Pass lineupName as optional name override for the output filename.
31
+ // If no name or path is provided, saveLineup defaults to ensemble name.
32
+ const outputPath = await (0, saver_1.saveLineup)(client, config.ensemble, validatedPath, lineupName);
33
+ log(`Saved lineup to ${outputPath}`);
34
+ return (0, descriptor_1.ok)(`Ensemble lineup saved to **${outputPath}**.`);
35
+ }
36
+ catch (err) {
37
+ return (0, descriptor_1.fail)(`Failed to save ensemble: ${(0, descriptor_1.formatError)(err)}`);
38
+ }
39
+ },
40
+ };
36
41
  }
@@ -1,3 +1,3 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { WorkflowHandle } from '@temporalio/client';
3
- export declare function registerSaveStateTool(server: McpServer, handle: WorkflowHandle, getPlayerId: () => string): void;
2
+ import { type TempoToolDescriptor } from './descriptor';
3
+ export declare function buildSaveStateTool(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerSaveStateTool = registerSaveStateTool;
3
+ exports.buildSaveStateTool = buildSaveStateTool;
4
4
  /**
5
5
  * `save_state` — write a curated artifact to one of the calling player's
6
6
  * saveable-state slots (#334 PR-1, ADR 0011).
@@ -16,42 +16,47 @@ exports.registerSaveStateTool = registerSaveStateTool;
16
16
  */
17
17
  const zod_1 = require("zod");
18
18
  const signals_1 = require("../workflows/signals");
19
- const helpers_1 = require("./helpers");
19
+ const descriptor_1 = require("./descriptor");
20
20
  const validation_1 = require("../utils/validation");
21
- function registerSaveStateTool(server, handle, getPlayerId) {
22
- (0, helpers_1.defineTool)(server, 'save_state', `Save curated state for yourself into a named slot — a peer can later read it via \`fetch_state\`, and a future restart can seed itself from this artifact instead of replaying the transcript.
23
-
24
- Recommended structure (markdown, not enforced):
25
-
26
- ## Current task
27
- ...
28
- ## Findings
29
- ...
30
- ## Next steps
31
- ...
32
- ## Open questions
33
- ...
34
-
35
- Limits: ${validation_1.PLAYER_STATE_CONTENT_MAX} bytes per slot, max ${validation_1.PLAYER_STATE_SLOTS_MAX} slots per player. Slot key defaults to "${validation_1.PLAYER_STATE_DEFAULT_KEY}". When all ${validation_1.PLAYER_STATE_SLOTS_MAX} slots are full, saving a new key fails with \`PlayerStateSlotsFull\` — call \`clear_state\` to free a slot.`, {
36
- content: zod_1.z.string().min(1).max(validation_1.PLAYER_STATE_CONTENT_MAX).describe(`The state content — markdown encouraged, opaque to the system. Max ${validation_1.PLAYER_STATE_CONTENT_MAX} bytes (UTF-8).`),
37
- key: zod_1.z.string().regex(validation_1.PLAYER_STATE_KEY_REGEX).max(validation_1.PLAYER_STATE_KEY_MAX).optional().describe(`Slot name (default "${validation_1.PLAYER_STATE_DEFAULT_KEY}"). Alphanumeric + underscore + hyphen, max ${validation_1.PLAYER_STATE_KEY_MAX} chars.`),
38
- }, async (args) => {
39
- const { content, key } = args;
40
- const slotKey = key ?? validation_1.PLAYER_STATE_DEFAULT_KEY;
41
- const savedBy = getPlayerId();
42
- try {
43
- const result = await handle.executeUpdate(signals_1.savePlayerStateUpdate, {
44
- args: [{ key: slotKey, content, savedBy }],
45
- });
46
- return (0, helpers_1.ok)(`Saved to slot **"${slotKey}"** at ${result.savedAt}.`);
47
- }
48
- catch (err) {
49
- // The workflow validator surfaces structured ApplicationFailure errors
50
- // (`PlayerStateSlotsFull`, `PlayerStateContentTooLarge`,
51
- // `PlayerStateInvalidKey`). The `formatError` message preserves the
52
- // workflow-supplied text so the LLM sees the existing-keys list and
53
- // can pick which slot to clear.
54
- return (0, helpers_1.fail)(`Failed to save state: ${(0, helpers_1.formatError)(err)}`);
55
- }
56
- });
21
+ function buildSaveStateTool(handle, getPlayerId) {
22
+ return {
23
+ name: 'save_state',
24
+ description: `Save curated state for yourself into a named slot — a peer can later read it via \`fetch_state\`, and a future restart can seed itself from this artifact instead of replaying the transcript.
25
+
26
+ Recommended structure (markdown, not enforced):
27
+
28
+ ## Current task
29
+ ...
30
+ ## Findings
31
+ ...
32
+ ## Next steps
33
+ ...
34
+ ## Open questions
35
+ ...
36
+
37
+ Limits: ${validation_1.PLAYER_STATE_CONTENT_MAX} bytes per slot, max ${validation_1.PLAYER_STATE_SLOTS_MAX} slots per player. Slot key defaults to "${validation_1.PLAYER_STATE_DEFAULT_KEY}". When all ${validation_1.PLAYER_STATE_SLOTS_MAX} slots are full, saving a new key fails with \`PlayerStateSlotsFull\` — call \`clear_state\` to free a slot.`,
38
+ params: {
39
+ content: zod_1.z.string().min(1).max(validation_1.PLAYER_STATE_CONTENT_MAX).describe(`The state content — markdown encouraged, opaque to the system. Max ${validation_1.PLAYER_STATE_CONTENT_MAX} bytes (UTF-8).`),
40
+ key: zod_1.z.string().regex(validation_1.PLAYER_STATE_KEY_REGEX).max(validation_1.PLAYER_STATE_KEY_MAX).optional().describe(`Slot name (default "${validation_1.PLAYER_STATE_DEFAULT_KEY}"). Alphanumeric + underscore + hyphen, max ${validation_1.PLAYER_STATE_KEY_MAX} chars.`),
41
+ },
42
+ handler: async (args) => {
43
+ const { content, key } = args;
44
+ const slotKey = key ?? validation_1.PLAYER_STATE_DEFAULT_KEY;
45
+ const savedBy = getPlayerId();
46
+ try {
47
+ const result = await handle.executeUpdate(signals_1.savePlayerStateUpdate, {
48
+ args: [{ key: slotKey, content, savedBy }],
49
+ });
50
+ return (0, descriptor_1.ok)(`Saved to slot **"${slotKey}"** at ${result.savedAt}.`);
51
+ }
52
+ catch (err) {
53
+ // The workflow validator surfaces structured ApplicationFailure errors
54
+ // (`PlayerStateSlotsFull`, `PlayerStateContentTooLarge`,
55
+ // `PlayerStateInvalidKey`). The `formatError` message preserves the
56
+ // workflow-supplied text so the LLM sees the existing-keys list and
57
+ // can pick which slot to clear.
58
+ return (0, descriptor_1.fail)(`Failed to save state: ${(0, descriptor_1.formatError)(err)}`);
59
+ }
60
+ },
61
+ };
57
62
  }
@@ -1,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { Client } from '@temporalio/client';
3
2
  import { Config } from '../config';
4
- export declare function registerScheduleTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string): void;
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ export declare function buildScheduleTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;