agent-tempo 1.7.0 → 2.0.0-beta.2

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 (171) hide show
  1. package/CLAUDE.md +10 -13
  2. package/README.md +21 -15
  3. package/dashboard/dist/assets/index-BbR7zIdK.js.map +1 -1
  4. package/dashboard/package.json +1 -1
  5. package/dist/activities/hard-terminate.d.ts +2 -2
  6. package/dist/activities/hard-terminate.js +3 -9
  7. package/dist/activities/maestro.d.ts +8 -13
  8. package/dist/activities/maestro.js +3 -10
  9. package/dist/activities/outbox.js +16 -2
  10. package/dist/activities/resolve.d.ts +18 -7
  11. package/dist/activities/resolve.js +58 -46
  12. package/dist/adapters/base.js +3 -0
  13. package/dist/adapters/claude-code/adapter.js +7 -0
  14. package/dist/cli/command-center-command.js +15 -1
  15. package/dist/cli/commands.d.ts +8 -0
  16. package/dist/cli/commands.js +79 -11
  17. package/dist/cli/daemon-command.js +19 -33
  18. package/dist/cli/help-text.js +9 -7
  19. package/dist/cli/home-command.d.ts +26 -0
  20. package/dist/cli/home-command.js +156 -0
  21. package/dist/cli/removed-verbs.d.ts +0 -4
  22. package/dist/cli/removed-verbs.js +23 -12
  23. package/dist/cli/sa-preflight.d.ts +0 -14
  24. package/dist/cli/sa-preflight.js +1 -17
  25. package/dist/cli/startup.d.ts +1 -10
  26. package/dist/cli/startup.js +0 -40
  27. package/dist/cli.js +34 -80
  28. package/dist/client/core.js +13 -15
  29. package/dist/client/index.d.ts +2 -1
  30. package/dist/client/interface.d.ts +5 -14
  31. package/dist/client/with-spawn.d.ts +9 -4
  32. package/dist/client/with-spawn.js +7 -10
  33. package/dist/config.d.ts +14 -13
  34. package/dist/config.js +14 -0
  35. package/dist/constants.d.ts +50 -0
  36. package/dist/constants.js +60 -1
  37. package/dist/daemon.js +81 -0
  38. package/dist/http/auth.d.ts +3 -21
  39. package/dist/http/auth.js +10 -31
  40. package/dist/http/event-types.d.ts +38 -4
  41. package/dist/http/orphans.d.ts +3 -3
  42. package/dist/http/orphans.js +3 -3
  43. package/dist/http/server.d.ts +0 -5
  44. package/dist/http/server.js +79 -29
  45. package/dist/http/snapshot.js +3 -0
  46. package/dist/http/writes.d.ts +1 -1
  47. package/dist/http/writes.js +25 -2
  48. package/dist/observability/nondeterminism-alarm.d.ts +113 -0
  49. package/dist/observability/nondeterminism-alarm.js +162 -0
  50. package/dist/palette/index.d.ts +6 -7
  51. package/dist/palette/index.js +6 -7
  52. package/dist/pi/mission-control/actions.d.ts +67 -1
  53. package/dist/pi/mission-control/actions.js +61 -0
  54. package/dist/pi/mission-control/extension.d.ts +77 -0
  55. package/dist/pi/mission-control/extension.js +171 -0
  56. package/dist/pi/workflow-client.d.ts +14 -16
  57. package/dist/pi/workflow-client.js +18 -44
  58. package/dist/server-tools.js +30 -29
  59. package/dist/server.js +42 -0
  60. package/dist/tools/action-guard.d.ts +23 -0
  61. package/dist/tools/action-guard.js +33 -0
  62. package/dist/tools/coat-check.d.ts +20 -0
  63. package/dist/tools/coat-check.js +129 -0
  64. package/dist/tools/gate.d.ts +13 -0
  65. package/dist/tools/gate.js +88 -0
  66. package/dist/tools/schedule.d.ts +18 -0
  67. package/dist/tools/schedule.js +93 -1
  68. package/dist/tools/stage.d.ts +17 -0
  69. package/dist/tools/stage.js +85 -1
  70. package/dist/tools/state.d.ts +14 -0
  71. package/dist/tools/state.js +95 -0
  72. package/dist/types.d.ts +54 -7
  73. package/dist/upgrade/boot-guard.d.ts +95 -0
  74. package/dist/upgrade/boot-guard.js +88 -0
  75. package/dist/upgrade/from-upgrade.d.ts +95 -0
  76. package/dist/upgrade/from-upgrade.js +330 -0
  77. package/dist/upgrade/phase-engine.js +4 -1
  78. package/dist/utils/duration.d.ts +3 -6
  79. package/dist/utils/duration.js +3 -6
  80. package/dist/utils/format-hosts.d.ts +1 -1
  81. package/dist/utils/format-hosts.js +0 -2
  82. package/dist/utils/grpc-shutdown-guard.js +0 -4
  83. package/dist/utils/hosts.d.ts +4 -10
  84. package/dist/utils/hosts.js +12 -28
  85. package/dist/utils/orphan-guard.d.ts +37 -0
  86. package/dist/utils/orphan-guard.js +26 -0
  87. package/dist/utils/search-attributes.d.ts +28 -18
  88. package/dist/utils/search-attributes.js +48 -18
  89. package/dist/utils/visibility-deadline.d.ts +16 -0
  90. package/dist/utils/visibility-deadline.js +16 -0
  91. package/dist/workflows/maestro-signals.d.ts +0 -13
  92. package/dist/workflows/maestro-signals.js +6 -14
  93. package/dist/workflows/maestro.js +27 -32
  94. package/dist/workflows/scheduler.js +7 -1
  95. package/dist/workflows/session.js +237 -153
  96. package/dist/workflows/signals.d.ts +9 -1
  97. package/dist/workflows/signals.js +8 -6
  98. package/package.json +1 -6
  99. package/workflow-bundle.js +478 -225
  100. package/dist/cli/legacy-migration.d.ts +0 -35
  101. package/dist/cli/legacy-migration.js +0 -341
  102. package/dist/client/ensure-conductor-spawned.d.ts +0 -35
  103. package/dist/client/ensure-conductor-spawned.js +0 -48
  104. package/dist/tui/App.d.ts +0 -85
  105. package/dist/tui/App.js +0 -1791
  106. package/dist/tui/bootstrap-types.d.ts +0 -46
  107. package/dist/tui/bootstrap-types.js +0 -7
  108. package/dist/tui/commands.d.ts +0 -71
  109. package/dist/tui/commands.js +0 -1375
  110. package/dist/tui/components/ChatView.d.ts +0 -35
  111. package/dist/tui/components/ChatView.js +0 -54
  112. package/dist/tui/components/CommandPalette.d.ts +0 -21
  113. package/dist/tui/components/CommandPalette.js +0 -67
  114. package/dist/tui/components/ConversationStream.d.ts +0 -114
  115. package/dist/tui/components/ConversationStream.js +0 -307
  116. package/dist/tui/components/CreateEnsembleWizard.d.ts +0 -19
  117. package/dist/tui/components/CreateEnsembleWizard.js +0 -223
  118. package/dist/tui/components/DestroyConfirmModal.d.ts +0 -17
  119. package/dist/tui/components/DestroyConfirmModal.js +0 -62
  120. package/dist/tui/components/ErrorView.d.ts +0 -31
  121. package/dist/tui/components/ErrorView.js +0 -129
  122. package/dist/tui/components/HomeView.d.ts +0 -54
  123. package/dist/tui/components/HomeView.js +0 -306
  124. package/dist/tui/components/LoadLineupModal.d.ts +0 -18
  125. package/dist/tui/components/LoadLineupModal.js +0 -79
  126. package/dist/tui/components/MainView.d.ts +0 -21
  127. package/dist/tui/components/MainView.js +0 -107
  128. package/dist/tui/components/NewEnsembleModal.d.ts +0 -9
  129. package/dist/tui/components/NewEnsembleModal.js +0 -73
  130. package/dist/tui/components/Picker.d.ts +0 -23
  131. package/dist/tui/components/Picker.js +0 -70
  132. package/dist/tui/components/PlayerDetailView.d.ts +0 -26
  133. package/dist/tui/components/PlayerDetailView.js +0 -118
  134. package/dist/tui/components/PromptArea.d.ts +0 -50
  135. package/dist/tui/components/PromptArea.js +0 -303
  136. package/dist/tui/components/RecruitWizard.d.ts +0 -17
  137. package/dist/tui/components/RecruitWizard.js +0 -221
  138. package/dist/tui/components/RestoreConfirmModal.d.ts +0 -18
  139. package/dist/tui/components/RestoreConfirmModal.js +0 -71
  140. package/dist/tui/components/ScheduleWizard.d.ts +0 -19
  141. package/dist/tui/components/ScheduleWizard.js +0 -259
  142. package/dist/tui/components/Splash.d.ts +0 -23
  143. package/dist/tui/components/Splash.js +0 -221
  144. package/dist/tui/components/StatusBar.d.ts +0 -48
  145. package/dist/tui/components/StatusBar.js +0 -128
  146. package/dist/tui/components/StatusOverlay.d.ts +0 -15
  147. package/dist/tui/components/StatusOverlay.js +0 -76
  148. package/dist/tui/components/TitleBar.d.ts +0 -10
  149. package/dist/tui/components/TitleBar.js +0 -21
  150. package/dist/tui/index.d.ts +0 -15
  151. package/dist/tui/index.js +0 -162
  152. package/dist/tui/ink-context.d.ts +0 -18
  153. package/dist/tui/ink-context.js +0 -59
  154. package/dist/tui/ink-loader.d.ts +0 -26
  155. package/dist/tui/ink-loader.js +0 -42
  156. package/dist/tui/removed-commands.d.ts +0 -9
  157. package/dist/tui/removed-commands.js +0 -22
  158. package/dist/tui/sse-handler.d.ts +0 -52
  159. package/dist/tui/sse-handler.js +0 -157
  160. package/dist/tui/store.d.ts +0 -598
  161. package/dist/tui/store.js +0 -753
  162. package/dist/tui/utils/format.d.ts +0 -56
  163. package/dist/tui/utils/format.js +0 -155
  164. package/dist/tui/utils/fullscreen.d.ts +0 -23
  165. package/dist/tui/utils/fullscreen.js +0 -71
  166. package/dist/tui/utils/history.d.ts +0 -10
  167. package/dist/tui/utils/history.js +0 -85
  168. package/dist/tui/utils/platform.d.ts +0 -45
  169. package/dist/tui/utils/platform.js +0 -258
  170. package/dist/tui/utils/theme.d.ts +0 -21
  171. package/dist/tui/utils/theme.js +0 -24
