agent-tempo 1.7.0 → 2.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) 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 +0 -10
  9. package/dist/activities/outbox.js +4 -2
  10. package/dist/adapters/base.js +3 -0
  11. package/dist/cli/commands.d.ts +8 -0
  12. package/dist/cli/commands.js +79 -11
  13. package/dist/cli/daemon-command.js +19 -33
  14. package/dist/cli/help-text.js +7 -7
  15. package/dist/cli/home-command.d.ts +26 -0
  16. package/dist/cli/home-command.js +156 -0
  17. package/dist/cli/removed-verbs.d.ts +0 -4
  18. package/dist/cli/removed-verbs.js +23 -12
  19. package/dist/cli/sa-preflight.d.ts +0 -14
  20. package/dist/cli/sa-preflight.js +1 -17
  21. package/dist/cli/startup.d.ts +1 -10
  22. package/dist/cli/startup.js +0 -40
  23. package/dist/cli.js +34 -80
  24. package/dist/client/core.js +13 -15
  25. package/dist/client/index.d.ts +2 -1
  26. package/dist/client/interface.d.ts +5 -14
  27. package/dist/client/with-spawn.d.ts +9 -4
  28. package/dist/client/with-spawn.js +7 -10
  29. package/dist/config.d.ts +0 -13
  30. package/dist/constants.d.ts +22 -0
  31. package/dist/constants.js +23 -1
  32. package/dist/daemon.js +52 -0
  33. package/dist/http/auth.d.ts +3 -21
  34. package/dist/http/auth.js +10 -31
  35. package/dist/http/event-types.d.ts +5 -4
  36. package/dist/http/orphans.d.ts +3 -3
  37. package/dist/http/orphans.js +3 -3
  38. package/dist/http/server.d.ts +0 -5
  39. package/dist/http/server.js +69 -29
  40. package/dist/http/writes.d.ts +1 -1
  41. package/dist/http/writes.js +25 -2
  42. package/dist/palette/index.d.ts +6 -7
  43. package/dist/palette/index.js +6 -7
  44. package/dist/pi/mission-control/actions.d.ts +67 -1
  45. package/dist/pi/mission-control/actions.js +61 -0
  46. package/dist/pi/mission-control/extension.d.ts +77 -0
  47. package/dist/pi/mission-control/extension.js +171 -0
  48. package/dist/pi/workflow-client.d.ts +14 -16
  49. package/dist/pi/workflow-client.js +18 -44
  50. package/dist/types.d.ts +15 -6
  51. package/dist/upgrade/boot-guard.d.ts +95 -0
  52. package/dist/upgrade/boot-guard.js +88 -0
  53. package/dist/upgrade/from-upgrade.d.ts +95 -0
  54. package/dist/upgrade/from-upgrade.js +330 -0
  55. package/dist/upgrade/phase-engine.js +4 -1
  56. package/dist/utils/duration.d.ts +3 -6
  57. package/dist/utils/duration.js +3 -6
  58. package/dist/utils/format-hosts.d.ts +1 -1
  59. package/dist/utils/format-hosts.js +0 -2
  60. package/dist/utils/grpc-shutdown-guard.js +0 -4
  61. package/dist/utils/hosts.d.ts +4 -10
  62. package/dist/utils/hosts.js +12 -28
  63. package/dist/utils/search-attributes.d.ts +27 -18
  64. package/dist/utils/search-attributes.js +39 -18
  65. package/dist/utils/visibility-deadline.d.ts +16 -0
  66. package/dist/utils/visibility-deadline.js +16 -0
  67. package/dist/workflows/maestro-signals.d.ts +0 -13
  68. package/dist/workflows/maestro-signals.js +6 -14
  69. package/dist/workflows/maestro.js +27 -32
  70. package/dist/workflows/scheduler.js +7 -1
  71. package/dist/workflows/session.js +44 -110
  72. package/dist/workflows/signals.d.ts +9 -1
  73. package/dist/workflows/signals.js +8 -6
  74. package/package.json +1 -6
  75. package/workflow-bundle.js +239 -182
  76. package/dist/cli/legacy-migration.d.ts +0 -35
  77. package/dist/cli/legacy-migration.js +0 -341
  78. package/dist/client/ensure-conductor-spawned.d.ts +0 -35
  79. package/dist/client/ensure-conductor-spawned.js +0 -48
  80. package/dist/tui/App.d.ts +0 -85
  81. package/dist/tui/App.js +0 -1791
  82. package/dist/tui/bootstrap-types.d.ts +0 -46
  83. package/dist/tui/bootstrap-types.js +0 -7
  84. package/dist/tui/commands.d.ts +0 -71
  85. package/dist/tui/commands.js +0 -1375
  86. package/dist/tui/components/ChatView.d.ts +0 -35
  87. package/dist/tui/components/ChatView.js +0 -54
  88. package/dist/tui/components/CommandPalette.d.ts +0 -21
  89. package/dist/tui/components/CommandPalette.js +0 -67
  90. package/dist/tui/components/ConversationStream.d.ts +0 -114
  91. package/dist/tui/components/ConversationStream.js +0 -307
  92. package/dist/tui/components/CreateEnsembleWizard.d.ts +0 -19
  93. package/dist/tui/components/CreateEnsembleWizard.js +0 -223
  94. package/dist/tui/components/DestroyConfirmModal.d.ts +0 -17
  95. package/dist/tui/components/DestroyConfirmModal.js +0 -62
  96. package/dist/tui/components/ErrorView.d.ts +0 -31
  97. package/dist/tui/components/ErrorView.js +0 -129
  98. package/dist/tui/components/HomeView.d.ts +0 -54
  99. package/dist/tui/components/HomeView.js +0 -306
  100. package/dist/tui/components/LoadLineupModal.d.ts +0 -18
  101. package/dist/tui/components/LoadLineupModal.js +0 -79
  102. package/dist/tui/components/MainView.d.ts +0 -21
  103. package/dist/tui/components/MainView.js +0 -107
  104. package/dist/tui/components/NewEnsembleModal.d.ts +0 -9
  105. package/dist/tui/components/NewEnsembleModal.js +0 -73
  106. package/dist/tui/components/Picker.d.ts +0 -23
  107. package/dist/tui/components/Picker.js +0 -70
  108. package/dist/tui/components/PlayerDetailView.d.ts +0 -26
  109. package/dist/tui/components/PlayerDetailView.js +0 -118
  110. package/dist/tui/components/PromptArea.d.ts +0 -50
  111. package/dist/tui/components/PromptArea.js +0 -303
  112. package/dist/tui/components/RecruitWizard.d.ts +0 -17
  113. package/dist/tui/components/RecruitWizard.js +0 -221
  114. package/dist/tui/components/RestoreConfirmModal.d.ts +0 -18
  115. package/dist/tui/components/RestoreConfirmModal.js +0 -71
  116. package/dist/tui/components/ScheduleWizard.d.ts +0 -19
  117. package/dist/tui/components/ScheduleWizard.js +0 -259
  118. package/dist/tui/components/Splash.d.ts +0 -23
  119. package/dist/tui/components/Splash.js +0 -221
  120. package/dist/tui/components/StatusBar.d.ts +0 -48
  121. package/dist/tui/components/StatusBar.js +0 -128
  122. package/dist/tui/components/StatusOverlay.d.ts +0 -15
  123. package/dist/tui/components/StatusOverlay.js +0 -76
  124. package/dist/tui/components/TitleBar.d.ts +0 -10
  125. package/dist/tui/components/TitleBar.js +0 -21
  126. package/dist/tui/index.d.ts +0 -15
  127. package/dist/tui/index.js +0 -162
  128. package/dist/tui/ink-context.d.ts +0 -18
  129. package/dist/tui/ink-context.js +0 -59
  130. package/dist/tui/ink-loader.d.ts +0 -26
  131. package/dist/tui/ink-loader.js +0 -42
  132. package/dist/tui/removed-commands.d.ts +0 -9
  133. package/dist/tui/removed-commands.js +0 -22
  134. package/dist/tui/sse-handler.d.ts +0 -52
  135. package/dist/tui/sse-handler.js +0 -157
  136. package/dist/tui/store.d.ts +0 -598
  137. package/dist/tui/store.js +0 -753
  138. package/dist/tui/utils/format.d.ts +0 -56
  139. package/dist/tui/utils/format.js +0 -155
  140. package/dist/tui/utils/fullscreen.d.ts +0 -23
  141. package/dist/tui/utils/fullscreen.js +0 -71
  142. package/dist/tui/utils/history.d.ts +0 -10
  143. package/dist/tui/utils/history.js +0 -85
  144. package/dist/tui/utils/platform.d.ts +0 -45
  145. package/dist/tui/utils/platform.js +0 -258
  146. package/dist/tui/utils/theme.d.ts +0 -21
  147. package/dist/tui/utils/theme.js +0 -24
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.agentSessionWorkflow = agentSessionWorkflow;
4
4
  const workflow_1 = require("@temporalio/workflow");
