@sema-agent/client-core 0.104.1 → 0.105.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 (86) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/README.md +11 -4
  3. package/dist/adapt/arms.js +14 -6
  4. package/dist/adapter/activeRunSelfHeal.d.ts +1 -0
  5. package/dist/adapter/activeRunSelfHeal.js +10 -5
  6. package/dist/adapter/downstream/eventToSdkMessage.js +4 -4
  7. package/dist/adapter/downstream/wiringManifestView.d.ts +6 -0
  8. package/dist/adapter/downstream/wiringManifestView.js +25 -0
  9. package/dist/adapter/runStream.js +5 -1
  10. package/dist/cloudConfigWireCaps.js +3 -0
  11. package/dist/compensations.js +6 -6
  12. package/dist/coreValuePorts.d.ts +3 -1
  13. package/dist/coreValuePorts.js +4 -0
  14. package/dist/displayUntrusted.d.ts +4 -2
  15. package/dist/displayUntrusted.js +45 -22
  16. package/dist/engineGenerationPort.d.ts +11 -2
  17. package/dist/engineGenerationPort.js +63 -9
  18. package/dist/engineHealthFacts.d.ts +5 -0
  19. package/dist/engineHealthFacts.js +11 -0
  20. package/dist/eventLeg.d.ts +1 -1
  21. package/dist/eventLeg.js +23 -3
  22. package/dist/generated/engineFactTables.d.ts +1 -0
  23. package/dist/generated/engineFactTables.js +1 -0
  24. package/dist/generated/sdkFactTables.d.ts +2 -0
  25. package/dist/generated/sdkFactTables.js +9 -0
  26. package/dist/headlessReconnectWire.js +31 -4
  27. package/dist/hitl/askGateWire.js +26 -2
  28. package/dist/hitl/frameRouter.d.ts +4 -0
  29. package/dist/hitl/frameRouter.js +14 -0
  30. package/dist/hitl/gateIdentity.d.ts +1 -0
  31. package/dist/hitl/gateIdentity.js +3 -0
  32. package/dist/hitl/planReviewCard.d.ts +21 -0
  33. package/dist/hitl/planReviewCard.js +229 -0
  34. package/dist/hitl/planReviewWire.d.ts +38 -13
  35. package/dist/hitl/planReviewWire.js +355 -133
  36. package/dist/hostSettingsSource.d.ts +1 -1
  37. package/dist/hostSettingsSource.js +8 -4
  38. package/dist/hostTurnSettings.d.ts +1 -1
  39. package/dist/hostTurnSettings.js +29 -10
  40. package/dist/i18n/messages.en.d.ts +50 -0
  41. package/dist/i18n/messages.en.js +50 -0
  42. package/dist/i18n/messages.zh.js +51 -0
  43. package/dist/index.d.ts +15 -3
  44. package/dist/index.js +9 -1
  45. package/dist/mcpTransportKindsCapability.d.ts +18 -0
  46. package/dist/mcpTransportKindsCapability.js +75 -0
  47. package/dist/mcpWireCaps.d.ts +4 -1
  48. package/dist/mcpWireCaps.js +24 -13
  49. package/dist/notifications.d.ts +9 -0
  50. package/dist/notifications.js +11 -2
  51. package/dist/ownKey.d.ts +4 -0
  52. package/dist/ownKey.js +8 -0
  53. package/dist/permissionModeWriteCapability.d.ts +13 -0
  54. package/dist/permissionModeWriteCapability.js +35 -0
  55. package/dist/permissionsAllowGrantCapability.d.ts +3 -0
  56. package/dist/permissionsAllowGrantCapability.js +26 -3
  57. package/dist/permissionsDeclaration.d.ts +23 -1
  58. package/dist/permissionsDeclaration.js +60 -30
  59. package/dist/planReviewCardFacts.d.ts +116 -0
  60. package/dist/planReviewCardFacts.js +469 -0
  61. package/dist/reattachWindow.d.ts +8 -1
  62. package/dist/reattachWindow.js +44 -12
  63. package/dist/runFollow.d.ts +30 -0
  64. package/dist/runFollow.js +117 -0
  65. package/dist/runLedgerSnapshot.d.ts +20 -0
  66. package/dist/runLedgerSnapshot.js +272 -0
  67. package/dist/runPermissionModeSwitch.d.ts +57 -0
  68. package/dist/runPermissionModeSwitch.js +135 -0
  69. package/dist/runReattachPolicy.d.ts +13 -5
  70. package/dist/runReattachPolicy.js +58 -23
  71. package/dist/seam.d.ts +3 -0
  72. package/dist/seam.js +1 -1
  73. package/dist/seatContract.js +1 -0
  74. package/dist/sessionMemoryErase.d.ts +1 -1
  75. package/dist/sessionMemoryErase.js +5 -0
  76. package/dist/sessionMemoryStatus.d.ts +27 -1
  77. package/dist/sessionMemoryStatus.js +117 -0
  78. package/dist/sseIdleTriage.d.ts +3 -1
  79. package/dist/sseIdleTriage.js +19 -4
  80. package/dist/subagent/engineSubagentTail.js +2 -0
  81. package/dist/subagentContentStore.d.ts +3 -0
  82. package/dist/subagentContentStore.js +10 -1
  83. package/dist/turnFailurePresentation.d.ts +5 -2
  84. package/dist/turnFailurePresentation.js +12 -4
  85. package/docs/INTEGRATION-CLIENTS.md +493 -10
  86. package/package.json +2 -2