@@ -11,9 +11,8 @@ const listen_1 = require("./tools/listen");
11
11
  const recruit_1 = require("./tools/recruit");
12
12
  const report_1 = require("./tools/report");
13
13
  const set_name_1 = require("./tools/set-name");
14
+ // #793 — canonical `schedule` (action create|cancel|list) + unschedule/schedules aliases.
14
15
  const schedule_1 = require("./tools/schedule");
15
- const unschedule_1 = require("./tools/unschedule");
16
- const schedules_1 = require("./tools/schedules");
17
16
  const save_lineup_1 = require("./tools/save-lineup");
18
17
  const load_lineup_1 = require("./tools/load-lineup");
19
18
  const agent_types_1 = require("./tools/agent-types");
@@ -25,13 +24,13 @@ const pause_1 = require("./tools/pause");
25
24
  const play_1 = require("./tools/play");
26
25
  const shutdown_1 = require("./tools/shutdown");
27
26
  const restore_1 = require("./tools/restore");
28
- const quality_gate_1 = require("./tools/quality-gate");
27
+ // #793 canonical `gate` (action define|list) + quality_gate/gates aliases.
28
+ // `evaluate_gate` stays a SEPARATE tool (partial merge — runtime op, not CRUD).
29
+ const gate_1 = require("./tools/gate");
29
30
  const evaluate_gate_1 = require("./tools/evaluate-gate");
30
- const gates_1 = require("./tools/gates");
31
31
  const worktree_1 = require("./tools/worktree");