5
5
  const search_attributes_1 = require("../utils/search-attributes");
6
+ const constants_1 = require("../constants");
6
7
  const common_1 = require("@temporalio/common");
7
8
  /**
8
9
  * Workflow-deterministic clock. The Temporal TS SDK intercepts `new Date()` at the
@@ -61,15 +62,6 @@ async function agentSessionWorkflow(input) {
61
62
  // PR-C commit 6 (#119a): each attachment carries its own `leaseMs` (negotiated at
62
63
  // claim time). No workflow-side default constant — heartbeats extend `expiresAt`
63
64
  // by `currentAttachment.leaseMs`.
64
- /**
65
- * Legacy CAN-extension constant. Retained solely so sessions that ran on a
66
- * pre-#249 workflow bundle replay deterministically: the `patched()` branch at
67
- * the CAN-boundary extension site selects this constant on the non-patched
68
- * side, matching the exact arg sequence those histories recorded. New runs
69
- * (and all post-#249 CAN transitions) use `currentAttachment.leaseMs` instead
70
- * — see the call site below.
71
- */
72
- const HEARTBEAT_INTERVAL_MS = 30_000;
73
65
  /**
74
66
  * Default grace period for `draining → detached` transition after requestDetach. Used when a
75
67
  * `requestDetach` signal omits `deadlineMs`. Per-signal overrides are honored via the
@@ -78,65 +70,26 @@ async function agentSessionWorkflow(input) {
78
70
  const DEFAULT_DRAINING_DEADLINE_MS = 5_000;
79
71
  /** Max duration a messageId can stay in-flight before the safety timer ejects it. */