@@ -0,0 +1,116 @@
1
+ export type PlanBodyUnknownCause = 'not_observed' | 'gate_unidentified' | 'gate_moved' | 'unreadable' | 'ambiguous_call' | 'malformed_frame' | 'conflicting_claims' | 'not_presented' | 'not_carried';
2
+ export type PlanReviewBody = {
3
+ readonly kind: 'shown';
4
+ readonly markdown: string;
5
+ } | {
6
+ readonly kind: 'marked';
7
+ readonly literal: string;
8
+ } | {
9
+ readonly kind: 'too_large';
10
+ readonly length: number;
11
+ } | {
12
+ readonly kind: 'unknown';
13
+ readonly cause: PlanBodyUnknownCause;
14
+ };
15
+ export interface PlanReviewCardFacts {
16
+ readonly taskId: string;
17
+ readonly checkpointId?: string;
18
+ readonly body: PlanReviewBody;
19
+ }
20
+ export declare function planReviewBodyOf(text: string): Exclude<PlanReviewBody, {
21
+ kind: 'unknown';
22
+ }>;
23
+ export declare function mintPlanReviewCardFacts(taskId: string, checkpointId: string | undefined, body: PlanReviewBody): PlanReviewCardFacts;
24
+ export declare function unknownBody(cause: PlanBodyUnknownCause): PlanReviewBody;
25
+ export declare function planReviewCardFactsFrom(v: {} | null | undefined): PlanReviewCardFacts | undefined;
26
+ export declare function samePlanReviewCardFacts(a: PlanReviewCardFacts, b: PlanReviewCardFacts): boolean;
27
+ export declare function isPlanReviewPark(result: unknown): result is {
28
+ taskId: string;
29
+ sessionId?: string;
30
+ };
31
+ export declare function pausedCheckpointIdOf(carrier: {} | null | undefined): string | undefined;
32
+ export type PlanClaim = {
33
+ readonly kind: 'text';
34
+ readonly text: string;
35
+ } | {
36
+ readonly kind: 'cause';
37
+ readonly cause: PlanBodyUnknownCause;
38
+ };
39
+ interface PresentedCall {
40
+ readonly plan?: string;
41
+ }
42
+ interface ClaimWindow {
43
+ presented: PresentedCall[];
44
+ malformed: boolean;
45
+ ambiguous: boolean;
46
+ unreadable: boolean;
47
+ }
48
+ interface PlanReviewGateEntry {
49
+ readonly checkpointId: string;
50
+ readonly facts: PlanReviewCardFacts;
51
+ readonly claim: PlanClaim;
52
+ readonly highWater?: string;
53
+ readonly generation: number;
54
+ }
55
+ interface PlanReviewRunRecord {
56
+ readonly open: Set<string>;
57
+ readonly settled: Set<string>;
58
+ window: ClaimWindow;
59
+ sawPlanFrame: boolean;
60
+ claimAtMarker?: PlanClaim | undefined;
61
+ claimGate?: string | undefined;
62
+ dirty: boolean;
63
+ gate?: PlanReviewGateEntry;
64
+ generation: number;
65
+ cardIssued: boolean;
66
+ }
67
+ export declare function _resetPlanReviewRunsForTest(): void;
68
+ export interface PlanReviewFactsTicket {
69
+ readonly sessionKey: string;
70
+ readonly taskId: string;
71
+ readonly generation: number;
72
+ }
73
+ export declare function beginPlanReviewFactsRead(sessionKey: string, taskId: string): PlanReviewFactsTicket;
74
+ export declare function commitPlanReviewFacts(ticket: PlanReviewFactsTicket, facts: PlanReviewCardFacts, claim: PlanClaim, highWater?: string): PlanReviewCardFacts | undefined;
75
+ export declare function samePlanClaim(a: PlanClaim, b: PlanClaim): boolean;
76
+ export declare function registeredPlanReviewCardFacts(sessionKey: string, taskId: string, checkpointId: string): PlanReviewCardFacts | undefined;
77
+ export interface PlanReviewCurrentGate {
78
+ readonly checkpointId: string;
79
+ readonly facts: PlanReviewCardFacts;
80
+ readonly generation: number;
81
+ }
82
+ export declare function currentPlanReviewGateOf(sessionKey: string, taskId: string): PlanReviewCurrentGate | undefined;
83
+ export declare function planReviewRunGeneration(sessionKey: string, taskId: string): number;
84
+ export declare function notePlanReviewCardIssued(sessionKey: string, taskId: string): boolean;
85
+ export declare function planReviewGateHighWaterOf(sessionKey: string, taskId: string, checkpointId: string): string | undefined;
86
+ export interface PlanBodyClaimLeg {
87
+ taskId?: string;
88
+ readonly buffer: Array<{
89
+ readonly frame: object;
90
+ readonly subFlow: boolean;
91
+ }>;
92
+ overflow: boolean;
93
+ unreadable: boolean;
94
+ }
95
+ export declare function openPlanBodyClaimLeg(): PlanBodyClaimLeg;
96
+ export declare function stepPlanBodyClaim(leg: PlanBodyClaimLeg, frame: object, subFlow: boolean): void;
97
+ export declare function planReviewParkFacts(leg: PlanBodyClaimLeg, result: {} | null | undefined): PlanReviewCardFacts | undefined;
98
+ export interface PlanReviewFactsTaken {
99
+ readonly sessionKey: string;
100
+ readonly taskId: string;
101
+ readonly facts: PlanReviewCardFacts;
102
+ readonly generation: number;
103
+ }
104
+ export declare function planReviewFactsCurrent(taken: PlanReviewFactsTaken): boolean;
105
+ export interface PlanGateRowRead {
106
+ readonly ok: boolean;
107
+ readonly atPlanGate: boolean;
108
+ readonly checkpointId?: string;
109
+ }
110
+ export declare function planGateRowReadOf(row: {} | null | undefined): PlanGateRowRead;
111
+ export type PlanReviewLedgerFold = PlanReviewRunRecord;
112
+ export declare function openPlanReviewLedgerFold(): PlanReviewLedgerFold;
113
+ export declare function stepPlanReviewLedgerFold(fold: PlanReviewLedgerFold, frame: object, subFlow: boolean): PlanReviewLedgerFold;
114
+ export declare function planReviewLedgerClaimOf(fold: PlanReviewLedgerFold): PlanClaim | undefined;
115
+ export declare function isPlanReviewClaimFrame(frame: object): boolean;
116
+ export {};
@@ -0,0 +1,469 @@
1
+ import { displayUntrusted, displayUntrustedMarks, DISPLAY_DECISION_BODY } from './displayUntrusted.js';
2
+ import { readRunTerminal, runTerminalGateKind } from './runTerminal.js';
3
+ import { SDK_PLAN_REVIEW_GATE_KINDS } from './generated/sdkFactTables.js';
4
+ import { CORE_PRESENT_PLAN_TOOL_NAME } from './generated/engineFactTables.js';
5
+ import { DEFAULT_SESSION_KEY } from './sessionSlot.js';
6
+ const PLAN_BODY_MAX_LENGTH = 200_000;
7
+ const PLAN_BODY_UNKNOWN_CAUSES = Object.freeze([
8
+ 'not_observed', 'gate_unidentified', 'gate_moved', 'unreadable', 'ambiguous_call', 'malformed_frame', 'conflicting_claims', 'not_presented', 'not_carried',
9
+ ]);
10
+ const TEMPORARY_CAUSES = new Set(['unreadable', 'gate_moved', 'not_observed', 'gate_unidentified']);
11
+ const BODY_JUDGE_READING = Object.freeze({ ...DISPLAY_DECISION_BODY, credentialUrls: false, credentialWords: false });
12
+ export function planReviewBodyOf(text) {
13
+ try {
14
+ if (typeof text !== 'string')
15
+ return Object.freeze({ kind: 'marked', literal: '' });
16
+ if (text.length > PLAN_BODY_MAX_LENGTH)
17
+ return Object.freeze({ kind: 'too_large', length: text.length });
18
+ const laidOut = text.split('\r\n').join('\n');
19
+ if (displayUntrustedMarks(laidOut, BODY_JUDGE_READING).marks.length > 0) {
20
+ return Object.freeze({ kind: 'marked', literal: displayUntrusted(laidOut, { ...DISPLAY_DECISION_BODY, escapeBackslashes: true }) });
21
+ }
22
+ return Object.freeze({ kind: 'shown', markdown: laidOut });
23
+ }
24
+ catch {
25
+ return Object.freeze({ kind: 'marked', literal: '' });
26
+ }
27
+ }
28
+ export function mintPlanReviewCardFacts(taskId, checkpointId, body) {
29
+ const b = checkpointId === undefined ? unknownBody('gate_unidentified') : body;
30
+ return Object.freeze({ taskId, ...(checkpointId !== undefined ? { checkpointId } : {}), body: Object.isFrozen(b) ? b : Object.freeze({ ...b }) });
31
+ }
32
+ export function unknownBody(cause) {
33
+ return Object.freeze({ kind: 'unknown', cause });
34
+ }
35
+ function ownData(v, key) {
36
+ if (typeof v !== 'object' || v === null)
37
+ return { present: false };
38
+ const d = Object.getOwnPropertyDescriptor(v, key);
39
+ if (d === undefined)
40
+ return { present: false };
41
+ if (!Object.hasOwn(d, 'value'))
42
+ return { present: true };
43
+ return { present: true, value: d.value };
44
+ }
45
+ const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
46
+ export function planReviewCardFactsFrom(v) {
47
+ try {
48
+ if (typeof v !== 'object' || v === null || Array.isArray(v))
49
+ return undefined;
50
+ const taskId = ownData(v, 'taskId').value;
51
+ if (!nonEmpty(taskId))
52
+ return undefined;
53
+ const ck = ownData(v, 'checkpointId');
54
+ if (ck.present && !nonEmpty(ck.value))
55
+ return undefined;
56
+ const body = readBody(ownData(v, 'body').value);
57
+ if (body === undefined)
58
+ return undefined;
59
+ const checkpointId = ck.present ? ck.value : undefined;
60
+ if (checkpointId === undefined && !(body.kind === 'unknown' && body.cause === 'gate_unidentified'))
61
+ return undefined;
62
+ return mintPlanReviewCardFacts(taskId, checkpointId, body);
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ }
68
+ function readBody(v) {
69
+ if (typeof v !== 'object' || v === null || Array.isArray(v))
70
+ return undefined;
71
+ const kind = ownData(v, 'kind').value;
72
+ if (kind === 'shown') {
73
+ const markdown = ownData(v, 'markdown').value;
74
+ return typeof markdown === 'string' ? Object.freeze({ kind, markdown }) : undefined;
75
+ }
76
+ if (kind === 'marked') {
77
+ const literal = ownData(v, 'literal').value;
78
+ return typeof literal === 'string' ? Object.freeze({ kind, literal }) : undefined;
79
+ }
80
+ if (kind === 'too_large') {
81
+ const length = ownData(v, 'length').value;
82
+ return typeof length === 'number' && Number.isInteger(length) && length > PLAN_BODY_MAX_LENGTH ? Object.freeze({ kind, length }) : undefined;
83
+ }
84
+ if (kind === 'unknown') {
85
+ const cause = ownData(v, 'cause').value;
86
+ return typeof cause === 'string' && PLAN_BODY_UNKNOWN_CAUSES.includes(cause) ? unknownBody(cause) : undefined;
87
+ }
88
+ return undefined;
89
+ }
90
+ export function samePlanReviewCardFacts(a, b) {
91
+ if (a === b)
92
+ return true;
93
+ if (a.taskId !== b.taskId || a.checkpointId !== b.checkpointId || a.body.kind !== b.body.kind)
94
+ return false;
95
+ const x = a.body;
96
+ const y = b.body;
97
+ return x.markdown === y.markdown && x.literal === y.literal && x.length === y.length && x.cause === y.cause;
98
+ }
99
+ function isPlanGateKind(kind) {
100
+ return typeof kind === 'string' && SDK_PLAN_REVIEW_GATE_KINDS.includes(kind);
101
+ }
102
+ export function isPlanReviewPark(result) {
103
+ const read = readRunTerminal(result);
104
+ if (read === null || read.kind !== 'paused')
105
+ return false;
106
+ if (!isPlanGateKind(runTerminalGateKind(read)))
107
+ return false;
108
+ const taskId = result?.taskId;
109
+ return typeof taskId === 'string' && taskId.length > 0;
110
+ }
111
+ export function pausedCheckpointIdOf(carrier) {
112
+ try {
113
+ const read = readRunTerminal(carrier);
114
+ if (read === null || read.kind !== 'paused')
115
+ return undefined;
116
+ const id = read.checkpointId;
117
+ return typeof id === 'string' && id.length > 0 ? id : undefined;
118
+ }
119
+ catch {
120
+ return undefined;
121
+ }
122
+ }
123
+ const SETTLED_CALLS_MAX = 10_000;
124
+ const PLAN_REVIEW_RUNS_MAX = 64;
125
+ const planReviewRuns = new Map();
126
+ const runKey = (sessionKey, taskId) => `${sessionKey}\u0000${taskId}`;
127
+ function emptyWindow() {
128
+ return { presented: [], malformed: false, ambiguous: false, unreadable: false };
129
+ }
130
+ function recordFor(sessionKey, taskId) {
131
+ const key = runKey(sessionKey, taskId);
132
+ let rec = planReviewRuns.get(key);
133
+ if (rec !== undefined) {
134
+ planReviewRuns.delete(key);
135
+ }
136
+ else {
137
+ rec = { open: new Set(), settled: new Set(), window: emptyWindow(), sawPlanFrame: false, dirty: false, generation: 0, cardIssued: false };
138
+ }
139
+ planReviewRuns.set(key, rec);
140
+ while (planReviewRuns.size > PLAN_REVIEW_RUNS_MAX) {
141
+ const oldest = planReviewRuns.keys().next();
142
+ if (oldest.done === true)
143
+ break;
144
+ planReviewRuns.delete(oldest.value);
145
+ }
146
+ return rec;
147
+ }
148
+ export function _resetPlanReviewRunsForTest() {
149
+ planReviewRuns.clear();
150
+ }
151
+ export function beginPlanReviewFactsRead(sessionKey, taskId) {
152
+ const rec = recordFor(sessionKey, taskId);
153
+ rec.generation += 1;
154
+ return { sessionKey, taskId, generation: rec.generation };
155
+ }
156
+ export function commitPlanReviewFacts(ticket, facts, claim, highWater) {
157
+ const rec = planReviewRuns.get(runKey(ticket.sessionKey, ticket.taskId));
158
+ if (rec === undefined || rec.generation !== ticket.generation)
159
+ return undefined;
160
+ const checkpointId = facts.checkpointId;
161
+ if (checkpointId === undefined)
162
+ return facts;
163
+ if (facts.body.kind === 'unknown' && TEMPORARY_CAUSES.has(facts.body.cause))
164
+ return facts;
165
+ const prev = rec.gate;
166
+ let out = facts;
167
+ if (prev !== undefined && prev.checkpointId === checkpointId && (isConflict(prev.facts) || !samePlanClaim(prev.claim, claim))) {
168
+ out = mintPlanReviewCardFacts(facts.taskId, checkpointId, unknownBody('conflicting_claims'));
169
+ }
170
+ rec.gate = { checkpointId, facts: out, claim, generation: ticket.generation, ...(highWater !== undefined ? { highWater } : {}) };
171
+ return out;
172
+ }
173
+ function isConflict(facts) {
174
+ return facts.body.kind === 'unknown' && facts.body.cause === 'conflicting_claims';
175
+ }
176
+ export function samePlanClaim(a, b) {
177
+ if (a.kind === 'text' && b.kind === 'text')
178
+ return a.text === b.text;
179
+ if (a.kind === 'cause' && b.kind === 'cause')
180
+ return a.cause === b.cause;
181
+ return false;
182
+ }
183
+ export function registeredPlanReviewCardFacts(sessionKey, taskId, checkpointId) {
184
+ const gate = currentPlanReviewGateOf(sessionKey, taskId);
185
+ return gate !== undefined && gate.checkpointId === checkpointId ? gate.facts : undefined;
186
+ }
187
+ export function currentPlanReviewGateOf(sessionKey, taskId) {
188
+ const rec = planReviewRuns.get(runKey(sessionKey, taskId));
189
+ const gate = rec?.gate;
190
+ return rec !== undefined && gate !== undefined && gate.generation === rec.generation
191
+ ? { checkpointId: gate.checkpointId, facts: gate.facts, generation: gate.generation }
192
+ : undefined;
193
+ }
194
+ export function planReviewRunGeneration(sessionKey, taskId) {
195
+ return recordFor(sessionKey, taskId).generation;
196
+ }
197
+ export function notePlanReviewCardIssued(sessionKey, taskId) {
198
+ const rec = recordFor(sessionKey, taskId);
199
+ const before = rec.cardIssued;
200
+ rec.cardIssued = true;
201
+ return before;
202
+ }
203
+ export function planReviewGateHighWaterOf(sessionKey, taskId, checkpointId) {
204
+ const gate = planReviewRuns.get(runKey(sessionKey, taskId))?.gate;
205
+ return gate !== undefined && gate.checkpointId === checkpointId ? gate.highWater : undefined;
206
+ }
207
+ function claimOf(rec) {
208
+ const w = rec.window;
209
+ if (w.unreadable)
210
+ return { kind: 'cause', cause: 'unreadable' };
211
+ if (w.malformed)
212
+ return { kind: 'cause', cause: 'malformed_frame' };
213
+ if (rec.open.size > 0 || w.ambiguous || w.presented.length > 1)
214
+ return { kind: 'cause', cause: 'ambiguous_call' };
215
+ const only = w.presented[0];
216
+ if (only === undefined)
217
+ return { kind: 'cause', cause: rec.sawPlanFrame ? 'not_presented' : 'not_observed' };
218
+ return only.plan === undefined ? { kind: 'cause', cause: 'not_carried' } : { kind: 'text', text: only.plan };
219
+ }
220
+ function planMarker(rec, gate) {
221
+ if (!rec.dirty && rec.claimAtMarker !== undefined && (gate === undefined || rec.claimGate === undefined || rec.claimGate === gate)) {
222
+ if (gate !== undefined)
223
+ rec.claimGate = gate;
224
+ return rec.claimAtMarker;
225
+ }
226
+ const claim = claimOf(rec);
227
+ rec.claimAtMarker = claim;
228
+ rec.claimGate = gate;
229
+ rec.dirty = false;
230
+ rec.window = emptyWindow();
231
+ return claim;
232
+ }
233
+ function otherMarker(rec) {
234
+ rec.claimAtMarker = undefined;
235
+ rec.claimGate = undefined;
236
+ rec.dirty = false;
237
+ rec.window = emptyWindow();
238
+ }
239
+ function settle(rec, id) {
240
+ rec.settled.add(id);
241
+ while (rec.settled.size > SETTLED_CALLS_MAX) {
242
+ const oldest = rec.settled.values().next();
243
+ if (oldest.done === true)
244
+ break;
245
+ rec.settled.delete(oldest.value);
246
+ }
247
+ }
248
+ function classOf(frame) {
249
+ const type = ownData(frame, 'type').value;
250
+ if (type === 'tool_start' || type === 'tool_end')
251
+ return ownData(frame, 'toolName').value === CORE_PRESENT_PLAN_TOOL_NAME ? 'plan_call' : 'other';
252
+ if (type === 'needs_review' || type === 'suspended')
253
+ return 'marker';
254
+ if (type === 'done')
255
+ return 'done';
256
+ if (type === 'meta')
257
+ return 'meta';
258
+ return 'other';
259
+ }
260
+ function foldPlanCall(rec, frame) {
261
+ rec.sawPlanFrame = true;
262
+ const id = ownData(frame, 'toolCallId').value;
263
+ if (!nonEmpty(id)) {
264
+ rec.window.malformed = true;
265
+ rec.dirty = true;
266
+ return;
267
+ }
268
+ if (rec.settled.has(id))
269
+ return;
270
+ rec.dirty = true;
271
+ if (ownData(frame, 'type').value === 'tool_start') {
272
+ if (ownData(frame, 'recovered').value === true)
273
+ rec.window.ambiguous = true;
274
+ rec.open.add(id);
275
+ return;
276
+ }
277
+ const started = rec.open.delete(id);
278
+ settle(rec, id);
279
+ if (!started) {
280
+ rec.window.ambiguous = true;
281
+ return;
282
+ }
283
+ if (ownData(frame, 'isError').value !== false || ownData(frame, 'notExecuted').value === true)
284
+ return;
285
+ const s = ownData(frame, 'structured');
286
+ if (!s.present || s.value === undefined) {
287
+ rec.window.presented.push({});
288
+ return;
289
+ }
290
+ const sv = s.value;
291
+ if (typeof sv !== 'object' || sv === null || Array.isArray(sv) || ownData(sv, 'type').value !== 'exit-plan-mode') {
292
+ rec.window.malformed = true;
293
+ return;
294
+ }
295
+ const plan = ownData(sv, 'plan').value;
296
+ if (typeof plan !== 'string') {
297
+ rec.window.malformed = true;
298
+ return;
299
+ }
300
+ rec.window.presented.push({ plan });
301
+ }
302
+ function markerGateOf(frame) {
303
+ const v = ownData(frame, 'checkpointId').value;
304
+ return nonEmpty(v) ? v : undefined;
305
+ }
306
+ function foldMarker(rec, frame) {
307
+ const type = ownData(frame, 'type').value;
308
+ const gate = ownData(frame, 'gate');
309
+ if (type === 'needs_review') {
310
+ if (!gate.present || (gate.value !== null && (typeof gate.value !== 'object' || Array.isArray(gate.value)))) {
311
+ rec.window.malformed = true;
312
+ rec.dirty = true;
313
+ planMarker(rec);
314
+ return;
315
+ }
316
+ if (gate.value === null) {
317
+ planMarker(rec, markerGateOf(frame));
318
+ return;
319
+ }
320
+ const kind = ownData(gate.value, 'kind').value;
321
+ if (typeof kind !== 'string') {
322
+ rec.window.malformed = true;
323
+ rec.dirty = true;
324
+ planMarker(rec);
325
+ return;
326
+ }
327
+ if (isPlanGateKind(kind))
328
+ planMarker(rec, markerGateOf(frame));
329
+ else
330
+ otherMarker(rec);
331
+ return;
332
+ }
333
+ const kind = gate.present && typeof gate.value === 'object' && gate.value !== null ? ownData(gate.value, 'kind').value : undefined;
334
+ if (isPlanGateKind(kind))
335
+ planMarker(rec, markerGateOf(frame));
336
+ else
337
+ otherMarker(rec);
338
+ }
339
+ const LEG_BUFFER_MAX = 256;
340
+ export function openPlanBodyClaimLeg() {
341
+ return { buffer: [], overflow: false, unreadable: false };
342
+ }
343
+ function bindLeg(leg, taskId) {
344
+ const rec = recordFor(DEFAULT_SESSION_KEY, taskId);
345
+ if (leg.taskId === taskId)
346
+ return rec;
347
+ const pending = leg.buffer.splice(0);
348
+ const lost = leg.overflow || leg.unreadable;
349
+ leg.taskId = taskId;
350
+ leg.overflow = false;
351
+ leg.unreadable = false;
352
+ if (lost) {
353
+ rec.window.unreadable = true;
354
+ rec.dirty = true;
355
+ }
356
+ for (const p of pending)
357
+ foldInto(rec, p.frame, p.subFlow);
358
+ return rec;
359
+ }
360
+ function foldInto(rec, frame, subFlow) {
361
+ try {
362
+ const c = classOf(frame);
363
+ if (c === 'plan_call') {
364
+ if (!subFlow)
365
+ foldPlanCall(rec, frame);
366
+ }
367
+ else if (c === 'marker') {
368
+ if (!subFlow)
369
+ foldMarker(rec, frame);
370
+ }
371
+ }
372
+ catch {
373
+ rec.window.unreadable = true;
374
+ rec.dirty = true;
375
+ }
376
+ }
377
+ export function stepPlanBodyClaim(leg, frame, subFlow) {
378
+ try {
379
+ const c = classOf(frame);
380
+ if (c === 'meta') {
381
+ const taskId = ownData(frame, 'taskId').value;
382
+ if (nonEmpty(taskId))
383
+ bindLeg(leg, taskId);
384
+ return;
385
+ }
386
+ if (c !== 'plan_call' && c !== 'marker')
387
+ return;
388
+ if (leg.taskId === undefined) {
389
+ if (leg.buffer.length >= LEG_BUFFER_MAX)
390
+ leg.overflow = true;
391
+ else
392
+ leg.buffer.push({ frame, subFlow });
393
+ return;
394
+ }
395
+ foldInto(recordFor(DEFAULT_SESSION_KEY, leg.taskId), frame, subFlow);
396
+ }
397
+ catch {
398
+ leg.unreadable = true;
399
+ if (leg.taskId !== undefined) {
400
+ const rec = recordFor(DEFAULT_SESSION_KEY, leg.taskId);
401
+ rec.window.unreadable = true;
402
+ rec.dirty = true;
403
+ }
404
+ }
405
+ }
406
+ export function planReviewParkFacts(leg, result) {
407
+ let taskId;
408
+ let checkpointId;
409
+ try {
410
+ if (!isPlanReviewPark(result)) {
411
+ const read = readRunTerminal(result);
412
+ const tid = ownData(result, 'taskId').value;
413
+ if (read !== null && read.kind === 'paused' && nonEmpty(tid))
414
+ otherMarker(legRecord(leg, tid));
415
+ return undefined;
416
+ }
417
+ taskId = result.taskId;
418
+ checkpointId = pausedCheckpointIdOf(result);
419
+ const claim = planMarker(legRecord(leg, taskId), checkpointId);
420
+ const body = claim.kind === 'text' ? planReviewBodyOf(claim.text) : unknownBody(claim.cause);
421
+ const ticket = beginPlanReviewFactsRead(DEFAULT_SESSION_KEY, taskId);
422
+ return commitPlanReviewFacts(ticket, mintPlanReviewCardFacts(taskId, checkpointId, body), claim);
423
+ }
424
+ catch {
425
+ return taskId === undefined ? undefined : mintPlanReviewCardFacts(taskId, checkpointId, unknownBody('unreadable'));
426
+ }
427
+ }
428
+ function legRecord(leg, taskId) {
429
+ return leg.taskId === undefined || leg.taskId === taskId ? bindLeg(leg, taskId) : recordFor(DEFAULT_SESSION_KEY, taskId);
430
+ }
431
+ export function planReviewFactsCurrent(taken) {
432
+ const rec = planReviewRuns.get(runKey(taken.sessionKey, taken.taskId));
433
+ return rec !== undefined && rec.generation === taken.generation;
434
+ }
435
+ export function planGateRowReadOf(row) {
436
+ try {
437
+ const result = ownData(row, 'result').value;
438
+ const read = readRunTerminal(result);
439
+ const atPlanGate = read !== null && read.kind === 'paused' && isPlanGateKind(runTerminalGateKind(read));
440
+ const checkpointId = pausedCheckpointIdOf(result);
441
+ return { ok: true, atPlanGate, ...(checkpointId !== undefined ? { checkpointId } : {}) };
442
+ }
443
+ catch {
444
+ return { ok: false, atPlanGate: false };
445
+ }
446
+ }
447
+ export function openPlanReviewLedgerFold() {
448
+ return { open: new Set(), settled: new Set(), window: emptyWindow(), sawPlanFrame: true, dirty: false, generation: 0, cardIssued: false };
449
+ }
450
+ export function stepPlanReviewLedgerFold(fold, frame, subFlow) {
451
+ if (typeof frame === 'object' && frame !== null)
452
+ foldInto(fold, frame, subFlow);
453
+ return fold;
454
+ }
455
+ export function planReviewLedgerClaimOf(fold) {
456
+ return fold.dirty ? undefined : fold.claimAtMarker;
457
+ }
458
+ export function isPlanReviewClaimFrame(frame) {
459
+ if (typeof frame !== 'object' || frame === null)
460
+ return false;
461
+ let c;
462
+ try {
463
+ c = classOf(frame);
464
+ }
465
+ catch {
466
+ c = 'unreadable';
467
+ }
468
+ return c === 'plan_call' || c === 'marker' || c === 'unreadable';
469
+ }
@@ -1,3 +1,4 @@
1
+ import { type ReattachBreak, type RunNotFollowed } from './runFollow.js';
1
2
  export declare const REATTACH_WINDOW_MS = 300000;
2
3
  export declare const REATTACH_BACKOFF_START_MS = 1000;
3
4
  export declare const REATTACH_BACKOFF_CAP_MS = 30000;
@@ -25,8 +26,10 @@ export interface ReattachWindowState {
25
26
  readonly consecutiveNotFound: number;
26
27
  readonly notFoundConfirmed: boolean;
27
28
  readonly tuning: Readonly<Tuned>;
29
+ readonly runId?: string;
30
+ readonly lastBreak?: ReattachBreak;
28
31
  }
29
- export declare function reattachWindowOpen(nowMs: number, tuning?: ReattachWindowTuning): ReattachWindowState;
32
+ export declare function reattachWindowOpen(nowMs: number, tuning?: ReattachWindowTuning, runId?: string): ReattachWindowState;
30
33
  export type ReattachProbeResult = 'readable' | 'unreachable' | 'not-found';
31
34
  export type ReattachWindowEvent = {
32
35
  readonly type: 'attempt';
@@ -40,6 +43,8 @@ export type ReattachWindowEvent = {
40
43
  } | {
41
44
  readonly type: 'backoff';
42
45
  readonly serverRetryAfterMs?: number;
46
+ readonly break?: ReattachBreak;
47
+ readonly runId?: string;
43
48
  } | {
44
49
  readonly type: 'new-segment';
45
50
  };
@@ -51,9 +56,11 @@ export type ReattachWindowDecision = {
51
56
  readonly afterMs: number;
52
57
  } | {
53
58
  readonly action: 'window-exhausted';
59
+ readonly notFollowed: RunNotFollowed<'reattach_exhausted' | 'bad_input'>;
54
60
  } | {
55
61
  readonly action: 'run-unknown';
56
62
  readonly confirmations: number;
63
+ readonly notFollowed: RunNotFollowed<'run_unknown'>;
57
64
  };
58
65
  export interface ReattachWindowStep {
59
66
  readonly state: ReattachWindowState;