32
+ // #793 — canonical `stage` (action create|list|cancel) + stages/cancel_stage aliases.
32
33
  const stage_1 = require("./tools/stage");
33
- const stages_1 = require("./tools/stages");
34
- const cancel_stage_1 = require("./tools/cancel-stage");
35
34
  const restart_1 = require("./tools/restart");
36
35
  const destroy_1 = require("./tools/destroy");
37
36
  const reset_1 = require("./tools/reset");
@@ -39,15 +38,12 @@ const migrate_1 = require("./tools/migrate");
39
38
  const attachment_info_1 = require("./tools/attachment-info");
40
39
  const hosts_1 = require("./tools/hosts");
41
40
  const set_ensemble_description_1 = require("./tools/set-ensemble-description");
42
- // #334 PR-1 — player saveable state (save_state / fetch_state / clear_state).
43
- const save_state_1 = require("./tools/save-state");
44
- const fetch_state_1 = require("./tools/fetch-state");
45
- const clear_state_1 = require("./tools/clear-state");
46
- // #318 — ensemble-shared coat-check (put / get / list / evict).
47
- const coat_check_put_1 = require("./tools/coat-check-put");
48
- const coat_check_get_1 = require("./tools/coat-check-get");
49
- const coat_check_list_1 = require("./tools/coat-check-list");
50
- const coat_check_evict_1 = require("./tools/coat-check-evict");
41
+ // #334 PR-1 / #793 canonical `state` (action save|fetch|clear) + save_state/
42
+ // fetch_state/clear_state aliases.
43
+ const state_1 = require("./tools/state");
44
+ // #318 / #793 — canonical `coat_check` (action put|get|list|evict) +
45
+ // coat_check_put/get/list/evict aliases.
46
+ const coat_check_1 = require("./tools/coat-check");
51
47
  const respond_1 = require("./tools/respond");