80
72
  const PROCESSING_DEADLINE_MS = 15 * 60 * 1000;
81
- // Version marker for v0.10 records a patch marker in workflow history.
82
- // Future workflow changes that alter the command sequence should use
83
- // patched('v0.10-<change-name>') to protect in-flight sessions from
84
- // non-determinism errors during rolling deploys.
85
- (0, workflow_1.patched)('v0.10-initial');
86
- (0, workflow_1.patched)('v0.11-check-and-set-status');
87
- (0, workflow_1.patched)('v0.13-quality-gates');
88
- (0, workflow_1.patched)('v0.14-worktrees');
89
- (0, workflow_1.patched)('v0.15-blocked-detection');
90
- (0, workflow_1.patched)('v0.18-stages');
91
- (0, workflow_1.patched)('v0.23-hold-release');
92
- (0, workflow_1.patched)('v0.25-attachment-lifecycle');
93
- // Issue #172: kept as a replay marker for workflows that predate the
94
- // simpler hold-on-startup design (v0.26). The state field + interceptor
95
- // were removed in favor of baking the banner/directive into
96
- // `SessionInput.messages` at workflow creation, but leaving the patched
97
- // marker ensures existing replay histories that recorded this command
98
- // still deserialize cleanly. Safe no-op today.
99
- (0, workflow_1.patched)('v0.26-pending-startup-context');
100
- // ── T0.5 SA diet (#747) — ONE marker gates the whole diet ──
101
- //
102
- // New runs (incl. post-deploy CAN successors — fresh executions re-record
103
- // the marker) stop writing the read-only/write-only search attributes:
104
- // - AgentTempoGitRoot / AgentTempoPlayerType / AgentTempoIsConductor
105
- // migrate to the workflow MEMO (low-churn fields only — NEVER memo
106
- // counters like activityCount/lastActivityAt: memo upserts are
107
- // billable actions, that would trade query actions for upsert actions).
108
- // - AgentTempoAttachmentId is dropped outright (zero readers anywhere;
109
- // adapters correlate via the claimAttachment token).
110
- // Old histories replay the recorded SA-write branch unchanged — safe,
111
- // because any namespace with such histories has the legacy SAs registered.
112
- // Readers go through the dual-read helpers in utils/search-attributes.ts
113
- // (memo preferred, SA fallback). Filter SAs (Ensemble, PlayerId, Hostname,
114
- // AttachedHost, AttachmentState) are untouched — they appear in visibility
115
- // query expressions and MUST stay search attributes.
116
- const saDiet = (0, workflow_1.patched)('v1.8-sa-diet');
117
- // T0.1 (#748) — the observation-path memo extension: workDir / agentType /
118
- // gitBranch join the memo so the cloud-profile maestro scan can read the
119
- // full player row from visibility list results (zero per-player queries).
120
- // Payload-only upsertMemo change, but gated behind its own marker per the
121
- // repo's conservative determinism policy. All three pass the low-churn bar
122
- // (workDir/agentType set-at-start; gitBranch via rare updateMetadata).
123
- const memoObservationFields = (0, workflow_1.patched)('v1.8-memo-observation-fields');
73
+ // ── 2.0 clean-slate (#787) ──
74
+ // The replay-only `patched()` markers that protected in-flight 1.x sessions
75
+ // across rolling deploys are gone: 2.0 is a hard cutover (the #786 boot guard
76
+ // refuses to replay any 1.x history), so there are no pre-patch histories left
77
+ // to protect. The SA-diet (#747) and observation-field memo (#748) behavior is
78
+ // now unconditional — the new path IS the only path.
124
79
  /**
125
80
  * T0.5 — the memo mirror of the migrated read-only metadata fields.
126
81
  * Shared by the run-start upsert and the updateMetadata handler so the
127
82
  * two write sites can't drift. Key names come from the shared
128
83
  * {@link MEMO_KEYS} registry (also used by the client-side
129
- * `workflow.start({ memo })` seeds and the dual-read helpers).
84
+ * `workflow.start({ memo })` seeds and the memo readers).
130
85
  */
