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,4 +1,4 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { Client, WorkflowHandle } from '@temporalio/client';
3
2
  import { Config } from '../config';
4
- export declare function registerMigrateTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle): void;
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ export declare function buildMigrateTool(client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle): TempoToolDescriptor;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerMigrateTool = registerMigrateTool;
3
+ exports.buildMigrateTool = buildMigrateTool;
4
4
  /**
5
5
  * `migrate` — sugar for `restart --host=<h>` per design §9.6.
6
6
  *
@@ -16,45 +16,50 @@ exports.registerMigrateTool = registerMigrateTool;
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 restart_1 = require("./restart");
21
21
  const validation_1 = require("../utils/validation");
22
- function registerMigrateTool(server, client, config, getPlayerId, handle) {
23
- (0, helpers_1.defineTool)(server, 'migrate', 'Migrate a session to a different host — sugar for `restart` with a required `host`. Reaps the current attachment, claims fresh on the target host, spawns a new adapter. Cross-host routing (per-host task queues) is honored automatically. When `force=true` AND the target is currently on a different host, `confirmStealFromHost` must match that hostname (design §16.5).', {
24
- playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player name to migrate'),
25
- host: zod_1.z.string().min(1).describe('Target hostname required'),
26
- fresh: zod_1.z.boolean().optional().describe('Skip context replay (default false)'),
27
- force: zod_1.z.boolean().optional().describe('Steal a live attachment via forceDetach (default false)'),
28
- contextMessages: zod_1.z.number().min(0).max(validation_1.RESTART_CONTEXT_MESSAGES_MAX).optional().describe('Number of recent messages to include in context (default 10)'),
29
- confirmStealFromHost: zod_1.z.string().optional().describe('Required when `force=true` and the target\'s current attachment is on a different host (design §16.5 Option B).'),
30
- }, async (args) => {
31
- const input = args;
32
- const nameError = (0, validation_1.validatePlayerName)(input.playerId);
33
- if (nameError)
34
- return (0, helpers_1.fail)(nameError);
35
- if (!input.host || !input.host.trim()) {
36
- return (0, helpers_1.fail)('`host` is required for migrate. Use `restart` (without host) to restart on the session\'s current host.');
37
- }
38
- // Shared cross-host guard with `restart` — same rules, same copy-paste
39
- // error messages (§16.5).
40
- const guardError = await (0, restart_1.enforceYesStealGuard)(client, config.ensemble, input.playerId, input);
41
- if (guardError)
42
- return (0, helpers_1.fail)(guardError);
43
- try {
44
- const entry = {
45
- type: 'restart',
46
- targetPlayerId: input.playerId,
47
- invokerPlayerId: getPlayerId(),
48
- host: input.host,
49
- ...(input.fresh !== undefined ? { fresh: input.fresh } : {}),
50
- ...(input.force !== undefined ? { force: input.force } : {}),
51
- ...(input.contextMessages !== undefined ? { contextMessages: input.contextMessages } : {}),
52
- };
53
- const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
54
- return (0, helpers_1.ok)(`Migrate queued for **${input.playerId}** ${input.host}. (outbox: ${entryId})`);
55
- }
56
- catch (err) {
57
- return (0, helpers_1.fail)(`Failed to migrate: ${(0, helpers_1.formatError)(err)}`);
58
- }
59
- });
22
+ function buildMigrateTool(client, config, getPlayerId, handle) {
23
+ return {
24
+ name: 'migrate',
25
+ description: 'Migrate a session to a different host — sugar for `restart` with a required `host`. Reaps the current attachment, claims fresh on the target host, spawns a new adapter. Cross-host routing (per-host task queues) is honored automatically. When `force=true` AND the target is currently on a different host, `confirmStealFromHost` must match that hostname (design §16.5).',
26
+ params: {
27
+ playerId: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).describe('The player name to migrate'),
28
+ host: zod_1.z.string().min(1).describe('Target hostname required'),
29
+ fresh: zod_1.z.boolean().optional().describe('Skip context replay (default false)'),
30
+ force: zod_1.z.boolean().optional().describe('Steal a live attachment via forceDetach (default false)'),
31
+ contextMessages: zod_1.z.number().min(0).max(validation_1.RESTART_CONTEXT_MESSAGES_MAX).optional().describe('Number of recent messages to include in context (default 10)'),
32
+ confirmStealFromHost: zod_1.z.string().optional().describe('Required when `force=true` and the target\'s current attachment is on a different host (design §16.5 Option B).'),
33
+ },
34
+ handler: async (args) => {
35
+ const input = args;
36
+ const nameError = (0, validation_1.validatePlayerName)(input.playerId);
37
+ if (nameError)
38
+ return (0, descriptor_1.fail)(nameError);
39
+ if (!input.host || !input.host.trim()) {
40
+ return (0, descriptor_1.fail)('`host` is required for migrate. Use `restart` (without host) to restart on the session\'s current host.');
41
+ }
42
+ // Shared cross-host guard with `restart` — same rules, same copy-paste
43
+ // error messages (§16.5).
44
+ const guardError = await (0, restart_1.enforceYesStealGuard)(client, config.ensemble, input.playerId, input);
45
+ if (guardError)
46
+ return (0, descriptor_1.fail)(guardError);
47
+ try {
48
+ const entry = {
49
+ type: 'restart',
50
+ targetPlayerId: input.playerId,
51
+ invokerPlayerId: getPlayerId(),
52
+ host: input.host,
53
+ ...(input.fresh !== undefined ? { fresh: input.fresh } : {}),
54
+ ...(input.force !== undefined ? { force: input.force } : {}),
55
+ ...(input.contextMessages !== undefined ? { contextMessages: input.contextMessages } : {}),
56
+ };
57
+ const entryId = await handle.executeUpdate(signals_1.submitOutboxUpdate, { args: [entry] });
58
+ return (0, descriptor_1.ok)(`Migrate queued for **${input.playerId}** → ${input.host}. (outbox: ${entryId})`);
59
+ }
60
+ catch (err) {
61
+ return (0, descriptor_1.fail)(`Failed to migrate: ${(0, descriptor_1.formatError)(err)}`);
62
+ }
63
+ },
64
+ };
60
65
  }
@@ -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 registerPauseTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string): void;
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ export declare function buildPauseTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;
@@ -1,36 +1,41 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPauseTool = registerPauseTool;
3
+ exports.buildPauseTool = buildPauseTool;
4
4
  const signals_1 = require("../workflows/signals");
5
- const helpers_1 = require("./helpers");
5
+ const descriptor_1 = require("./descriptor");
6
6
  const ensemble_ops_1 = require("../utils/ensemble-ops");
7
7
  const log = (...args) => console.error('[agent-tempo:pause]', ...args);
8
- function registerPauseTool(server, client, config, getPlayerId) {
9
- (0, helpers_1.defineTool)(server, 'pause', 'Pause all sessions in the ensemble — locks outbox dispatch and pauses the scheduler. Stop commands still go through. Use `play` to unpause.', {}, async () => {
10
- try {
11
- const [toggle, sessions] = await Promise.all([
12
- (0, ensemble_ops_1.pauseMaestroAndScheduler)(client, config.ensemble),
13
- (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, true),
14
- ]);
15
- const bits = [
16
- `Ensemble **${config.ensemble}** paused.`,
17
- `${sessions.sent} session(s) paused`,
18
- ];
19
- if (toggle.maestro)
20
- bits.push('maestro paused');
21
- if (toggle.scheduler)
22
- bits.push('scheduler paused');
23
- if (sessions.failed > 0) {
24
- const errs = sessions.perSession
25
- .filter((p) => p.outcome === 'failed')
26
- .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
27
- bits.push(`Errors:\n${errs.join('\n')}`);
8
+ function buildPauseTool(client, config, getPlayerId) {
9
+ return {
10
+ name: 'pause',
11
+ description: 'Pause all sessions in the ensemble — locks outbox dispatch and pauses the scheduler. Stop commands still go through. Use `play` to unpause.',
12
+ params: {},
13
+ handler: async () => {
14
+ try {
15
+ const [toggle, sessions] = await Promise.all([
16
+ (0, ensemble_ops_1.pauseMaestroAndScheduler)(client, config.ensemble),
17
+ (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, true),
18
+ ]);
19
+ const bits = [
20
+ `Ensemble **${config.ensemble}** paused.`,
21
+ `${sessions.sent} session(s) paused`,
22
+ ];
23
+ if (toggle.maestro)
24
+ bits.push('maestro paused');
25
+ if (toggle.scheduler)
26
+ bits.push('scheduler paused');
27
+ if (sessions.failed > 0) {
28
+ const errs = sessions.perSession
29
+ .filter((p) => p.outcome === 'failed')
30
+ .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
31
+ bits.push(`Errors:\n${errs.join('\n')}`);
32
+ }
33
+ log(`Paused ensemble "${config.ensemble}" by ${getPlayerId()}`);
34
+ return (0, descriptor_1.ok)(bits.join('\n'));
28
35
  }
29
- log(`Paused ensemble "${config.ensemble}" by ${getPlayerId()}`);
30
- return (0, helpers_1.ok)(bits.join('\n'));
31
- }
32
- catch (err) {
33
- return (0, helpers_1.fail)(`Failed to pause ensemble: ${(0, helpers_1.formatError)(err)}`);
34
- }
35
- });
36
+ catch (err) {
37
+ return (0, descriptor_1.fail)(`Failed to pause ensemble: ${(0, descriptor_1.formatError)(err)}`);
38
+ }
39
+ },
40
+ };
36
41
  }
@@ -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 registerPlayTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string): void;
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ export declare function buildPlayTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;
@@ -1,57 +1,62 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerPlayTool = registerPlayTool;
3
+ exports.buildPlayTool = buildPlayTool;
4
4
  const zod_1 = require("zod");
5
5
  const signals_1 = require("../workflows/signals");
6
- const helpers_1 = require("./helpers");
6
+ const descriptor_1 = require("./descriptor");
7
7
  const ensemble_ops_1 = require("../utils/ensemble-ops");
8
8
  const log = (...args) => console.error('[agent-tempo:play]', ...args);
9
- function registerPlayTool(server, client, config, getPlayerId) {
10
- (0, helpers_1.defineTool)(server, 'play', 'Resume all paused sessions in the ensemble — unlocks outbox dispatch and resumes the scheduler. Buffered outbox entries will be dispatched. Pass `release: true` to also release any held sessions (deliver deferred task messages and unlock their outboxes) in the same call.', {
11
- release: zod_1.z.boolean().optional().describe('Also release any held sessions (deliver deferred task messages and unlock outboxes). Safe to call when no sessions are held — it is a no-op on those. Default: false.'),
12
- }, async (args) => {
13
- const release = args.release === true;
14
- try {
15
- // Unpause everything in parallel: maestro + scheduler + every session.
16
- const [toggle, sessions] = await Promise.all([
17
- (0, ensemble_ops_1.unpauseMaestroAndScheduler)(client, config.ensemble),
18
- (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, false),
19
- ]);
20
- // `releaseHeld` is idempotent safe to fan out to everyone. Keep it
21
- // AFTER the unpause so sessions aren't releasing while paused.
22
- let releasedCount = 0;
23
- const releaseErrors = [];
24
- if (release) {
25
- const released = await (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble,
26
- // typed constant → `'releaseHeld'` string name, matches the session handler
27
- signals_1.releaseHeldSignal.name, undefined);
28
- releasedCount = released.sent;
29
- for (const p of released.perSession) {
30
- if (p.outcome === 'failed')
31
- releaseErrors.push(`${p.playerId} release: ${'error' in p ? p.error : ''}`);
9
+ function buildPlayTool(client, config, getPlayerId) {
10
+ return {
11
+ name: 'play',
12
+ description: 'Resume all paused sessions in the ensemble — unlocks outbox dispatch and resumes the scheduler. Buffered outbox entries will be dispatched. Pass `release: true` to also release any held sessions (deliver deferred task messages and unlock their outboxes) in the same call.',
13
+ params: {
14
+ release: zod_1.z.boolean().optional().describe('Also release any held sessions (deliver deferred task messages and unlock outboxes). Safe to call when no sessions are held — it is a no-op on those. Default: false.'),
15
+ },
16
+ handler: async (args) => {
17
+ const release = args.release === true;
18
+ try {
19
+ // Unpause everything in parallel: maestro + scheduler + every session.
20
+ const [toggle, sessions] = await Promise.all([
21
+ (0, ensemble_ops_1.unpauseMaestroAndScheduler)(client, config.ensemble),
22
+ (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble, signals_1.setPausedSignal.name, false),
23
+ ]);
24
+ // `releaseHeld` is idempotent — safe to fan out to everyone. Keep it
25
+ // AFTER the unpause so sessions aren't releasing while paused.
26
+ let releasedCount = 0;
27
+ const releaseErrors = [];
28
+ if (release) {
29
+ const released = await (0, ensemble_ops_1.signalAllSessions)(client, config.ensemble,
30
+ // typed constant → `'releaseHeld'` string name, matches the session handler
31
+ signals_1.releaseHeldSignal.name, undefined);
32
+ releasedCount = released.sent;
33
+ for (const p of released.perSession) {
34
+ if (p.outcome === 'failed')
35
+ releaseErrors.push(`${p.playerId} release: ${'error' in p ? p.error : ''}`);
36
+ }
32
37
  }
38
+ const bits = [
39
+ `Ensemble **${config.ensemble}** resumed.`,
40
+ `${sessions.sent} session(s) resumed`,
41
+ ];
42
+ if (release)
43
+ bits.push(`${releasedCount} session(s) signalled for release`);
44
+ if (toggle.maestro)
45
+ bits.push('maestro resumed');
46
+ if (toggle.scheduler)
47
+ bits.push('scheduler resumed');
48
+ const failedUnpause = sessions.perSession
49
+ .filter((p) => p.outcome === 'failed')
50
+ .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
51
+ const allErrors = [...failedUnpause, ...releaseErrors.map((e) => ` - ${e}`)];
52
+ if (allErrors.length > 0)
53
+ bits.push(`Errors:\n${allErrors.join('\n')}`);
54
+ log(`Resumed ensemble "${config.ensemble}" by ${getPlayerId()}${release ? ' (with release)' : ''}`);
55
+ return (0, descriptor_1.ok)(bits.join('\n'));
33
56
  }
34
- const bits = [
35
- `Ensemble **${config.ensemble}** resumed.`,
36
- `${sessions.sent} session(s) resumed`,
37
- ];
38
- if (release)
39
- bits.push(`${releasedCount} session(s) signalled for release`);
40
- if (toggle.maestro)
41
- bits.push('maestro resumed');
42
- if (toggle.scheduler)
43
- bits.push('scheduler resumed');
44
- const failedUnpause = sessions.perSession
45
- .filter((p) => p.outcome === 'failed')
46
- .map((p) => ` - ${p.playerId}: ${'error' in p ? p.error : ''}`);
47
- const allErrors = [...failedUnpause, ...releaseErrors.map((e) => ` - ${e}`)];
48
- if (allErrors.length > 0)
49
- bits.push(`Errors:\n${allErrors.join('\n')}`);
50
- log(`Resumed ensemble "${config.ensemble}" by ${getPlayerId()}${release ? ' (with release)' : ''}`);
51
- return (0, helpers_1.ok)(bits.join('\n'));
52
- }
53
- catch (err) {
54
- return (0, helpers_1.fail)(`Failed to resume ensemble: ${(0, helpers_1.formatError)(err)}`);
55
- }
56
- });
57
+ catch (err) {
58
+ return (0, descriptor_1.fail)(`Failed to resume ensemble: ${(0, descriptor_1.formatError)(err)}`);
59
+ }
60
+ },
61
+ };
57
62
  }
@@ -1,3 +1,3 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { WorkflowHandle } from '@temporalio/client';
3
- export declare function registerQualityGateTool(server: McpServer, handle: WorkflowHandle, getPlayerId: () => string): void;
2
+ import { type TempoToolDescriptor } from './descriptor';
3
+ export declare function buildQualityGateTool(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor;
@@ -1,26 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerQualityGateTool = registerQualityGateTool;
3
+ exports.buildQualityGateTool = buildQualityGateTool;
4
4
  const zod_1 = require("zod");
5
- const helpers_1 = require("./helpers");
5
+ const descriptor_1 = require("./descriptor");
6
6
  const validation_1 = require("../utils/validation");
7
- function registerQualityGateTool(server, handle, getPlayerId) {
8
- (0, helpers_1.defineTool)(server, 'quality_gate', 'Define or replace a quality gate for a task. Each gate has a list of criteria that must pass before the task is considered complete. Conductor only.', {
9
- task: zod_1.z.string().max(validation_1.GATE_TASK_MAX).describe('Unique task name for this gate (e.g. "pr-review", "deploy-staging")'),
10
- criteria: zod_1.z.array(zod_1.z.string().max(validation_1.GATE_CRITERION_TEXT_MAX)).min(1).max(validation_1.GATE_CRITERIA_MAX).describe('List of criteria that must be evaluated (e.g. ["Tests pass", "No lint errors", "Code reviewed"])'),
11
- }, async (args) => {
12
- const { task, criteria } = args;
13
- try {
14
- await handle.signal('setQualityGate', {
15
- task,
16
- criteria,
17
- createdBy: getPlayerId(),
18
- });
19
- const lines = criteria.map((c, i) => ` ${i}. [ ] ${c}`);
20
- return (0, helpers_1.ok)(`Quality gate **${task}** set with ${criteria.length} criteria:\n${lines.join('\n')}`);
21
- }
22
- catch (err) {
23
- return (0, helpers_1.fail)(`Failed to set quality gate: ${(0, helpers_1.formatError)(err)}`);
24
- }
25
- });
7
+ function buildQualityGateTool(handle, getPlayerId) {
8
+ return {
9
+ name: 'quality_gate',
10
+ description: 'Define or replace a quality gate for a task. Each gate has a list of criteria that must pass before the task is considered complete. Conductor only.',
11
+ params: {
12
+ task: zod_1.z.string().max(validation_1.GATE_TASK_MAX).describe('Unique task name for this gate (e.g. "pr-review", "deploy-staging")'),
13
+ criteria: zod_1.z.array(zod_1.z.string().max(validation_1.GATE_CRITERION_TEXT_MAX)).min(1).max(validation_1.GATE_CRITERIA_MAX).describe('List of criteria that must be evaluated (e.g. ["Tests pass", "No lint errors", "Code reviewed"])'),
14
+ },
15
+ handler: async (args) => {
16
+ const { task, criteria } = args;
17
+ try {
18
+ await handle.signal('setQualityGate', {
19
+ task,
20
+ criteria,
21
+ createdBy: getPlayerId(),
22
+ });
23
+ const lines = criteria.map((c, i) => ` ${i}. [ ] ${c}`);
24
+ return (0, descriptor_1.ok)(`Quality gate **${task}** set with ${criteria.length} criteria:\n${lines.join('\n')}`);
25
+ }
26
+ catch (err) {
27
+ return (0, descriptor_1.fail)(`Failed to set quality gate: ${(0, descriptor_1.formatError)(err)}`);
28
+ }
29
+ },
30
+ };
26
31
  }
@@ -1,3 +1,3 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { WorkflowHandle } from '@temporalio/client';
3
- export declare function registerRecallTool(server: McpServer, handle: WorkflowHandle, getPlayerId: () => string): void;
2
+ import { type TempoToolDescriptor } from './descriptor';
3
+ export declare function buildRecallTool(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor;
@@ -1,32 +1,37 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.registerRecallTool = registerRecallTool;
3
+ exports.buildRecallTool = buildRecallTool;
4
4
  const zod_1 = require("zod");
5
- const helpers_1 = require("./helpers");
5
+ const descriptor_1 = require("./descriptor");
6
6
  const recall_format_1 = require("../utils/recall-format");
7
- function registerRecallTool(server, handle, getPlayerId) {
8
- (0, helpers_1.defineTool)(server, 'recall', 'Read your own message history. Shows received messages by default; use includeSent to also see outgoing messages. `offset` pages the timeline; `previewLength` truncates bodies (unset = full text).', {
9
- limit: zod_1.z.number().min(1).max(100).optional().describe('Max messages to return (default 20, max 100)'),
10
- offset: zod_1.z.number().int().min(0).optional().describe('Skip N messages for paging (default 0)'),
11
- previewLength: zod_1.z.number().int().min(1).optional().describe('Truncate each body to N chars + "…"; omit for full text'),
12
- since: zod_1.z.string().optional().describe('Only show messages at or after this ISO timestamp'),
13
- from: zod_1.z.string().optional().describe('Filter received messages by sender name'),
14
- includeSent: zod_1.z.boolean().optional().describe('Include sent messages in the timeline (default: false)'),
15
- }, async (args) => {
16
- const { limit, offset, previewLength, since, from: fromFilter, includeSent } = args;
17
- // Validate `since` up-front so the formatter never sees a garbage date.
18
- if (since && Number.isNaN(Date.parse(since))) {
19
- return (0, helpers_1.fail)(`Invalid ISO timestamp for "since": ${since}`);
20
- }
21
- try {
22
- const received = await handle.query('allMessages');
23
- const sent = includeSent ? await handle.query('allSentMessages') : [];
24
- const timeline = (0, recall_format_1.buildTimeline)(received, sent, Boolean(includeSent));
25
- const rendered = (0, recall_format_1.formatRecall)(timeline, { limit, offset, previewLength, since, from: fromFilter });
26
- return (0, helpers_1.ok)(rendered.text);
27
- }
28
- catch (err) {
29
- return (0, helpers_1.fail)(`Failed to recall messages: ${(0, helpers_1.formatError)(err)}`);
30
- }
31
- });
7
+ function buildRecallTool(handle, getPlayerId) {
8
+ return {
9
+ name: 'recall',
10
+ description: 'Read your own message history. Shows received messages by default; use includeSent to also see outgoing messages. `offset` pages the timeline; `previewLength` truncates bodies (unset = full text).',
11
+ params: {
12
+ limit: zod_1.z.number().min(1).max(100).optional().describe('Max messages to return (default 20, max 100)'),
13
+ offset: zod_1.z.number().int().min(0).optional().describe('Skip N messages for paging (default 0)'),
14
+ previewLength: zod_1.z.number().int().min(1).optional().describe('Truncate each body to N chars + "…"; omit for full text'),
15
+ since: zod_1.z.string().optional().describe('Only show messages at or after this ISO timestamp'),
16
+ from: zod_1.z.string().optional().describe('Filter received messages by sender name'),
17
+ includeSent: zod_1.z.boolean().optional().describe('Include sent messages in the timeline (default: false)'),
18
+ },
19
+ handler: async (args) => {
20
+ const { limit, offset, previewLength, since, from: fromFilter, includeSent } = args;
21
+ // Validate `since` up-front so the formatter never sees a garbage date.
22
+ if (since && Number.isNaN(Date.parse(since))) {
23
+ return (0, descriptor_1.fail)(`Invalid ISO timestamp for "since": ${since}`);
24
+ }
25
+ try {
26
+ const received = await handle.query('allMessages');
27
+ const sent = includeSent ? await handle.query('allSentMessages') : [];
28
+ const timeline = (0, recall_format_1.buildTimeline)(received, sent, Boolean(includeSent));
29
+ const rendered = (0, recall_format_1.formatRecall)(timeline, { limit, offset, previewLength, since, from: fromFilter });
30
+ return (0, descriptor_1.ok)(rendered.text);
31
+ }
32
+ catch (err) {
33
+ return (0, descriptor_1.fail)(`Failed to recall messages: ${(0, descriptor_1.formatError)(err)}`);
34
+ }
35
+ },
36
+ };
32
37
  }
@@ -1,8 +1,8 @@
1
- import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
1
  import { Client, WorkflowHandle } from '@temporalio/client';
3
2
  import { Config } from '../config';
4
3
  import { AgentType } from '../types';
5
4
  import type { HostInfo } from '../types';
5
+ import { type TempoToolDescriptor } from './descriptor';
6
6
  /**
7
7
  * #274 M15 — dep-injection surface on the recruit tool registrar.
8
8
  *
@@ -13,7 +13,7 @@ import type { HostInfo } from '../types';
13
13
  export interface RegisterRecruitToolDeps {
14
14
  listHostsFn?: (client: Client) => Promise<HostInfo[]>;
15
15
  }
16
- export declare function registerRecruitTool(server: McpServer, client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle, ownAgentType?: AgentType, deps?: RegisterRecruitToolDeps): void;
16
+ export declare function buildRecruitTool(client: Client, config: Config, getPlayerId: () => string, handle: WorkflowHandle, ownAgentType?: AgentType, deps?: RegisterRecruitToolDeps): TempoToolDescriptor;
17
17
  /**
18
18
  * Given a host liveness+profile snapshot, validate that `targetHost` is
19
19
  * (a) known, (b) recruit-ready, and (c) advertises support for