52
48
  /**
53
49
  * Register every tempo MCP tool onto `server`. Single source of truth — the
@@ -69,9 +65,10 @@ function buildAllTempoTools(opts) {
69
65
  (0, listen_1.buildListenTool)(handle),
70
66
  (0, recruit_1.buildRecruitTool)(client, config, getPlayerId, handle, ownAgentType, defaultAgentSource),
71
67
  (0, report_1.buildReportTool)(handle),
68
+ // #793 — canonical `schedule` (action defaults to "create") + legacy
69
+ // unschedule/schedules forwarding aliases.
72
70
  (0, schedule_1.buildScheduleTool)(client, config, getPlayerId),
73
- (0, unschedule_1.buildUnscheduleTool)(client, config),
74
- (0, schedules_1.buildSchedulesTool)(client, config),
71
+ ...(0, schedule_1.buildScheduleAliasTools)(client, config),
75
72
  (0, save_lineup_1.buildSaveLineupTool)(client, config, getPlayerId, isConductor),
76
73
  (0, load_lineup_1.buildLoadLineupTool)(client, config, getPlayerId, ownAgentType, handle, setPlayerId, isConductor),
77
74
  (0, agent_types_1.buildAgentTypesTool)(),
@@ -90,23 +87,27 @@ function buildAllTempoTools(opts) {
90
87
  (0, attachment_info_1.buildAttachmentInfoTool)(client, config),
91
88
  (0, hosts_1.buildHostsTool)(client, config),
92
89
  (0, set_ensemble_description_1.buildSetEnsembleDescriptionTool)(client, config),
93
- // #334 PR-1 — owner-write / peer-read player saveable state.
94
- (0, save_state_1.buildSaveStateTool)(handle, getPlayerId),
95
- (0, fetch_state_1.buildFetchStateTool)(client, config, handle, getPlayerId),
96
- (0, clear_state_1.buildClearStateTool)(handle),
97
- // #318 — ensemble-shared coat-check (put/get/list/evict). Any player can put;
98
- // any player can get/list; owner-or-conductor can evict. Audit identity is
99
- // set at the tool layer via getPlayerId() — no playerId arg on any schema.
100
- (0, coat_check_put_1.buildCoatCheckPutTool)(client, config, getPlayerId),
101
- (0, coat_check_get_1.buildCoatCheckGetTool)(client, config, getPlayerId),
102
- (0, coat_check_list_1.buildCoatCheckListTool)(client, config),
103
- (0, coat_check_evict_1.buildCoatCheckEvictTool)(client, config, getPlayerId),
90
+ // #334 PR-1 / #793 canonical `state` (owner-write / peer-read) + legacy
91
+ // save_state/fetch_state/clear_state forwarding aliases.
92
+ (0, state_1.buildStateTool)(client, config, handle, getPlayerId),
93
+ ...(0, state_1.buildStateAliasTools)(client, config, handle, getPlayerId),
94
+ // #318 / #793 canonical `coat_check` (put/get/list/evict) + legacy
95
+ // coat_check_* forwarding aliases. Any player can put/get/list;
96
+ // owner-or-conductor can evict. Audit identity is set at the tool layer via
97
+ // getPlayerId() no playerId arg on any schema.
98
+ (0, coat_check_1.buildCoatCheckTool)(client, config, getPlayerId),
99
+ ...(0, coat_check_1.buildCoatCheckAliasTools)(client, config, getPlayerId),
104
100
  // #700 P2 — answer a planner's correlated `[Q <id>]` question (writes the
105
101
  // maestro Q&A mailbox directly; from = getPlayerId(), no spoofable arg).
106
102
  (0, respond_1.buildRespondTool)(client, config, getPlayerId),
107
103
  ];
108
104
  if (isConductor) {
109
- tools.push((0, quality_gate_1.buildQualityGateTool)(handle, getPlayerId), (0, evaluate_gate_1.buildEvaluateGateTool)(handle, getPlayerId), (0, gates_1.buildGatesTool)(handle), (0, worktree_1.buildWorktreeTool)(client, config, handle, getPlayerId), (0, stage_1.buildStageTool)(handle, getPlayerId), (0, stages_1.buildStagesTool)(handle), (0, cancel_stage_1.buildCancelStageTool)(handle));
105
+ tools.push(
106
+ // #793 — canonical `gate` (define|list) + quality_gate/gates aliases.
107
+ // `evaluate_gate` stays a separate tool (partial-merge boundary).
108
+ (0, gate_1.buildGateTool)(handle, getPlayerId), (0, evaluate_gate_1.buildEvaluateGateTool)(handle, getPlayerId), ...(0, gate_1.buildGateAliasTools)(handle, getPlayerId), (0, worktree_1.buildWorktreeTool)(client, config, handle, getPlayerId),
109
+ // #793 — canonical `stage` (create|list|cancel) + stages/cancel_stage aliases.
110
+ (0, stage_1.buildStageTool)(handle, getPlayerId), ...(0, stage_1.buildStageAliasTools)(handle));
110
111
  }
111
112
  return tools;
112
113
  }
package/dist/server.js CHANGED
@@ -59,6 +59,7 @@ const parent_death_watchdog_1 = require("./utils/parent-death-watchdog");
59
59
  const grpc_shutdown_guard_1 = require("./utils/grpc-shutdown-guard");
60
60
  const action_counters_1 = require("./utils/action-counters");
61
61
  const search_attributes_1 = require("./utils/search-attributes");
62
+ const orphan_guard_1 = require("./utils/orphan-guard");
62
63
  const log = (...args) => console.error('[agent-tempo]', ...args);
63
64
  async function main() {
64
65
  (0, parent_death_watchdog_1.installParentDeathWatchdog)();
@@ -157,6 +158,12 @@ async function main() {
157
158
  isConductor,
158
159
  agentType: isBridgeMode ? 'copilot' : 'claude',
159
160
  adapterId,
161
+ // #704 — thread the adapter descriptor's dialog-blocking property onto
162
+ // durable metadata so the session workflow can ARM/DISARM the booting
163
+ // watchdog without importing the client-side registry. This self-bootstrap
164
+ // path is interactive `claude-code` (or the Copilot bridge), so it resolves
165
+ // to disarmed; recruited headless sessions arm via `startRecruitedSession`.
166
+ canBlockOnDialog: adapterDescriptor?.canBlockOnDialog === true,
160
167
  },
161
168
  // Issue #450 — self-bootstrap path has no resolved player type, so
162
169
  // this falls through to `'Conductor session'` for conductors and
@@ -170,6 +177,41 @@ async function main() {
170
177
  taskQueue: config.taskQueue,
171
178
  },
172
179
  };
180
+ // #704 Item 1b — late-orphan self-tombstone guard. A recruited process can
181
+ // launch LONG after its recruit was cancelled (slow / wedged cold start). If
182
+ // this derived id's latest run is CLOSED with a destroy / boot-timeout tombstone
183
+ // MEMO and NO newer RUNNING run exists, this process is that orphan — exit before
184
+ // `start(USE_EXISTING)` bootstraps a brand-new run that collides with whoever took
185
+ // over the worktree. The running-run × close-reason PAIR is the discriminator:
186
+ // every managed re-creation (recruit / restart / migrate / up) pre-creates a
187
+ // RUNNING run, so a legit reuse is seen as RUNNING and simply attaches — it never
188
+ // reaches this branch. Gated `!isConductor` (conductors are operator-driven via
189
+ // `up`, never a recruited orphan). A generous wall-clock TTL bounds a stale
190
+ // tombstone so a much-later legit manual reuse of the same name isn't blocked
191
+ // forever (observed orphan delay ~100min; default 6h, env-overridable).
192
+ if (!isConductor) {
193
+ const ttlMsRaw = Number(process.env[config_1.ENV.ORPHAN_TOMBSTONE_TTL_MS]);
194
+ const orphanTombstoneTtlMs = Number.isFinite(ttlMsRaw) && ttlMsRaw > 0 ? ttlMsRaw : 6 * 60 * 60 * 1000;
195
+ try {
196
+ const desc = await client.workflow.getHandle(workflowId).describe();
197
+ const closeReason = desc.memo?.[search_attributes_1.MEMO_KEYS.closeReason];
198
+ const orphan = (0, orphan_guard_1.shouldSelfExitAsOrphan)({
199
+ statusName: desc.status.name,
200
+ closeReason,
201
+ closeTimeMs: desc.closeTime ? desc.closeTime.getTime() : 0,
202
+ }, orphanTombstoneTtlMs, Date.now());
203
+ if (orphan) {
204
+ log(`recruit was cancelled (close-reason: ${closeReason}) — exiting to avoid ` +
205
+ `re-registering an orphan session for ${workflowId}`);
206
+ process.exit(0);
207
+ }
208
+ }
209
+ catch {
210
+ // No prior run (NotFound) → first-ever start for this id → proceed. Any other
211
+ // describe() failure is non-fatal: the guard is a best-effort backstop, not a
212
+ // correctness gate — fall through and let the start proceed.
213
+ }
214
+ }
173
215
  const startedHandle = await client.workflow.start('agentSessionWorkflow', {
174
216
  workflowId,
175
217
  taskQueue: config.taskQueue,
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Per-action runtime field guard for the canonical multi-action tools (#793).
3
+ *
4
+ * The tool-family merge (#793) collapses each family into one canonical tool
5
+ * with a flat `{ action, ...per-action optional fields }` param shape. Because
6
+ * the union makes every per-action field optional at the zod boundary (we do
7
+ * NOT use `z.discriminatedUnion` — see docs/design/793-tool-family-merge-brief.md
8
+ * §2), cross-field "this action requires that field" rules are enforced at
9
+ * RUNTIME inside the handler, before dispatch.
10
+ *
11
+ * {@link firstMissing} returns the first required field that is absent so the
12
+ * handler can return a friendly, actionable `fail(...)` message naming the
13
+ * exact tool, action, and field — instead of a cryptic downstream error.
14
+ */
15
+ /**
16
+ * Return the first field name in `fields` whose value in `args` is "missing"
17
+ * (`undefined`, `null`, or an empty string), or `null` when all are present.
18
+ *
19
+ * Empty-string counts as missing so a canonical handler rejects e.g.
20
+ * `coat_check{action:'get', ticket:''}` with the same friendly error a wholly
21
+ * omitted ticket would produce.
22
+ */
23
+ export declare function firstMissing(args: Record<string, unknown>, fields: readonly string[]): string | null;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ /**
3
+ * Per-action runtime field guard for the canonical multi-action tools (#793).
4
+ *
5
+ * The tool-family merge (#793) collapses each family into one canonical tool
6
+ * with a flat `{ action, ...per-action optional fields }` param shape. Because
7
+ * the union makes every per-action field optional at the zod boundary (we do
8
+ * NOT use `z.discriminatedUnion` — see docs/design/793-tool-family-merge-brief.md
9
+ * §2), cross-field "this action requires that field" rules are enforced at
10
+ * RUNTIME inside the handler, before dispatch.
11
+ *
12
+ * {@link firstMissing} returns the first required field that is absent so the
13
+ * handler can return a friendly, actionable `fail(...)` message naming the
14
+ * exact tool, action, and field — instead of a cryptic downstream error.
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.firstMissing = firstMissing;
18
+ /**
19
+ * Return the first field name in `fields` whose value in `args` is "missing"
20
+ * (`undefined`, `null`, or an empty string), or `null` when all are present.
21
+ *
22
+ * Empty-string counts as missing so a canonical handler rejects e.g.
23
+ * `coat_check{action:'get', ticket:''}` with the same friendly error a wholly
24
+ * omitted ticket would produce.
25
+ */
26
+ function firstMissing(args, fields) {
27
+ for (const field of fields) {
28
+ const v = args[field];
29
+ if (v === undefined || v === null || v === '')
30
+ return field;
31
+ }
32
+ return null;
33
+ }
@@ -0,0 +1,20 @@
1
+ import { Client } from '@temporalio/client';
2
+ import { Config } from '../config';
3
+ import { type TempoToolDescriptor } from './descriptor';
4
+ /**
5
+ * Canonical `coat_check` tool. Dispatches on `action` to the same per-action
6
+ * logic the legacy tools used. Per-action required fields are runtime-guarded
7
+ * (the flat union makes them optional at the zod boundary).
8
+ */
9
+ export declare function buildCoatCheckTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;
10
+ /**
11
+ * Legacy forwarding aliases — `coat_check_put` / `coat_check_get` /
12
+ * `coat_check_list` / `coat_check_evict`. Each keeps its EXACT original param
13
+ * schema and handler (reused verbatim from the legacy descriptor); only the
14
+ * description gains a deprecation note pointing at the canonical tool.
15
+ *
16
+ * Authored as explicit object literals (not loop-generated) so the
17
+ * surface-drift name scrape and any future static analysis see each alias name
18
+ * adjacent to its description (docs/design/793-tool-family-merge-brief.md §6).
19
+ */
20
+ export declare function buildCoatCheckAliasTools(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor[];
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildCoatCheckTool = buildCoatCheckTool;
4
+ exports.buildCoatCheckAliasTools = buildCoatCheckAliasTools;
5
+ /**
6
+ * `coat_check` — canonical multi-action coat-check tool (#793 tool-family merge).
7
+ *
8
+ * Merges the four legacy per-action tools (`coat_check_put` / `coat_check_get` /
9
+ * `coat_check_list` / `coat_check_evict`) into ONE canonical tool with a flat
10
+ * `{ action, ...per-action optional fields }` param shape (NOT a discriminated
11
+ * union — see docs/design/793-tool-family-merge-brief.md §2). The canonical name
12
+ * is **net-new**, so `action` is REQUIRED (no legacy caller to keep compatible).
13
+ *
14
+ * The legacy tools stay registered as thin forwarding aliases
15
+ * ({@link buildCoatCheckAliasTools}) so every existing caller keeps its exact
16
+ * original schema and behaviour — the alias-not-remove invariant (#793). Both the
17
+ * canonical handler and the aliases reuse the legacy descriptors' handler bodies
18
+ * verbatim, so there is a single implementation per action.
19
+ */
20
+ const zod_1 = require("zod");
21
+ const descriptor_1 = require("./descriptor");
22
+ const action_guard_1 = require("./action-guard");
23
+ const validation_1 = require("../utils/validation");
24
+ const coat_check_put_1 = require("./coat-check-put");
25
+ const coat_check_get_1 = require("./coat-check-get");
26
+ const coat_check_list_1 = require("./coat-check-list");
27
+ const coat_check_evict_1 = require("./coat-check-evict");
28
+ /**
29
+ * Canonical `coat_check` tool. Dispatches on `action` to the same per-action
30
+ * logic the legacy tools used. Per-action required fields are runtime-guarded
31
+ * (the flat union makes them optional at the zod boundary).
32
+ */
33
+ function buildCoatCheckTool(client, config, getPlayerId) {
34
+ const put = (0, coat_check_put_1.buildCoatCheckPutTool)(client, config, getPlayerId);
35
+ const get = (0, coat_check_get_1.buildCoatCheckGetTool)(client, config, getPlayerId);
36
+ const list = (0, coat_check_list_1.buildCoatCheckListTool)(client, config);
37
+ const evict = (0, coat_check_evict_1.buildCoatCheckEvictTool)(client, config, getPlayerId);
38
+ return {
39
+ name: 'coat_check',
40
+ description: 'Ensemble-shared transient store (stash large artifacts past the cue size cap). ' +
41
+ 'action="put" stashes content (summary+content[, contentType, ttlMs]) and returns a ticket; ' +
42
+ 'action="get" redeems a ticket (bumps fetch audit); ' +
43
+ 'action="list" surveys entry headers (putBy/prefix/unfetchedOnly filters); ' +
44
+ 'action="evict" removes an entry early (owner-or-conductor).',
45
+ params: {
46
+ action: zod_1.z.enum(['put', 'get', 'list', 'evict']).describe('Which coat-check operation to perform'),
47
+ // put:
48
+ summary: zod_1.z.string().min(1).max(validation_1.COAT_CHECK_SUMMARY_MAX).optional().describe('put: short human-readable label for the entry'),
49
+ content: zod_1.z.string().min(1).max(validation_1.COAT_CHECK_CONTENT_MAX).optional().describe('put: the body to stash (≤32 KiB)'),
50
+ contentType: zod_1.z.string().max(validation_1.COAT_CHECK_CONTENT_TYPE_MAX).optional().describe('put: optional MIME/content-type hint'),
51
+ ttlMs: zod_1.z.number().int().min(validation_1.COAT_CHECK_TTL_MIN_MS).max(validation_1.COAT_CHECK_TTL_MAX_MS).optional().describe('put: optional time-to-live in ms (default 7d)'),
52
+ // get / evict:
53
+ ticket: zod_1.z.string().regex(validation_1.COAT_CHECK_TICKET_REGEX).max(validation_1.COAT_CHECK_TICKET_MAX).optional().describe('get/evict: the ticket id returned by put'),
54
+ // list:
55
+ putBy: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).optional().describe('list: filter to entries stashed by this player'),
56
+ prefix: zod_1.z.string().max(validation_1.COAT_CHECK_SUMMARY_MAX).optional().describe('list: filter to entries whose summary starts with this prefix'),
57
+ unfetchedOnly: zod_1.z.boolean().optional().describe('list: only entries that have never been fetched'),
58
+ },
59
+ handler: async (args) => {
60
+ const action = args.action;
61
+ switch (action) {
62
+ case 'put': {
63
+ const m = (0, action_guard_1.firstMissing)(args, ['summary', 'content']);
64
+ if (m)
65
+ return (0, descriptor_1.fail)(`coat_check action="put" requires "${m}".`);
66
+ return put.handler(args);
67
+ }
68
+ case 'get': {
69
+ const m = (0, action_guard_1.firstMissing)(args, ['ticket']);
70
+ if (m)
71
+ return (0, descriptor_1.fail)(`coat_check action="get" requires "${m}".`);
72
+ return get.handler(args);
73
+ }
74
+ case 'list':
75
+ return list.handler(args);
76
+ case 'evict': {
77
+ const m = (0, action_guard_1.firstMissing)(args, ['ticket']);
78
+ if (m)
79
+ return (0, descriptor_1.fail)(`coat_check action="evict" requires "${m}".`);
80
+ return evict.handler(args);
81
+ }
82
+ default:
83
+ return (0, descriptor_1.fail)(`Unknown coat_check action: ${String(action)}. Expected put | get | list | evict.`);
84
+ }
85
+ },
86
+ };
87
+ }
88
+ /**
89
+ * Legacy forwarding aliases — `coat_check_put` / `coat_check_get` /
90
+ * `coat_check_list` / `coat_check_evict`. Each keeps its EXACT original param
91
+ * schema and handler (reused verbatim from the legacy descriptor); only the
92
+ * description gains a deprecation note pointing at the canonical tool.
93
+ *
94
+ * Authored as explicit object literals (not loop-generated) so the
95
+ * surface-drift name scrape and any future static analysis see each alias name
96
+ * adjacent to its description (docs/design/793-tool-family-merge-brief.md §6).
97
+ */
98
+ function buildCoatCheckAliasTools(client, config, getPlayerId) {
99
+ const put = (0, coat_check_put_1.buildCoatCheckPutTool)(client, config, getPlayerId);
100
+ const get = (0, coat_check_get_1.buildCoatCheckGetTool)(client, config, getPlayerId);
101
+ const list = (0, coat_check_list_1.buildCoatCheckListTool)(client, config);
102
+ const evict = (0, coat_check_evict_1.buildCoatCheckEvictTool)(client, config, getPlayerId);
103
+ return [
104
+ {
105
+ name: 'coat_check_put',
106
+ description: 'DEPRECATED — use `coat_check` with action="put". ' + put.description,
107
+ params: put.params,
108
+ handler: put.handler,
109
+ },
110
+ {
111
+ name: 'coat_check_get',
112
+ description: 'DEPRECATED — use `coat_check` with action="get". ' + get.description,
113
+ params: get.params,
114
+ handler: get.handler,
115
+ },
116
+ {
117
+ name: 'coat_check_list',
118
+ description: 'DEPRECATED — use `coat_check` with action="list". ' + list.description,
119
+ params: list.params,
120
+ handler: list.handler,
121
+ },
122
+ {
123
+ name: 'coat_check_evict',
124
+ description: 'DEPRECATED — use `coat_check` with action="evict". ' + evict.description,
125
+ params: evict.params,
126
+ handler: evict.handler,
127
+ },
128
+ ];
129
+ }
@@ -0,0 +1,13 @@
1
+ import { WorkflowHandle } from '@temporalio/client';
2
+ import { type TempoToolDescriptor } from './descriptor';
3
+ /**
4
+ * Canonical `gate` tool. Dispatches on `action` (define | list); `evaluate_gate`
5
+ * is intentionally excluded (separate tool).
6
+ */
7
+ export declare function buildGateTool(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor;
8
+ /**
9
+ * Legacy forwarding aliases — `quality_gate` → define, `gates` → list. Each
10
+ * keeps its exact original schema + handler; description gains a deprecation
11
+ * note. Explicit object literals (see §6 drift note).
12
+ */
13
+ export declare function buildGateAliasTools(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor[];
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildGateTool = buildGateTool;
4
+ exports.buildGateAliasTools = buildGateAliasTools;
5
+ /**
6
+ * `gate` — canonical multi-action quality-gate tool (#793 merge, PARTIAL).
7
+ *
8
+ * Merges the two gate-DEFINITION tools (`quality_gate` → define, `gates` → list)
9
+ * into ONE canonical tool. The canonical name is **net-new**, so `action` is
10
+ * REQUIRED.
11
+ *
12
+ * PARTIAL merge: `evaluate_gate` STAYS A SEPARATE TOOL and is NOT folded in.
13
+ * Rationale (brief §3⑤): evaluate is a distinct runtime *operation* — record
14
+ * pass/fail + notes against criteria — not CRUD on the gate *definition*. The
15
+ * define/list-the-gate vs act-on-the-gate line is the partial boundary.
16
+ *
17
+ * Legacy tools stay registered as forwarding aliases ({@link buildGateAliasTools});
18
+ * both paths reuse the legacy handler bodies. Conductor-only (gated in
19
+ * server-tools.ts alongside the other gate/stage tools).
20
+ */
21
+ const zod_1 = require("zod");
22
+ const descriptor_1 = require("./descriptor");
23
+ const action_guard_1 = require("./action-guard");
24
+ const validation_1 = require("../utils/validation");
25
+ const quality_gate_1 = require("./quality-gate");
26
+ const gates_1 = require("./gates");
27
+ /**
28
+ * Canonical `gate` tool. Dispatches on `action` (define | list); `evaluate_gate`
29
+ * is intentionally excluded (separate tool).
30
+ */
31
+ function buildGateTool(handle, getPlayerId) {
32
+ const define = (0, quality_gate_1.buildQualityGateTool)(handle, getPlayerId);
33
+ const list = (0, gates_1.buildGatesTool)(handle);
34
+ return {
35
+ name: 'gate',
36
+ description: 'Define and inspect quality gates for a task (conductor only). ' +
37
+ 'action="define" sets/replaces a gate (task + criteria); ' +
38
+ 'action="list" shows gates and per-criterion status (optional task/status filters). ' +
39
+ 'To record pass/fail on criteria, use the separate `evaluate_gate` tool.',
40
+ params: {
41
+ action: zod_1.z.enum(['define', 'list']).describe('Which gate operation to perform'),
42
+ // define / list (filter):
43
+ task: zod_1.z.string().max(validation_1.GATE_TASK_MAX).optional().describe('define: the task this gate guards (required). list: optional task filter.'),
44
+ // define:
45
+ criteria: zod_1.z.array(zod_1.z.string().max(validation_1.GATE_CRITERION_TEXT_MAX)).min(1).max(validation_1.GATE_CRITERIA_MAX).optional().describe('define: the list of criteria that must pass (required)'),
46
+ // list:
47
+ status: zod_1.z.enum(['open', 'passed', 'failed']).optional().describe('list: optional status filter'),
48
+ },
49
+ handler: async (args) => {
50
+ const action = args.action;
51
+ switch (action) {
52
+ case 'define': {
53
+ const m = (0, action_guard_1.firstMissing)(args, ['task', 'criteria']);
54
+ if (m)
55
+ return (0, descriptor_1.fail)(`gate action="define" requires "${m}".`);
56
+ return define.handler(args);
57
+ }
58
+ case 'list':
59
+ return list.handler(args);
60
+ default:
61
+ return (0, descriptor_1.fail)(`Unknown gate action: ${String(action)}. Expected define | list.`);
62
+ }
63
+ },
64
+ };
65
+ }
66
+ /**
67
+ * Legacy forwarding aliases — `quality_gate` → define, `gates` → list. Each
68
+ * keeps its exact original schema + handler; description gains a deprecation
69
+ * note. Explicit object literals (see §6 drift note).
70
+ */
71
+ function buildGateAliasTools(handle, getPlayerId) {
72
+ const define = (0, quality_gate_1.buildQualityGateTool)(handle, getPlayerId);
73
+ const list = (0, gates_1.buildGatesTool)(handle);
74
+ return [
75
+ {
76
+ name: 'quality_gate',
77
+ description: 'DEPRECATED — use `gate` with action="define". ' + define.description,
78
+ params: define.params,
79
+ handler: define.handler,
80
+ },
81
+ {
82
+ name: 'gates',
83
+ description: 'DEPRECATED — use `gate` with action="list". ' + list.description,
84
+ params: list.params,
85
+ handler: list.handler,
86
+ },
87
+ ];
88
+ }
@@ -1,4 +1,22 @@
1
1
  import { Client } from '@temporalio/client';
2
2
  import { Config } from '../config';
3
3
  import { type TempoToolDescriptor } from './descriptor';
4
+ /**
5
+ * Canonical `schedule` tool (#793 merge) — **reused** name, so `action` defaults
6
+ * to `'create'` for backward-compat (existing callers omit `action` → the legacy
7
+ * bare-`schedule` create behaviour). Actions: `create | cancel | list`.
8
+ *
9
+ * The rich one-of timing validation lives in the create handler (reused
10
+ * verbatim); `cancel` reuses `unschedule`, `list` reuses `schedules`. The legacy
11
+ * `unschedule` / `schedules` names stay registered as forwarding aliases
12
+ * ({@link buildScheduleAliasTools}); there is no alias for `create` — the bare
13
+ * `schedule` IS create.
14
+ */
4
15
  export declare function buildScheduleTool(client: Client, config: Config, getPlayerId: () => string): TempoToolDescriptor;
16
+ /**
17
+ * Legacy forwarding aliases — `unschedule` → cancel, `schedules` → list. Each
18
+ * keeps its exact original schema + handler; description gains a deprecation
19
+ * note. No alias for `create` — the bare `schedule` IS create. Explicit object
20
+ * literals (see #793 brief §6 drift note).
21
+ */
22
+ export declare function buildScheduleAliasTools(client: Client, config: Config): TempoToolDescriptor[];
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.buildScheduleTool = buildScheduleTool;
4
+ exports.buildScheduleAliasTools = buildScheduleAliasTools;
4
5
  const zod_1 = require("zod");
5
6
  const croner_1 = require("croner");
6
7
  const client_1 = require("@temporalio/client");
@@ -8,9 +9,18 @@ const config_1 = require("../config");
8
9
  const duration_1 = require("../utils/duration");
9
10
  const resolve_1 = require("./resolve");
10
11
  const descriptor_1 = require("./descriptor");
12
+ const action_guard_1 = require("./action-guard");
13
+ const unschedule_1 = require("./unschedule");
14
+ const schedules_1 = require("./schedules");
11
15
  const validation_1 = require("../utils/validation");
12
16
  const log = (...args) => console.error('[agent-tempo:schedule]', ...args);
13
- function buildScheduleTool(client, config, getPlayerId) {
17
+ /**
18
+ * Internal create-only descriptor (the legacy bare-`schedule` behaviour). Its
19
+ * `.handler` is reused verbatim by the canonical {@link buildScheduleTool}
20
+ * dispatch under `action="create"`. Not exported — the canonical tool is the
21
+ * public surface.
22
+ */
23
+ function buildScheduleCreateTool(client, config, getPlayerId) {
14
24
  return {
15
25
  name: 'schedule',
16
26
  description: 'Schedule a message to be sent to a player at a specific time, after a delay, on a recurring interval, or via cron expression.',
@@ -155,3 +165,85 @@ function buildScheduleTool(client, config, getPlayerId) {
155
165
  },
156
166
  };
157
167
  }
168
+ /**
169
+ * Canonical `schedule` tool (#793 merge) — **reused** name, so `action` defaults
170
+ * to `'create'` for backward-compat (existing callers omit `action` → the legacy
171
+ * bare-`schedule` create behaviour). Actions: `create | cancel | list`.
172
+ *
173
+ * The rich one-of timing validation lives in the create handler (reused
174
+ * verbatim); `cancel` reuses `unschedule`, `list` reuses `schedules`. The legacy
175
+ * `unschedule` / `schedules` names stay registered as forwarding aliases
176
+ * ({@link buildScheduleAliasTools}); there is no alias for `create` — the bare
177
+ * `schedule` IS create.
178
+ */
179
+ function buildScheduleTool(client, config, getPlayerId) {
180
+ const create = buildScheduleCreateTool(client, config, getPlayerId);
181
+ const cancel = (0, unschedule_1.buildUnscheduleTool)(client, config);
182
+ const list = (0, schedules_1.buildSchedulesTool)(client, config);
183
+ return {
184
+ name: 'schedule',
185
+ description: 'Schedule messages to players (one-shot, delay, recurring, or cron). ' +
186
+ 'action="create" (default) schedules a message (name+message+target + one timing of at/delay/every/cron); ' +
187
+ 'action="cancel" removes a named schedule; ' +
188
+ 'action="list" shows all active schedules.',
189
+ params: {
190
+ action: zod_1.z.enum(['create', 'cancel', 'list']).optional().describe('Which schedule operation to perform (defaults to "create" when omitted)'),
191
+ // create:
192
+ name: zod_1.z.string().max(validation_1.SCHEDULE_NAME_MAX).optional().describe('create/cancel: unique name for this schedule'),
193
+ message: zod_1.z.string().max(validation_1.SCHEDULE_MESSAGE_MAX).optional().describe('create: the message to deliver'),
194
+ target: zod_1.z.string().max(validation_1.PLAYER_NAME_MAX).optional().describe('create: player to deliver to ("self" = this session)'),
195
+ at: zod_1.z.string().optional().describe('create: ISO datetime for one-shot delivery'),
196
+ delay: zod_1.z.string().optional().describe('create: duration until first delivery (e.g. "10m", "2h", "1d")'),
197
+ every: zod_1.z.string().optional().describe('create: recurring interval (e.g. "5m", "1h")'),
198
+ cron: zod_1.z.string().max(validation_1.CRON_EXPRESSION_MAX).optional().describe('create: cron expression. Mutually exclusive with at/delay/every.'),
199
+ timezone: zod_1.z.string().optional().describe('create: IANA timezone for cron evaluation (default UTC). Only with cron.'),
200
+ until: zod_1.z.string().optional().describe('create: ISO datetime — stop recurring after this time'),
201
+ count: zod_1.z.number().optional().describe('create: max number of deliveries for recurring schedules'),
202
+ },
203
+ handler: async (args) => {
204
+ const action = args.action ?? 'create';
205
+ switch (action) {
206
+ case 'create': {
207
+ const m = (0, action_guard_1.firstMissing)(args, ['name', 'message', 'target']);
208
+ if (m)
209
+ return (0, descriptor_1.fail)(`schedule action="create" requires "${m}".`);
210
+ return create.handler(args);
211
+ }
212
+ case 'cancel': {
213
+ const m = (0, action_guard_1.firstMissing)(args, ['name']);
214
+ if (m)
215
+ return (0, descriptor_1.fail)(`schedule action="cancel" requires "${m}".`);
216
+ return cancel.handler(args);
217
+ }
218
+ case 'list':
219
+ return list.handler(args);
220
+ default:
221
+ return (0, descriptor_1.fail)(`Unknown schedule action: ${String(action)}. Expected create | cancel | list.`);
222
+ }
223
+ },
224
+ };
225
+ }
226
+ /**
227
+ * Legacy forwarding aliases — `unschedule` → cancel, `schedules` → list. Each
228
+ * keeps its exact original schema + handler; description gains a deprecation
229
+ * note. No alias for `create` — the bare `schedule` IS create. Explicit object
230
+ * literals (see #793 brief §6 drift note).
231
+ */
232
+ function buildScheduleAliasTools(client, config) {
233
+ const cancel = (0, unschedule_1.buildUnscheduleTool)(client, config);
234
+ const list = (0, schedules_1.buildSchedulesTool)(client, config);
235
+ return [
236
+ {
237
+ name: 'unschedule',
238
+ description: 'DEPRECATED — use `schedule` with action="cancel". ' + cancel.description,
239
+ params: cancel.params,
240
+ handler: cancel.handler,
241
+ },
242
+ {
243
+ name: 'schedules',
244
+ description: 'DEPRECATED — use `schedule` with action="list". ' + list.description,
245
+ params: list.params,
246
+ handler: list.handler,
247
+ },
248
+ ];
249
+ }
@@ -1,3 +1,20 @@
1
1
  import { WorkflowHandle } from '@temporalio/client';
2
2
  import { type TempoToolDescriptor } from './descriptor';
3
+ /**
4
+ * Canonical `stage` tool (#793 merge) — **reused** name, so `action` defaults to
5
+ * `'create'` for backward-compat. Actions: `create | list | cancel` (all CRUD
6
+ * peers on the same StageEntry — see #793 brief §4). Conductor-only (gated in
7
+ * server-tools.ts).
8
+ *
9
+ * The legacy `stages` / `cancel_stage` names stay registered as forwarding
10
+ * aliases ({@link buildStageAliasTools}); there is no alias for `create` — the
11
+ * bare `stage` IS create.
12
+ */
3
13
  export declare function buildStageTool(handle: WorkflowHandle, getPlayerId: () => string): TempoToolDescriptor;
14
+ /**
15
+ * Legacy forwarding aliases — `stages` → list, `cancel_stage` → cancel. Each
16
+ * keeps its exact original schema + handler; description gains a deprecation
17
+ * note. No alias for `create` — the bare `stage` IS create. Explicit object
18
+ * literals (see #793 brief §6 drift note).
19
+ */
20
+ export declare function buildStageAliasTools(handle: WorkflowHandle): TempoToolDescriptor[];