131
86
  const metaMemo = () => ({
132
87
  ...(input.metadata.gitRoot ? { [search_attributes_1.MEMO_KEYS.gitRoot]: input.metadata.gitRoot } : {}),
133
88
  ...(input.metadata.playerType ? { [search_attributes_1.MEMO_KEYS.playerType]: input.metadata.playerType } : {}),
134
89
  [search_attributes_1.MEMO_KEYS.isConductor]: input.metadata.isConductor === true,
135
- ...(memoObservationFields ? {
136
- [search_attributes_1.MEMO_KEYS.workDir]: input.metadata.workDir,
137
- [search_attributes_1.MEMO_KEYS.agentType]: input.metadata.agentType || 'claude',
138
- ...(input.metadata.gitBranch ? { [search_attributes_1.MEMO_KEYS.gitBranch]: input.metadata.gitBranch } : {}),
139
- } : {}),
90
+ [search_attributes_1.MEMO_KEYS.workDir]: input.metadata.workDir,
91
+ [search_attributes_1.MEMO_KEYS.agentType]: input.metadata.agentType || 'claude',
92
+ ...(input.metadata.gitBranch ? { [search_attributes_1.MEMO_KEYS.gitBranch]: input.metadata.gitBranch } : {}),
140
93
  });
141
94
  // Ensure search attributes are always current — critical when reconnecting
142
95
  // via WorkflowIdConflictPolicy.USE_EXISTING, which skips the attributes
@@ -145,17 +98,20 @@ async function agentSessionWorkflow(input) {
145
98
  AgentTempoEnsemble: [input.metadata.ensemble],
146
99
  AgentTempoPlayerId: [input.metadata.playerId],
147
100
  AgentTempoHostname: [input.metadata.hostname],
148
- ...(saDiet ? {} : {
149
- ...(input.metadata.gitRoot ? { AgentTempoGitRoot: [input.metadata.gitRoot] } : {}),
150
- ...(input.metadata.playerType ? { AgentTempoPlayerType: [input.metadata.playerType] } : {}),
151
- AgentTempoIsConductor: [input.metadata.isConductor === true],
152
- }),
153
101
  // v0.25 attachment search attributes — initial values for a fresh/restored workflow.
154
102
  // Updated on every phase transition below.
155
103
  AgentTempoAttachedHost: [input.currentAttachment?.hostname ?? ''],
156
104
  AgentTempoAttachmentState: [input.phase ?? 'booting'],
157
- ...(saDiet ? {} : { AgentTempoAttachmentId: [input.currentAttachment?.attachmentId ?? ''] }),
158
105
  });
106
+ // #786 — 2.0 cutover protocol STAMP. Authoritative from the constant (this IS
107
+ // the 2.0 bundle → always PROTOCOL_VERSION, regardless of `input.protocol`).
108
+ // Re-upserted on EVERY run, incl. continueAsNew successors, so visibility
109
+ // always shows the stamp for the daemon boot guard — no need to thread a memo
110
+ // arg through the CAN payload. A 1.x run never executes this, so the guard
111
+ // sees its memo as undefined → un-stamped → refuse. Unconditional (no
112
+ // `patched()` marker): #786 is the first change on the 2.0 line, so there are
113
+ // no pre-stamp v2 histories to protect from this new command.
114
+ (0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.protocol]: constants_1.PROTOCOL_VERSION });
159
115
  // ── State (carried across continue-as-new) ──
160
116
  let part = input.part ?? input.autoSummary ?? 'No description set';
161
117
  // T0.5 (#747) — memo carrier for the migrated read-only fields + part.
@@ -164,9 +120,7 @@ async function agentSessionWorkflow(input) {
164
120
  // `memo` option so the fields are visible before the first workflow task
165
121
  // (and on standard-visibility servers whose list results may lag memo
166
122
  // upserts — see PR #747 T0.5 notes). Low-churn fields ONLY.
167
- if (saDiet) {
168
- (0, workflow_1.upsertMemo)({ ...metaMemo(), [search_attributes_1.MEMO_KEYS.part]: part });
169
- }
123
+ (0, workflow_1.upsertMemo)({ ...metaMemo(), [search_attributes_1.MEMO_KEYS.part]: part });
170
124
  const messages = input.messages ?? [];
171
125
  const sentMessages = input.sentMessages ?? [];
172
126
  const outbox = input.outbox ?? [];
@@ -408,7 +362,7 @@ async function agentSessionWorkflow(input) {
408
362
  // #399 W2 — every inbound cue counts as received traffic.
409
363
  receivedCount++;
410
364
  // Track inbound messages that expect a response (default: true for backward compat)
411
- if ((0, workflow_1.patched)('v0.20-response-requested-blocked') && msg.responseRequested !== false) {
365
+ if (msg.responseRequested !== false) {
412
366
  lastInboundRRTime = workflowNow().getTime();
413
367
  }
414
368
  });
@@ -418,8 +372,7 @@ async function agentSessionWorkflow(input) {
418
372
  // daemon aggregate — T0.1) can read it from visibility list results
419
373
  // instead of a per-player getPart query. Low-churn by nature: part
420
374
  // changes when a player re-describes its work, not per message.
421
- if (saDiet)
422
- (0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.part]: newPart });
375
+ (0, workflow_1.upsertMemo)({ [search_attributes_1.MEMO_KEYS.part]: newPart });
423
376
  lastActivityTime = workflowNow().getTime();
424
377
  activityCount++;
425
378
  lastOutboundTime = workflowNow().getTime();
@@ -461,7 +414,6 @@ async function agentSessionWorkflow(input) {
461
414
  lastActivityTime = workflowNow().getTime();
462
415
  activityCount++;
463
416
  });
464
- (0, workflow_1.setHandler)(signals_1.pendingResetQuery, () => pendingReset);
465
417
  (0, workflow_1.setHandler)(signals_1.ackResetSignal, (resetId) => {
466
418
  // Race-safe: only clear if the ack matches the current pending reset, so a
467
419
  // newer reset landing during the extension's wipe isn't silently dropped.
@@ -494,16 +446,10 @@ async function agentSessionWorkflow(input) {
494
446
  AgentTempoEnsemble: [input.metadata.ensemble],
495
447
  AgentTempoPlayerId: [input.metadata.playerId],
496
448
  AgentTempoHostname: [input.metadata.hostname],
497
- ...(saDiet ? {} : {
498
- ...(input.metadata.gitRoot ? { AgentTempoGitRoot: [input.metadata.gitRoot] } : {}),
499
- ...(input.metadata.playerType ? { AgentTempoPlayerType: [input.metadata.playerType] } : {}),
500
- AgentTempoIsConductor: [input.metadata.isConductor === true],
501
- }),
502
449
  });
503
450
  // T0.5 — keep the memo mirror current (low-churn: metadata updates are
504
451
  // rare lifecycle events, not per-message traffic).
505
- if (saDiet)
506
- (0, workflow_1.upsertMemo)(metaMemo());
452
+ (0, workflow_1.upsertMemo)(metaMemo());
507
453
  lastActivityTime = workflowNow().getTime();
508
454
  activityCount++;
509
455
  });
@@ -711,7 +657,6 @@ async function agentSessionWorkflow(input) {
711
657
  }
712
658
  (0, workflow_1.upsertSearchAttributes)({
713
659
  AgentTempoAttachedHost: [''],
714
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
715
660
  });
716
661
  setPhase('gone');
717
662
  // Inject a final audit message so the old adapter-completion path has something to show.
@@ -799,13 +744,23 @@ async function agentSessionWorkflow(input) {
799
744
  setPhase('attached');
800
745
  (0, workflow_1.upsertSearchAttributes)({
801
746
  AgentTempoAttachedHost: [host],
802
- ...(saDiet ? {} : { AgentTempoAttachmentId: [newAttachment.attachmentId] }),
803
747
  });
804
748
  lastActivityTime = nowMs;
805
749
  activityCount++;
806
750
  return attachmentTokenFrom(newAttachment, leaseMs);
807
751
  }, {
808
- validator: ({ leaseMs }) => {
752
+ validator: ({ host, leaseMs, protocolVersion }) => {
753
+ // #786 — cross-host cutover safety, checked FIRST (pure, synchronous, no
754
+ // IO, no history event — rejects pre-admission). A v1 adapter omits
755
+ // `protocolVersion` (→ undefined); any value other than PROTOCOL_VERSION is
756
+ // a stale/foreign adapter that must not claim this 2.0 workflow. Actionable
757
+ // error names the host + the fix.
758
+ if (protocolVersion !== constants_1.PROTOCOL_VERSION) {
759
+ throw common_1.ApplicationFailure.nonRetryable(`claimAttachment rejected on ${(0, workflow_1.workflowInfo)().workflowId}: adapter on host ` +
760
+ `'${host}' speaks protocol ${protocolVersion ?? '(v1/unset)'}, but this is a ` +
761
+ `protocol-${constants_1.PROTOCOL_VERSION} (2.0) workflow. Upgrade the agent-tempo install on ` +
762
+ `that host to 2.0 (it cannot drive a 2.0 session).`, 'ProtocolMismatch');
763
+ }
809
764
  if (!Number.isInteger(leaseMs) || leaseMs < 1_000 || leaseMs > 600_000) {
810
765
  throw common_1.ApplicationFailure.nonRetryable(`leaseMs must be between 1000 and 600000, got ${leaseMs}`, 'InvalidLease');
811
766
  }
@@ -881,7 +836,7 @@ async function agentSessionWorkflow(input) {
881
836
  // mismatch any history that recorded the race — conservative tiebreak.
882
837
  // Evaluated lazily (the v0.26-can-lease-from-attachment single-use
883
838
  // precedent): only histories that hit forceDetach record the marker.
884
- if ((0, workflow_1.patched)('v0.27-force-detach-recheck') && currentAttachment?.attachmentId !== reaped.attachmentId) {
839
+ if (currentAttachment?.attachmentId !== reaped.attachmentId) {
885
840
  workflow_1.log.info(`forceDetach: attachment changed during hard-terminate await ` +
886
841
  `(expected ${reaped.attachmentId}, now ${currentAttachment?.attachmentId ?? 'none'}) — ` +
887
842
  `not clobbering the fresh claim`);
@@ -898,7 +853,6 @@ async function agentSessionWorkflow(input) {
898
853
  setPhase('detached');
899
854
  (0, workflow_1.upsertSearchAttributes)({
900
855
  AgentTempoAttachedHost: [''],
901
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
902
856
  });
903
857
  // #159 Gap 1b: wake the main loop — `phase === 'detached'` isn't in the predicate
904
858
  // and the condition would otherwise sleep on the now-stale lease-expiry deadline.
@@ -1025,7 +979,6 @@ async function agentSessionWorkflow(input) {
1025
979
  setPhase('detached');
1026
980
  (0, workflow_1.upsertSearchAttributes)({
1027
981
  AgentTempoAttachedHost: [''],
1028
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
1029
982
  });
1030
983
  lastActivityTime = workflowNow().getTime();
1031
984
  activityCount++;
@@ -1356,12 +1309,10 @@ async function agentSessionWorkflow(input) {
1356
1309
  // live handler. Reconciled entries keep the ORIGINAL receipt time as
1357
1310
  // `reportedAt` and carry `reconciled: true`.
1358
1311
  //
1359
- // patched() gate: stage state itself drives no commands, but the
1360
- // completion/failure messages pushed here join `messages`, which
1361
- // participates in main-loop condition predicates whose resolution
1362
- // interleaves with recorded timer commands — a command-sequence
1363
- // dependency on replay. Conservative tiebreak per the ruling: marker.
1364
- if ((0, workflow_1.patched)('v0.27-stage-reconcile-reports')) {
1312
+ // Stage reconciliation fold each player's latest result/blocker report
1313
+ // into stage status, then apply the stage's completion/failure transitions.
1314
+ // (2.0: was patched()-gated for 1.x replay determinism; now unconditional — #787.)
1315
+ {
1365
1316
  const nowMs = workflowNow().getTime();
1366
1317
  for (const playerEntry of entry.players) {
1367
1318
  // Most recent stage-relevant (result|blocker) report from this
@@ -1543,7 +1494,6 @@ async function agentSessionWorkflow(input) {
1543
1494
  setPhase('detached');
1544
1495
  (0, workflow_1.upsertSearchAttributes)({
1545
1496
  AgentTempoAttachedHost: [''],
1546
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
1547
1497
  });
1548
1498
  workflow_1.log.warn(`lease expired for attachment ${reaped.attachmentId} (host=${reaped.hostname})`);
1549
1499
  }
@@ -1607,7 +1557,6 @@ async function agentSessionWorkflow(input) {
1607
1557
  setPhase('detached');
1608
1558
  (0, workflow_1.upsertSearchAttributes)({
1609
1559
  AgentTempoAttachedHost: [''],
1610
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
1611
1560
  });
1612
1561
  if (reaped) {
1613
1562
  workflow_1.log.info(`drainingDeadline exceeded (${Math.round(window / 1000)}s); ` +
@@ -1830,7 +1779,6 @@ async function agentSessionWorkflow(input) {
1830
1779
  setPhase('detached');
1831
1780
  (0, workflow_1.upsertSearchAttributes)({
1832
1781
  AgentTempoAttachedHost: [''],
1833
- ...(saDiet ? {} : { AgentTempoAttachmentId: [''] }),
1834
1782
  });
1835
1783
  workflow_1.log.warn(`spawn failed for "${entry.targetName}"; rolled back attachment ${entry.attachmentId} → detached`);
1836
1784
  }
@@ -1873,25 +1821,11 @@ async function agentSessionWorkflow(input) {
1873
1821
  // matches what the adapter signed up for and covers at least one full heartbeat
1874
1822
  // interval for every adapter class.
1875
1823
  //
1876
- // The `patched()` gate keeps replay of pre-#249 workflow runs deterministic:
1877
- // histories that CAN'd on the old bundle recorded `extendAttachmentForCAN(…, 30_000, …)`,
1878
- // so replaying those runs must pick the legacy constant. New runs (and in-flight
1879
- // runs that CAN *after* the deploy) take the patched branch.
1880
- //
1881
1824
  // Math lives in `./attachment-math.ts` for direct unit testability (#127).
1882
- //
1883
- // #255 cleanup: the `patched()` call stays at the eager/unconditional
1884
- // position it was introduced in — relocating it inside the
1885
- // `currentAttachment ?` branch would skip marker recording on histories
1886
- // that hit the CAN site with a null attachment, risking replay
1887
- // non-determinism against those recordings. The dead-code cleanup is
1888
- // strictly the removal of the `?? HEARTBEAT_INTERVAL_MS` fallback that
1889
- // used to sit inside the ternary: on the patched branch it never fires
1890
- // (Attachment.leaseMs is required), and on the pre-patched branch the
1891
- // fallback is replaced by the bare constant — same value either way.
1892
- const usePatchedLease = (0, workflow_1.patched)('v0.26-can-lease-from-attachment');
1825
+ // (2.0: the v0.26-can-lease-from-attachment patched() gate is gone — #787 —
1826
+ // so CAN always extends by `currentAttachment.leaseMs` = 3 × heartbeatMs.)
1893
1827
  const extendedAttachment = currentAttachment
1894
- ? (0, attachment_math_1.extendAttachmentForCAN)(currentAttachment, usePatchedLease ? currentAttachment.leaseMs : HEARTBEAT_INTERVAL_MS, workflowNow().getTime())
1828
+ ? (0, attachment_math_1.extendAttachmentForCAN)(currentAttachment, currentAttachment.leaseMs, workflowNow().getTime())
1895
1829
  : undefined;
1896
1830
  await (0, workflow_1.continueAsNew)({
1897
1831
  ...input,
@@ -40,7 +40,6 @@ export declare const setPendingResetSignal: import("@temporalio/workflow").Signa
40
40
  reason?: string;
41
41
  requestedBy?: string;
42
42
  }], string>;
43
- export declare const pendingResetQuery: import("@temporalio/workflow").QueryDefinition<PendingReset | null, [], string>;
44
43
  export declare const ackResetSignal: import("@temporalio/workflow").SignalDefinition<[string], string>;
45
44
  /** Result shape of {@link pendingIntakeQuery}. */
46
45
  export interface PendingIntake {
@@ -110,6 +109,15 @@ export declare const claimAttachmentUpdate: import("@temporalio/common").UpdateD
110
109
  leaseMs: number;
111
110
  /** Present on renewal; absent on fresh claim. */
112
111
  expectedAttachmentId?: string;
112
+ /**
113
+ * #786 — REQUIRED 2.0-wire field: the adapter's protocol version
114
+ * (`PROTOCOL_VERSION`). A 2.0 workflow rejects any value `!== PROTOCOL_VERSION`
115
+ * (incl. `undefined` = a v1 adapter) in the update VALIDATOR — pre-admission,
116
+ * no history event — with an actionable error naming the host + the upgrade
117
+ * command. Cross-host cutover safety: a stale 1.x adapter on another machine
118
+ * cannot silently claim a 2.0 workflow.
119
+ */
120
+ protocolVersion: number;
113
121
  }], string>;
114
122
  /**
115
123
  * Revoke the current attachment. Options for drain-grace behavior during `draining` phase.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.evaluateGateCriteriaSignal = exports.setQualityGateSignal = exports.testForceContinueAsNewSignal = exports.getCoarseActivityQuery = exports.getLeaseStateQuery = exports.getActivityStateQuery = exports.getMessagingStateQuery = exports.getRunIdQuery = exports.outboxQuery = exports.submitOutboxUpdate = exports.playerStateKeysQuery = exports.playerStateQuery = exports.clearPlayerStateUpdate = exports.savePlayerStateUpdate = exports.orphanSummaryQuery = exports.attachmentInfoQuery = exports.adapterExitedSignal = exports.requestDetachSignal = exports.heartbeatSignal = exports.setPreferredHostUpdate = exports.enqueueSpawnUpdate = exports.forceDetachUpdate = exports.claimAttachmentUpdate = exports.isDestroyedQuery = exports.destroyUpdate = exports.inFlightMessagesQuery = exports.processingEndUpdate = exports.processingStartUpdate = exports.historyQuery = exports.playerReportSignal = exports.commandSignal = exports.pausedQuery = exports.setPausedSignal = exports.outboxLockedQuery = exports.releaseHeldSignal = exports.pendingIntakeQuery = exports.ackResetSignal = exports.pendingResetQuery = exports.setPendingResetSignal = exports.allSentMessagesQuery = exports.allMessagesQuery = exports.pendingMessagesQuery = exports.getMetadataQuery = exports.getPartQuery = exports.updateMetadataSignal = exports.setNameSignal = exports.markDeliveredSignal = exports.setPartSignal = exports.recordSentMessageSignal = exports.receiveMessageSignal = void 0;
4
- exports.stagesQuery = exports.cancelStageSignal = exports.setStageSignal = exports.worktreesQuery = exports.removeWorktreeSignal = exports.setWorktreeSignal = exports.qualityGatesQuery = void 0;
3
+ exports.qualityGatesQuery = exports.evaluateGateCriteriaSignal = exports.setQualityGateSignal = exports.testForceContinueAsNewSignal = exports.getCoarseActivityQuery = exports.getLeaseStateQuery = exports.getActivityStateQuery = exports.getMessagingStateQuery = exports.getRunIdQuery = exports.outboxQuery = exports.submitOutboxUpdate = exports.playerStateKeysQuery = exports.playerStateQuery = exports.clearPlayerStateUpdate = exports.savePlayerStateUpdate = exports.orphanSummaryQuery = exports.attachmentInfoQuery = exports.adapterExitedSignal = exports.requestDetachSignal = exports.heartbeatSignal = exports.setPreferredHostUpdate = exports.enqueueSpawnUpdate = exports.forceDetachUpdate = exports.claimAttachmentUpdate = exports.isDestroyedQuery = exports.destroyUpdate = exports.inFlightMessagesQuery = exports.processingEndUpdate = exports.processingStartUpdate = exports.historyQuery = exports.playerReportSignal = exports.commandSignal = exports.pausedQuery = exports.setPausedSignal = exports.outboxLockedQuery = exports.releaseHeldSignal = exports.pendingIntakeQuery = exports.ackResetSignal = exports.setPendingResetSignal = exports.allSentMessagesQuery = exports.allMessagesQuery = exports.pendingMessagesQuery = exports.getMetadataQuery = exports.getPartQuery = exports.updateMetadataSignal = exports.setNameSignal = exports.markDeliveredSignal = exports.setPartSignal = exports.recordSentMessageSignal = exports.receiveMessageSignal = void 0;
4
+ exports.stagesQuery = exports.cancelStageSignal = exports.setStageSignal = exports.worktreesQuery = exports.removeWorktreeSignal = exports.setWorktreeSignal = void 0;
5
5
  const workflow_1 = require("@temporalio/workflow");
6
6
  // ── Player Signals ──
7
7
  // `isScheduled` + `scheduleName` are set by `src/activities/schedule-fire.ts`
@@ -29,11 +29,13 @@ exports.allMessagesQuery = (0, workflow_1.defineQuery)('allMessages');
29
29
  exports.allSentMessagesQuery = (0, workflow_1.defineQuery)('allSentMessages');
30
30
  // ── Reset (D14) — context clean-wipe poll-delivery ──
31
31
  // `deliverReset` sets the pending flag via `setPendingResetSignal`; the Pi
32
- // extension polls `pendingResetQuery`, performs the wipe (newSession), then
33
- // clears it via `ackResetSignal(resetId)`. Single-slot, latest-wins. The
34
- // workflow stamps `requestedAt` (deterministic). See WIRE-PROTOCOL.md.
32
+ // extension reads the pending reset off the combined `pendingIntakeQuery`
33
+ // (`.pendingReset`), performs the wipe (newSession), then clears it via
34
+ // `ackResetSignal(resetId)`. Single-slot, latest-wins. The workflow stamps
35
+ // `requestedAt` (deterministic). See WIRE-PROTOCOL.md.
36
+ // 2.0 (#788): the standalone `pendingResetQuery` ('pendingReset') was removed —
37
+ // reset now rides the combined `pendingIntake` query; these signals stay.
35
38
  exports.setPendingResetSignal = (0, workflow_1.defineSignal)('setPendingReset');
36
- exports.pendingResetQuery = (0, workflow_1.defineQuery)('pendingReset');
37
39
  exports.ackResetSignal = (0, workflow_1.defineSignal)('ackReset');
38
40
  exports.pendingIntakeQuery = (0, workflow_1.defineQuery)('pendingIntake');
39
41
  // ── Hold / Release ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-tempo",
3
- "version": "1.7.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "Many agents, one tempo. Durable coordination for multi-agent work via Temporal.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -110,12 +110,8 @@
110
110
  "@temporalio/worker": "~1.15.0",
111
111
  "@temporalio/workflow": "~1.15.0",
112
112
  "croner": "^10.0.1",
113
- "ink": "^6.8.0",
114
- "ink-spinner": "^5.0.0",
115
- "ink-text-input": "^6.0.0",
116
113
  "p-limit": "^3.1.0",
117
114
  "qrcode-terminal": "^0.12.0",
118
- "react": "^19.2.4",
119
115
  "semver": "^7.7.4",
120
116
  "typebox": "^1.0.1",
121
117
  "yaml": "^2.8.3",
@@ -127,7 +123,6 @@
127
123
  "@types/chai": "^4.3.20",
128
124
  "@types/mocha": "^10.0.10",
129
125
  "@types/node": "^20.0.0",
130
- "@types/react": "^19.2.14",
131
126
  "@types/semver": "^7.7.1",
132
127
  "chai": "^4.5.0",
133
128
  "mocha": "^11.7.5",