@sema-agent/client-core 0.96.0 → 0.97.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.
- package/CHANGELOG.md +89 -0
- package/README.md +28 -22
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +7 -7
- package/dist/adapter/downstream/terminalToSdkResult.js +6 -2
- package/dist/agentSession/backgroundView.js +2 -15
- package/dist/agentsWireCaps.d.ts +1 -1
- package/dist/agentsWireCaps.js +16 -10
- package/dist/approvalDecidedByCapability.d.ts +2 -0
- package/dist/approvalDecidedByCapability.js +0 -1
- package/dist/approvalsStreamLiveCapability.d.ts +2 -0
- package/dist/approvalsStreamLiveCapability.js +3 -2
- package/dist/attachmentSeatCapability.d.ts +2 -0
- package/dist/attachmentSeatCapability.js +0 -1
- package/dist/callerCwdCapability.d.ts +2 -0
- package/dist/callerCwdCapability.js +0 -1
- package/dist/centerWiringCapability.d.ts +2 -0
- package/dist/centerWiringCapability.js +4 -3
- package/dist/cloudConfigWireCaps.d.ts +2 -2
- package/dist/cloudConfigWireCaps.js +192 -56
- package/dist/declared/supportFloorDeclared.js +3 -3
- package/dist/deviceExecutorManagementCapability.d.ts +2 -0
- package/dist/deviceExecutorManagementCapability.js +3 -2
- package/dist/displayUntrusted.d.ts +3 -0
- package/dist/displayUntrusted.js +15 -0
- package/dist/engineCapReader.d.ts +8 -2
- package/dist/engineCapReader.js +15 -7
- package/dist/engineCapsCache.d.ts +11 -3
- package/dist/engineCapsCache.js +54 -23
- package/dist/engineErrorCodes.d.ts +3 -0
- package/dist/engineErrorCodes.js +9 -1
- package/dist/engineNoticeCodes.js +2 -3
- package/dist/executionLaneCapability.d.ts +2 -0
- package/dist/executionLaneCapability.js +3 -2
- package/dist/fileHistoryCaptureCapability.d.ts +2 -0
- package/dist/fileHistoryCaptureCapability.js +34 -8
- package/dist/fileHistoryLegNotice.js +4 -0
- package/dist/fleet/fleetLedger.js +129 -105
- package/dist/gateOutcome.js +2 -4
- package/dist/gateVocabulary.d.ts +1 -6
- package/dist/gateVocabulary.js +2 -5
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +7 -0
- package/dist/generated/toolNameTables.d.ts +0 -1
- package/dist/generated/toolNameTables.js +0 -42
- package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
- package/dist/hitl/approvalEndingCause.js +2 -7
- package/dist/hitl/approvalHolds.d.ts +16 -1
- package/dist/hitl/approvalHolds.js +52 -12
- package/dist/hitl/askGateWire.js +1 -0
- package/dist/hitl/automaticAnswerVerdict.js +5 -7
- package/dist/hitl/decisionConflict.js +4 -3
- package/dist/hitl/decisionRefusal.js +19 -12
- package/dist/hitl/frameRouter.d.ts +3 -0
- package/dist/hitl/frameRouter.js +52 -25
- package/dist/hitl/gateLedger.d.ts +0 -5
- package/dist/hitl/gateLedger.js +0 -21
- package/dist/hitl/hitlBridge.js +18 -4
- package/dist/hitl/parkResolver.js +7 -3
- package/dist/hitl/replayedApproval.d.ts +2 -3
- package/dist/hitl/replayedApproval.js +7 -16
- package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
- package/dist/hitl/sessionPolicyDeliverable.js +15 -17
- package/dist/hitl/sessionPolicyWire.d.ts +2 -0
- package/dist/hitl/sessionPolicyWire.js +15 -3
- package/dist/hitl/standingRows.d.ts +1 -0
- package/dist/hitl/standingRows.js +38 -17
- package/dist/hitl/suspendedReopen.js +2 -1
- package/dist/hitl/toolApprovalWire.d.ts +8 -8
- package/dist/hitl/toolApprovalWire.js +50 -24
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/liveModelCatalog.d.ts +13 -0
- package/dist/liveModelCatalog.js +56 -0
- package/dist/mcpProbeCapability.d.ts +2 -0
- package/dist/mcpProbeCapability.js +3 -2
- package/dist/mcpWireCaps.d.ts +1 -0
- package/dist/mcpWireCaps.js +4 -1
- package/dist/memoryComplianceCapability.d.ts +2 -0
- package/dist/memoryComplianceCapability.js +3 -2
- package/dist/memoryOriginCapability.d.ts +2 -0
- package/dist/memoryOriginCapability.js +3 -2
- package/dist/modelIdentityResolvability.js +2 -2
- package/dist/noticePresentation.js +2 -2
- package/dist/outputStyleSeatCapability.d.ts +2 -0
- package/dist/outputStyleSeatCapability.js +0 -1
- package/dist/peerLaneCapability.d.ts +2 -0
- package/dist/peerLaneCapability.js +3 -2
- package/dist/permissionModesCapability.d.ts +2 -0
- package/dist/permissionModesCapability.js +0 -1
- package/dist/permissionRulesWriteCapability.d.ts +2 -0
- package/dist/permissionRulesWriteCapability.js +3 -2
- package/dist/permissionsAllowGrantCapability.d.ts +2 -0
- package/dist/permissionsAllowGrantCapability.js +4 -2
- package/dist/permissionsDeclaration.js +19 -21
- package/dist/request/taskRequest.d.ts +1 -4
- package/dist/request/taskRequest.js +74 -19
- package/dist/resumeRefusalCopy.js +4 -4
- package/dist/rewindArchiveCapability.js +5 -0
- package/dist/rewindArchiveReading.d.ts +2 -0
- package/dist/rewindArchiveReading.js +0 -1
- package/dist/runTerminal.d.ts +33 -4
- package/dist/runTerminal.js +170 -15
- package/dist/sdkWireTransit.d.ts +2 -1
- package/dist/sdkWireTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +2 -0
- package/dist/sealedKeyCapability.js +0 -1
- package/dist/seatContract.d.ts +7 -4
- package/dist/seatContract.js +34 -20
- package/dist/sessionPolicyCapability.d.ts +2 -0
- package/dist/sessionPolicyCapability.js +3 -2
- package/dist/sessionReadRedactionCapability.d.ts +2 -0
- package/dist/sessionReadRedactionCapability.js +0 -1
- package/dist/sessionSyncFileHistoryCapability.d.ts +2 -0
- package/dist/sessionSyncFileHistoryCapability.js +3 -2
- package/dist/skillToolListsCapability.d.ts +2 -0
- package/dist/skillToolListsCapability.js +3 -2
- package/dist/sqlEngineCapability.d.ts +2 -0
- package/dist/sqlEngineCapability.js +4 -3
- package/dist/steerPriorityCapability.d.ts +2 -0
- package/dist/steerPriorityCapability.js +3 -2
- package/dist/storePostureCapability.d.ts +2 -0
- package/dist/storePostureCapability.js +4 -3
- package/dist/toolHistoryBadTurn.js +3 -2
- package/dist/toolResult.d.ts +11 -0
- package/dist/toolResult.js +53 -0
- package/dist/userInvokedSkillsCapability.d.ts +2 -0
- package/dist/userInvokedSkillsCapability.js +3 -2
- package/dist/webSearchBackendCapability.d.ts +2 -0
- package/dist/webSearchBackendCapability.js +3 -2
- package/dist/wireErrorTriage.js +58 -34
- package/dist/wireFailureShape.d.ts +1 -1
- package/dist/wireFailureShape.js +76 -25
- package/dist/workflowsJournalCapability.d.ts +2 -0
- package/dist/workflowsJournalCapability.js +3 -2
- package/dist/writeProtectionCapability.d.ts +2 -0
- package/dist/writeProtectionCapability.js +3 -2
- package/docs/INTEGRATION-CLIENTS.md +533 -14
- package/package.json +4 -4
- package/dist/engineRefusedToolName.d.ts +0 -1
- package/dist/engineRefusedToolName.js +0 -8
- package/dist/engineWordRenames.d.ts +0 -8
- package/dist/engineWordRenames.js +0 -13
|
@@ -99,40 +99,48 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
99
99
|
const wfMap = new Map();
|
|
100
100
|
const rowMeta = new Map();
|
|
101
101
|
const retained = new Map();
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
function
|
|
102
|
+
const tails = new Map();
|
|
103
|
+
const TAIL_RECORD_MAX = 512;
|
|
104
|
+
function touchTail(tail) {
|
|
105
|
+
const prior = tails.get(tail);
|
|
106
|
+
tails.delete(tail);
|
|
107
|
+
if (prior === undefined && tails.size >= TAIL_RECORD_MAX) {
|
|
108
|
+
const held = new Set();
|
|
109
|
+
for (const id of taskMap.keys())
|
|
110
|
+
held.add(rowIdTail(id));
|
|
111
|
+
for (const id of retained.keys())
|
|
112
|
+
held.add(rowIdTail(id));
|
|
113
|
+
for (const candidate of tails.keys()) {
|
|
114
|
+
if (held.has(candidate))
|
|
115
|
+
continue;
|
|
116
|
+
tails.delete(candidate);
|
|
117
|
+
break;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const rec = prior ?? { gen: undefined, settled: undefined };
|
|
121
|
+
tails.set(tail, rec);
|
|
122
|
+
return rec;
|
|
123
|
+
}
|
|
124
|
+
function raiseTailGen(tail, gen) {
|
|
105
125
|
if (gen === undefined || tail.length === 0)
|
|
106
126
|
return;
|
|
107
|
-
const prior =
|
|
127
|
+
const prior = tails.get(tail)?.gen;
|
|
108
128
|
if (prior !== undefined && cycleSeqOrder(prior, gen) !== 'before')
|
|
109
129
|
return;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
cycleWatermark.delete(oldest);
|
|
115
|
-
}
|
|
116
|
-
cycleWatermark.set(tail, gen);
|
|
130
|
+
touchTail(tail).gen = gen;
|
|
131
|
+
}
|
|
132
|
+
function isFormerGeneration(tail, gen) {
|
|
133
|
+
return cycleSeqOrder(gen, tails.get(tail)?.gen) === 'before';
|
|
117
134
|
}
|
|
118
|
-
const settledTerminal = new Map();
|
|
119
|
-
const SETTLED_TERMINAL_MAX = 512;
|
|
120
135
|
function noteSettledTerminal(tail, row) {
|
|
121
136
|
if (tail.length === 0 || typeof row.status !== 'string')
|
|
122
137
|
return;
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
settledTerminal.delete(tail);
|
|
130
|
-
if (settledTerminal.size >= SETTLED_TERMINAL_MAX) {
|
|
131
|
-
const oldest = settledTerminal.keys().next().value;
|
|
132
|
-
if (oldest !== undefined)
|
|
133
|
-
settledTerminal.delete(oldest);
|
|
134
|
-
}
|
|
135
|
-
settledTerminal.set(tail, { status: row.status, cycleSeq: gen });
|
|
138
|
+
touchTail(tail).settled = { status: row.status, cycleSeq: wireCycleSeq(row) };
|
|
139
|
+
}
|
|
140
|
+
function withdrawSettledTerminal(tail) {
|
|
141
|
+
const rec = tails.get(tail);
|
|
142
|
+
if (rec !== undefined)
|
|
143
|
+
rec.settled = undefined;
|
|
136
144
|
}
|
|
137
145
|
let droppedMalformed = 0;
|
|
138
146
|
let droppedUnknownFrame = 0;
|
|
@@ -167,11 +175,16 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
167
175
|
...(retired ? { retiredByNotification: true } : {}),
|
|
168
176
|
};
|
|
169
177
|
};
|
|
170
|
-
function settleTerminalRow(row, receivedAtMs) {
|
|
178
|
+
function settleTerminalRow(row, tail, receivedAtMs) {
|
|
171
179
|
taskMap.delete(row.id);
|
|
172
180
|
rowMeta.delete(row.id);
|
|
181
|
+
for (const id of taskMap.keys()) {
|
|
182
|
+
if (rowIdTail(id) === tail) {
|
|
183
|
+
debug(`[fleet-frame] terminal row not retained: tail still in flight on an alias(row=${row.id} alias=${id})`);
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
173
187
|
retained.set(row.id, { row, expireAt: receivedAtMs + TERMINAL_RETAIN_MS });
|
|
174
|
-
const tail = rowIdTail(row.id);
|
|
175
188
|
for (const id of [...retained.keys()]) {
|
|
176
189
|
if (id !== row.id && rowIdTail(id) === tail)
|
|
177
190
|
retained.delete(id);
|
|
@@ -179,18 +192,32 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
179
192
|
noteSettledTerminal(tail, row);
|
|
180
193
|
}
|
|
181
194
|
function admitRow(row, receivedAtMs) {
|
|
195
|
+
const tail = rowIdTail(row.id);
|
|
196
|
+
const gen = wireCycleSeq(row);
|
|
197
|
+
if (isFormerGeneration(tail, gen)) {
|
|
198
|
+
debug(`[fleet-frame] former-generation row ignored(row=${row.id} row-cycle=${gen} tail-cycle=${tails.get(tail)?.gen})`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
raiseTailGen(tail, gen);
|
|
202
|
+
if (gen !== undefined) {
|
|
203
|
+
for (const [id, alias] of [...taskMap]) {
|
|
204
|
+
if (id !== row.id && rowIdTail(id) === tail && cycleSeqOrder(wireCycleSeq(alias), gen) === 'before') {
|
|
205
|
+
taskMap.delete(id);
|
|
206
|
+
rowMeta.delete(id);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
182
210
|
if (isSdkFleetTaskTerminal(row.status)) {
|
|
183
|
-
settleTerminalRow(row, receivedAtMs);
|
|
211
|
+
settleTerminalRow(row, tail, receivedAtMs);
|
|
184
212
|
return;
|
|
185
213
|
}
|
|
186
214
|
taskMap.set(row.id, row);
|
|
187
215
|
rowMeta.set(row.id, { receivedAtMs });
|
|
188
|
-
const tail = rowIdTail(row.id);
|
|
189
216
|
for (const id of [...retained.keys()]) {
|
|
190
217
|
if (rowIdTail(id) === tail)
|
|
191
218
|
retained.delete(id);
|
|
192
219
|
}
|
|
193
|
-
|
|
220
|
+
withdrawSettledTerminal(tail);
|
|
194
221
|
clearBgTerminalFacts(tail);
|
|
195
222
|
}
|
|
196
223
|
function forgetSettledTerminalRowOf(id) {
|
|
@@ -243,9 +270,6 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
243
270
|
break;
|
|
244
271
|
}
|
|
245
272
|
case 'snapshot': {
|
|
246
|
-
taskMap.clear();
|
|
247
|
-
wfMap.clear();
|
|
248
|
-
rowMeta.clear();
|
|
249
273
|
const receivedAtMs = nowFn();
|
|
250
274
|
const rows = [];
|
|
251
275
|
for (const row of frame.tasks) {
|
|
@@ -256,12 +280,26 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
256
280
|
}
|
|
257
281
|
rows.push(row);
|
|
258
282
|
}
|
|
283
|
+
const keepTails = new Set();
|
|
284
|
+
const currentTails = new Set();
|
|
285
|
+
for (const row of rows) {
|
|
286
|
+
const tail = rowIdTail(row.id);
|
|
287
|
+
if (isFormerGeneration(tail, wireCycleSeq(row)))
|
|
288
|
+
keepTails.add(tail);
|
|
289
|
+
else
|
|
290
|
+
currentTails.add(tail);
|
|
291
|
+
}
|
|
292
|
+
for (const tail of currentTails)
|
|
293
|
+
keepTails.delete(tail);
|
|
294
|
+
for (const id of [...taskMap.keys()]) {
|
|
295
|
+
if (keepTails.has(rowIdTail(id)))
|
|
296
|
+
continue;
|
|
297
|
+
taskMap.delete(id);
|
|
298
|
+
rowMeta.delete(id);
|
|
299
|
+
}
|
|
300
|
+
wfMap.clear();
|
|
259
301
|
for (const row of rows)
|
|
260
|
-
|
|
261
|
-
admitRow(row, receivedAtMs);
|
|
262
|
-
for (const row of rows)
|
|
263
|
-
if (!isSdkFleetTaskTerminal(row.status))
|
|
264
|
-
admitRow(row, receivedAtMs);
|
|
302
|
+
admitRow(row, receivedAtMs);
|
|
265
303
|
for (const row of frame.workflows)
|
|
266
304
|
wfMap.set(row.id, row);
|
|
267
305
|
break;
|
|
@@ -275,7 +313,6 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
275
313
|
}
|
|
276
314
|
const receivedAtMs = nowFn();
|
|
277
315
|
admitRow(row, receivedAtMs);
|
|
278
|
-
raiseCycleWatermark(rowIdTail(row.id), wireCycleSeq(row));
|
|
279
316
|
debug(`[fleet-row] id=${row.id} parent=${row.parentId ?? '-'} agentType=${row.agentType ?? '-'}` +
|
|
280
317
|
` agentName=${row.agentName ?? '-'} name=${row.name ?? '-'} status=${row.status ?? '-'}` +
|
|
281
318
|
` tokens=${row.tokens ?? '-'} parentToolCallId=${row.parentToolCallId ?? '-'}`);
|
|
@@ -420,79 +457,65 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
420
457
|
const writtenIds = new Set();
|
|
421
458
|
let applied = false;
|
|
422
459
|
let washBlocked = false;
|
|
423
|
-
let staleBlocked = false;
|
|
424
460
|
const notifSeq = cycleSeqValue(n.seq);
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
staleBlocked = true;
|
|
429
|
-
debug(`[fleet-frame] bg_notification stale-cycle ignored(watermark=${mark} notif-seq=${notifSeq})`);
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
for (const id of rowIds) {
|
|
433
|
-
const known = taskMap.get(id);
|
|
434
|
-
if (!known)
|
|
435
|
-
continue;
|
|
436
|
-
const heldGen = wireCycleSeq(known);
|
|
437
|
-
if (cycleSeqOrder(notifSeq, heldGen) === 'before') {
|
|
438
|
-
staleBlocked = true;
|
|
439
|
-
debug(`[fleet-frame] bg_notification stale-cycle ignored(row=${id} row-cycle=${heldGen} notif-seq=${notifSeq})`);
|
|
440
|
-
continue;
|
|
441
|
-
}
|
|
442
|
-
const started = known.startedAt;
|
|
443
|
-
const meta = rowMeta.get(id);
|
|
444
|
-
const frozenElapsed = typeof started === 'number' && started > 0 && started <= nowMs
|
|
445
|
-
? nowMs - started
|
|
446
|
-
: meta !== undefined && isElapsedBase(known.elapsedMs)
|
|
447
|
-
? known.elapsedMs + Math.max(0, nowMs - meta.receivedAtMs)
|
|
448
|
-
: known.elapsedMs;
|
|
449
|
-
taskMap.delete(id);
|
|
450
|
-
rowMeta.delete(id);
|
|
451
|
-
retained.set(id, {
|
|
452
|
-
row: {
|
|
453
|
-
...known,
|
|
454
|
-
status: coerced,
|
|
455
|
-
...(typeof frozenElapsed === 'number' ? { elapsedMs: frozenElapsed } : {}),
|
|
456
|
-
},
|
|
457
|
-
expireAt: nowMs + TERMINAL_RETAIN_MS,
|
|
458
|
-
retiredByNotification: true,
|
|
459
|
-
});
|
|
460
|
-
writtenIds.add(id);
|
|
461
|
-
applied = true;
|
|
461
|
+
const staleBlocked = isFormerGeneration(notifTail, notifSeq);
|
|
462
|
+
if (staleBlocked) {
|
|
463
|
+
debug(`[fleet-frame] bg_notification stale-cycle ignored(tail-cycle=${tails.get(notifTail)?.gen} notif-seq=${notifSeq})`);
|
|
462
464
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
465
|
+
if (!staleBlocked) {
|
|
466
|
+
for (const id of rowIds) {
|
|
467
|
+
const known = taskMap.get(id);
|
|
468
|
+
if (!known)
|
|
469
|
+
continue;
|
|
470
|
+
const started = known.startedAt;
|
|
471
|
+
const meta = rowMeta.get(id);
|
|
472
|
+
const frozenElapsed = typeof started === 'number' && started > 0 && started <= nowMs
|
|
473
|
+
? nowMs - started
|
|
474
|
+
: meta !== undefined && isElapsedBase(known.elapsedMs)
|
|
475
|
+
? known.elapsedMs + Math.max(0, nowMs - meta.receivedAtMs)
|
|
476
|
+
: known.elapsedMs;
|
|
477
|
+
taskMap.delete(id);
|
|
478
|
+
rowMeta.delete(id);
|
|
479
|
+
retained.set(id, {
|
|
480
|
+
row: {
|
|
481
|
+
...known,
|
|
482
|
+
status: coerced,
|
|
483
|
+
...(typeof frozenElapsed === 'number' ? { elapsedMs: frozenElapsed } : {}),
|
|
484
|
+
},
|
|
485
|
+
expireAt: nowMs + TERMINAL_RETAIN_MS,
|
|
486
|
+
retiredByNotification: true,
|
|
487
|
+
});
|
|
488
|
+
writtenIds.add(id);
|
|
476
489
|
applied = true;
|
|
477
|
-
continue;
|
|
478
490
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
491
|
+
for (const [id, entry] of retained) {
|
|
492
|
+
if (writtenIds.has(id))
|
|
493
|
+
continue;
|
|
494
|
+
if (rowIdTail(id) !== notifTail)
|
|
495
|
+
continue;
|
|
496
|
+
const prior = entry.row.status ?? '';
|
|
497
|
+
if (prior === n.status) {
|
|
498
|
+
applied = true;
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
if (isWashGreen(prior, n.status)) {
|
|
502
|
+
washBlocked = true;
|
|
503
|
+
debug(`[fleet-frame] bg_notification WASH-GREEN blocked(retained=${id} prior=${prior} notif=${n.status})`);
|
|
504
|
+
continue;
|
|
505
|
+
}
|
|
506
|
+
retained.set(id, {
|
|
507
|
+
row: { ...entry.row, status: coerced },
|
|
508
|
+
expireAt: nowMs + TERMINAL_RETAIN_MS,
|
|
509
|
+
...(entry.retiredByNotification === true ? { retiredByNotification: true } : {}),
|
|
510
|
+
});
|
|
511
|
+
applied = true;
|
|
483
512
|
}
|
|
484
|
-
retained.set(id, {
|
|
485
|
-
row: { ...entry.row, status: coerced },
|
|
486
|
-
expireAt: nowMs + TERMINAL_RETAIN_MS,
|
|
487
|
-
...(entry.retiredByNotification === true ? { retiredByNotification: true } : {}),
|
|
488
|
-
});
|
|
489
|
-
applied = true;
|
|
490
513
|
}
|
|
491
514
|
const factsAccepted = !staleBlocked &&
|
|
492
515
|
(applied ||
|
|
493
516
|
(!washBlocked &&
|
|
494
517
|
(() => {
|
|
495
|
-
for (const prior of [getBgTerminalFacts(n.taskId),
|
|
518
|
+
for (const prior of [getBgTerminalFacts(n.taskId), tails.get(notifTail)?.settled]) {
|
|
496
519
|
if (prior === undefined)
|
|
497
520
|
continue;
|
|
498
521
|
const order = cycleSeqOrder(notifSeq, prior.cycleSeq);
|
|
@@ -506,7 +529,7 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
506
529
|
return true;
|
|
507
530
|
})()));
|
|
508
531
|
if (factsAccepted)
|
|
509
|
-
|
|
532
|
+
raiseTailGen(notifTail, notifSeq);
|
|
510
533
|
if (factsAccepted) {
|
|
511
534
|
recordBgTerminalFacts(n.taskId, {
|
|
512
535
|
status: n.status,
|
|
@@ -633,7 +656,8 @@ export function createFleetLedger(hooks = {}, opts = {}) {
|
|
|
633
656
|
wfMap.clear();
|
|
634
657
|
rowMeta.clear();
|
|
635
658
|
retained.clear();
|
|
636
|
-
|
|
659
|
+
for (const rec of tails.values())
|
|
660
|
+
rec.settled = undefined;
|
|
637
661
|
contentAnchorSet = false;
|
|
638
662
|
contentAnchor = undefined;
|
|
639
663
|
debug(`[fleet-frame] 会话锚变更(${from ?? '-'} → ${to ?? '-'})⇒ 清上一会话的行/留存` +
|
package/dist/gateOutcome.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ccToolDenialKindForSettledBy, isCcToolDenialKind, isGateDeniedByWord } from './gateVocabulary.js';
|
|
2
2
|
import { GATE_PARKED_ERROR_CODE } from './engineErrorCodes.js';
|
|
3
3
|
import { CORE_MODE_RELEASE_REASONS, CORE_SETTLEMENT_KINDS } from './generated/engineFactTables.js';
|
|
4
|
-
import { currentEngineWord } from './engineWordRenames.js';
|
|
5
4
|
import { readAskOrigin, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
|
|
6
5
|
function str(v) {
|
|
7
6
|
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
@@ -19,9 +18,8 @@ export function modeReleaseReasonSentence(reason) {
|
|
|
19
18
|
try {
|
|
20
19
|
if (typeof reason !== 'string' || reason === '')
|
|
21
20
|
return undefined;
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
? MODE_RELEASE_SENTENCE_BY_REASON[word]
|
|
21
|
+
return Object.hasOwn(MODE_RELEASE_SENTENCE_BY_REASON, reason)
|
|
22
|
+
? MODE_RELEASE_SENTENCE_BY_REASON[reason]
|
|
25
23
|
: MODE_RELEASE_UNRECOGNISED_SENTENCE;
|
|
26
24
|
}
|
|
27
25
|
catch {
|
package/dist/gateVocabulary.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CORE_DENIED_BY_VALUES, CORE_PERSISTED_RULE_MANDATES } from './generated/engineFactTables.js';
|
|
2
|
-
import { PRIOR_ENGINE_WORD_RENAMES, type PriorEngineWord } from './engineWordRenames.js';
|
|
3
2
|
export declare const CC_TOOL_DENIAL_KINDS: readonly ["user-rejected", "permission-rule", "automode-blocked", "automode-unavailable", "automode-parsing-error", "interrupted", "cancelled"];
|
|
4
3
|
export type CcToolDenialKind = (typeof CC_TOOL_DENIAL_KINDS)[number];
|
|
5
4
|
export declare function isCcToolDenialKind(v: unknown): v is CcToolDenialKind;
|
|
@@ -11,11 +10,7 @@ export declare function isGateDeniedByWord(v: unknown): v is GateDeniedByWord;
|
|
|
11
10
|
export declare function gateDeniedByDetail(deniedBy: unknown): string;
|
|
12
11
|
export declare function askOriginDetail(origin: unknown): string;
|
|
13
12
|
export declare function mandatedApprovalDetail(): string;
|
|
14
|
-
|
|
15
|
-
[K in PriorEngineWord]: (typeof PRIOR_ENGINE_WORD_RENAMES)[K] extends (typeof CORE_PERSISTED_RULE_MANDATES)[number] ? K : never;
|
|
16
|
-
}[PriorEngineWord];
|
|
17
|
-
export declare const APPROVAL_MANDATE_WORDS: readonly ((typeof CORE_PERSISTED_RULE_MANDATES)[number] | RetiredMandateWord)[];
|
|
13
|
+
export declare const APPROVAL_MANDATE_WORDS: readonly (typeof CORE_PERSISTED_RULE_MANDATES)[number][];
|
|
18
14
|
export type ApprovalMandateWord = (typeof APPROVAL_MANDATE_WORDS)[number];
|
|
19
15
|
export declare function isApprovalMandateWord(v: unknown): v is ApprovalMandateWord;
|
|
20
16
|
export declare function approvalMandateDetail(word: ApprovalMandateWord): string;
|
|
21
|
-
export {};
|
package/dist/gateVocabulary.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { CORE_DENIED_BY_VALUES, CORE_PERSISTED_RULE_MANDATES } from './generated/engineFactTables.js';
|
|
2
|
-
import { PRIOR_ENGINE_WORD_RENAMES } from './engineWordRenames.js';
|
|
3
2
|
export const CC_TOOL_DENIAL_KINDS = Object.freeze([
|
|
4
3
|
'user-rejected',
|
|
5
4
|
'permission-rule',
|
|
@@ -72,8 +71,7 @@ export function askOriginDetail(origin) {
|
|
|
72
71
|
export function mandatedApprovalDetail() {
|
|
73
72
|
return 'no saved allow rule and no remembered answer can retire this question; each call is settled on its own — by you here or by an automatic check the deployment runs — and an answer covers only that call';
|
|
74
73
|
}
|
|
75
|
-
const
|
|
76
|
-
export const APPROVAL_MANDATE_WORDS = Object.freeze([...CORE_PERSISTED_RULE_MANDATES, ...RETIRED_MANDATE_WORDS]);
|
|
74
|
+
export const APPROVAL_MANDATE_WORDS = Object.freeze([...CORE_PERSISTED_RULE_MANDATES]);
|
|
77
75
|
const _mandateWordsPin = true;
|
|
78
76
|
void _mandateWordsPin;
|
|
79
77
|
export function isApprovalMandateWord(v) {
|
|
@@ -86,9 +84,8 @@ const APPROVAL_MANDATE_SENTENCES = Object.freeze({
|
|
|
86
84
|
probe_unanswered: 'the check run on this call did not answer (it timed out or failed; this client cannot tell which), so whether the call stays inside the directories allowed for this session is unknown',
|
|
87
85
|
write_protection: "this change lands on a protected location (the agent's own configuration), which is confirmed one change at a time",
|
|
88
86
|
target_unresolved: 'where this change lands on disk could not be determined (a link on the way could not be examined, or the target could not be resolved), so whether it lands on a guarded location is unknown',
|
|
89
|
-
write_protection_unresolved: 'the protected-location check could not tell where this change lands, so whether it touches a protected location is unknown',
|
|
90
87
|
});
|
|
91
|
-
const APPROVAL_MANDATE_SET = new Set(
|
|
88
|
+
const APPROVAL_MANDATE_SET = new Set(APPROVAL_MANDATE_WORDS);
|
|
92
89
|
export function approvalMandateDetail(word) {
|
|
93
90
|
if (typeof word === 'string' && Object.hasOwn(APPROVAL_MANDATE_SENTENCES, word)) {
|
|
94
91
|
return APPROVAL_MANDATE_SENTENCES[word];
|
|
@@ -3,3 +3,5 @@ export declare const SDK_STATUS_DERIVED_COARSE_CODES: readonly ["request.rejecte
|
|
|
3
3
|
export declare const SDK_DENY_REASON_ROUTING_FAILURE: "routing_failure_fail_closed";
|
|
4
4
|
export declare const SDK_ASK_ROW_ENDING_CAUSES: readonly ["routing_failure_fail_closed", "run_cancelled", "run_exited", "batch_aborted", "batch_sibling_withdrawn", "batch_bound_elsewhere", "adhoc_leg_no_durable_domain", "orphan_ttl_exceeded", "crashed_before_park", "shutdown_before_park"];
|
|
5
5
|
export declare const SDK_RUN_DEATH_VERDICT_CODES: readonly ["run.stalled", "run.orphaned", "approval.expired"];
|
|
6
|
+
export declare const SDK_APPROVAL_DECIDE_GATE_KINDS: readonly ["human", "irreversible_ask"];
|
|
7
|
+
export declare const SDK_PLAN_REVIEW_GATE_KINDS: readonly ["plan_review"];
|
|
@@ -32,3 +32,10 @@ export const SDK_RUN_DEATH_VERDICT_CODES = Object.freeze([
|
|
|
32
32
|
"run.orphaned",
|
|
33
33
|
"approval.expired",
|
|
34
34
|
]);
|
|
35
|
+
export const SDK_APPROVAL_DECIDE_GATE_KINDS = Object.freeze([
|
|
36
|
+
"human",
|
|
37
|
+
"irreversible_ask",
|
|
38
|
+
]);
|
|
39
|
+
export const SDK_PLAN_REVIEW_GATE_KINDS = Object.freeze([
|
|
40
|
+
"plan_review",
|
|
41
|
+
]);
|
|
@@ -1,44 +1,2 @@
|
|
|
1
1
|
export const CORE_PROTOCOL_PREFIXES = ["mcp__", "a2a__"];
|
|
2
|
-
export const CORE_RETIRED_TOOL_CURRENT_NAMES = new Map([
|
|
3
|
-
["read_file", "Read"],
|
|
4
|
-
["edit_file", "Edit"],
|
|
5
|
-
["write_file", "Write"],
|
|
6
|
-
["bash", "Bash"],
|
|
7
|
-
["bash_readonly", null],
|
|
8
|
-
["glob", "Glob"],
|
|
9
|
-
["grep", "Grep"],
|
|
10
|
-
["web_fetch", "WebFetch"],
|
|
11
|
-
["tool_search", "ToolSearch"],
|
|
12
|
-
["skill", "Skill"],
|
|
13
|
-
["present_plan", "ExitPlanMode"],
|
|
14
|
-
["enter_plan_mode", "EnterPlanMode"],
|
|
15
|
-
["spawn_subagent", "Agent"],
|
|
16
|
-
["CronCancel", "CronDelete"],
|
|
17
|
-
["lsp", "LSP"],
|
|
18
|
-
["submit_output", "StructuredOutput"],
|
|
19
|
-
["repo_map", "RepoMap"],
|
|
20
|
-
["read_tool_result", "ReadToolResult"],
|
|
21
|
-
["report_blocked", "ReportBlocked"],
|
|
22
|
-
["declare_done", "DeclareDone"],
|
|
23
|
-
["run_workflow", "Workflow"],
|
|
24
|
-
["RunWorkflow", "Workflow"],
|
|
25
|
-
["Task", "Agent"],
|
|
26
|
-
["BashOutput", "TaskOutput"],
|
|
27
|
-
["AgentOutputTool", "TaskOutput"],
|
|
28
|
-
["BashOutputTool", "TaskOutput"],
|
|
29
|
-
["AgentOutput", "TaskOutput"],
|
|
30
|
-
["WorkflowStatus", null],
|
|
31
|
-
["KillShell", "TaskStop"],
|
|
32
|
-
["KillBash", "TaskStop"],
|
|
33
|
-
["ListMcpResources", "ListMcpResourcesTool"],
|
|
34
|
-
["ReadMcpResource", "ReadMcpResourceTool"],
|
|
35
|
-
["ReadMcpResourceDir", "ReadMcpResourceDirTool"],
|
|
36
|
-
["MultiEdit", null],
|
|
37
|
-
["Fork", null],
|
|
38
|
-
["Sleep", null],
|
|
39
|
-
["Remember", null],
|
|
40
|
-
["remember", null],
|
|
41
|
-
["Recall", null],
|
|
42
|
-
["recall", null],
|
|
43
|
-
]);
|
|
44
2
|
export const CORE_SKILL_TOOL_NAME = "Skill";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { displayUntrusted } from '../displayUntrusted.js';
|
|
1
|
+
import { displayUntrusted, markerSafeCut } from '../displayUntrusted.js';
|
|
2
2
|
const NOTE_DISPLAY_MAX = 200;
|
|
3
3
|
export const DECISION_NOTE_NOTICE_KEY = 'approval-decision-note';
|
|
4
4
|
function cleanNote(raw) {
|
|
@@ -7,7 +7,7 @@ function cleanNote(raw) {
|
|
|
7
7
|
.trim();
|
|
8
8
|
if (flat === '')
|
|
9
9
|
return undefined;
|
|
10
|
-
return flat.length <= NOTE_DISPLAY_MAX ? flat : `${flat.slice(0, NOTE_DISPLAY_MAX - 1)}…`;
|
|
10
|
+
return flat.length <= NOTE_DISPLAY_MAX ? flat : `${flat.slice(0, markerSafeCut(flat, NOTE_DISPLAY_MAX - 1))}…`;
|
|
11
11
|
}
|
|
12
12
|
export function readDecisionNoteAudit(ack) {
|
|
13
13
|
if (ack === null || typeof ack !== 'object')
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ASK_GONE_DENIED_WORD } from '../engineErrorCodes.js';
|
|
2
2
|
import { SDK_ASK_ROW_ENDING_CAUSES } from '../generated/sdkFactTables.js';
|
|
3
|
+
import { guardedRead, readOwnDataValue } from '../ownKey.js';
|
|
3
4
|
import { readThrownExtra } from '../wireFailureShape.js';
|
|
4
5
|
export const ASK_ROW_ENDING_CAUSE_WORDS = SDK_ASK_ROW_ENDING_CAUSES;
|
|
5
6
|
const _askRowCausePin = true;
|
|
@@ -27,13 +28,7 @@ export function askRowEndingCauseFor(state, word) {
|
|
|
27
28
|
return undefined;
|
|
28
29
|
}
|
|
29
30
|
function ownDataSlot(o, key) {
|
|
30
|
-
|
|
31
|
-
const slot = Object.getOwnPropertyDescriptor(o, key);
|
|
32
|
-
return slot !== undefined && Object.hasOwn(slot, 'value') ? slot.value : undefined;
|
|
33
|
-
}
|
|
34
|
-
catch {
|
|
35
|
-
return undefined;
|
|
36
|
-
}
|
|
31
|
+
return guardedRead(() => readOwnDataValue(o, key));
|
|
37
32
|
}
|
|
38
33
|
export function approvalCompleteCauseOf(frame) {
|
|
39
34
|
try {
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { ApprovalHolderIdentity, FsApprovalOutcome, ToolApprovalFrameOutcome } from './toolApprovalWire.js';
|
|
2
|
+
export declare const APPROVAL_SETTLED_HOWS: readonly ["answered", "interrupted", "closed_by_engine"];
|
|
3
|
+
export type ApprovalSettledHow = (typeof APPROVAL_SETTLED_HOWS)[number];
|
|
4
|
+
export declare const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
|
|
5
|
+
export interface SettledApprovalEntry {
|
|
6
|
+
readonly how: ApprovalSettledHow;
|
|
7
|
+
readonly parked: boolean;
|
|
8
|
+
readonly outcome: ToolApprovalFrameOutcome;
|
|
9
|
+
}
|
|
2
10
|
export interface DurableDecisionHold {
|
|
3
11
|
readonly lane: 'durable';
|
|
4
12
|
readonly outcome: Promise<FsApprovalOutcome>;
|
|
@@ -17,7 +25,7 @@ export interface LiveCardHold {
|
|
|
17
25
|
};
|
|
18
26
|
readonly cardSignal: AbortSignal;
|
|
19
27
|
readonly interrupt: () => void;
|
|
20
|
-
trailing?: Promise<
|
|
28
|
+
trailing?: Promise<boolean>;
|
|
21
29
|
}
|
|
22
30
|
export type ApprovalHold = DurableDecisionHold | LiveCardHold;
|
|
23
31
|
export interface LiveCardIdentity {
|
|
@@ -27,12 +35,14 @@ export interface LiveCardIdentity {
|
|
|
27
35
|
readonly sessionId?: string;
|
|
28
36
|
}
|
|
29
37
|
export declare function liveCardHoldFor(who: ApprovalHolderIdentity): LiveCardHold | undefined;
|
|
38
|
+
export declare function settledForDurableLane(entry: SettledApprovalEntry | undefined): boolean;
|
|
30
39
|
export declare function liveCardAnsweredHow(o: ToolApprovalFrameOutcome): 'answered' | 'interrupted' | undefined;
|
|
31
40
|
export declare function awaitLiveCardHolder(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome | undefined>;
|
|
32
41
|
export interface ApprovalDecisionHoldTable {
|
|
33
42
|
readonly inFlight: Map<string, ApprovalHold>;
|
|
34
43
|
readonly settled: Map<string, DurableSettledHold>;
|
|
35
44
|
readonly openReads: Set<number>;
|
|
45
|
+
readonly outcomes: Map<string, SettledApprovalEntry>;
|
|
36
46
|
clock: number;
|
|
37
47
|
}
|
|
38
48
|
export interface DurableSettledHold {
|
|
@@ -40,6 +50,11 @@ export interface DurableSettledHold {
|
|
|
40
50
|
readonly hold: DurableDecisionHold;
|
|
41
51
|
}
|
|
42
52
|
export declare const approvalDecisionHolds: ApprovalDecisionHoldTable;
|
|
53
|
+
export declare function settledApprovalOf(approvalId: string | undefined): SettledApprovalEntry | undefined;
|
|
54
|
+
export declare function clearSettledApprovals(): void;
|
|
55
|
+
export declare function anyApprovalSettled(): boolean;
|
|
56
|
+
export declare function noteEngineClosedApproval(approvalId: string, parked: boolean): void;
|
|
57
|
+
export declare function settledLiveCardOutcome(approvalId: string): ToolApprovalFrameOutcome | undefined;
|
|
43
58
|
export declare function liveCardHoldOf(key: string): LiveCardHold | undefined;
|
|
44
59
|
export declare function holdLiveCard(identity: LiveCardIdentity, callerSignal: AbortSignal | undefined, present: (hold: LiveCardHold) => Promise<ToolApprovalFrameOutcome>): Promise<ToolApprovalFrameOutcome>;
|
|
45
60
|
export declare function joinLiveCard(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
2
|
import { liveFrameCallKey } from './gateIdentity.js';
|
|
3
3
|
import { approvalResolutionOf } from './approvalResolution.js';
|
|
4
|
+
export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
|
|
5
|
+
export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
|
|
4
6
|
const nonEmpty = (v) => typeof v === 'string' && v !== '';
|
|
5
7
|
export function liveCardHoldFor(who) {
|
|
6
8
|
if (nonEmpty(who.approvalId))
|
|
@@ -19,13 +21,8 @@ export function liveCardHoldFor(who) {
|
|
|
19
21
|
}
|
|
20
22
|
return undefined;
|
|
21
23
|
}
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
if (answeredHowOf(r) !== undefined)
|
|
25
|
-
return true;
|
|
26
|
-
if (r.kind === 'unsettled')
|
|
27
|
-
return false;
|
|
28
|
-
return hold.superseded !== undefined && !hold.superseded.parked;
|
|
24
|
+
export function settledForDurableLane(entry) {
|
|
25
|
+
return entry !== undefined && !entry.parked;
|
|
29
26
|
}
|
|
30
27
|
export function liveCardAnsweredHow(o) {
|
|
31
28
|
return answeredHowOf(approvalResolutionOf(o));
|
|
@@ -47,9 +44,43 @@ export async function awaitLiveCardHolder(hold, signal) {
|
|
|
47
44
|
finally {
|
|
48
45
|
unsubscribe();
|
|
49
46
|
}
|
|
50
|
-
|
|
47
|
+
const stillHeld = approvalDecisionHolds.inFlight.get(liveFrameCallKey(hold.identity.approvalId)) === hold;
|
|
48
|
+
return stillHeld || settledForDurableLane(settledApprovalOf(hold.identity.approvalId)) ? { ...o, joinedInFlight: true } : undefined;
|
|
49
|
+
}
|
|
50
|
+
export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), outcomes: new Map(), clock: 0 };
|
|
51
|
+
export function settledApprovalOf(approvalId) {
|
|
52
|
+
return typeof approvalId === 'string' && approvalId !== '' ? approvalDecisionHolds.outcomes.get(approvalId) : undefined;
|
|
53
|
+
}
|
|
54
|
+
export function clearSettledApprovals() {
|
|
55
|
+
approvalDecisionHolds.outcomes.clear();
|
|
56
|
+
}
|
|
57
|
+
export function anyApprovalSettled() {
|
|
58
|
+
return approvalDecisionHolds.outcomes.size > 0;
|
|
59
|
+
}
|
|
60
|
+
function noteSettled(approvalId, how, parked, outcome) {
|
|
61
|
+
if (typeof approvalId !== 'string' || approvalId === '')
|
|
62
|
+
return;
|
|
63
|
+
if (!APPROVAL_SETTLED_HOWS.includes(how))
|
|
64
|
+
return;
|
|
65
|
+
const t = approvalDecisionHolds.outcomes;
|
|
66
|
+
if (t.has(approvalId))
|
|
67
|
+
return;
|
|
68
|
+
t.set(approvalId, Object.freeze({ how, parked, outcome: Object.freeze({ ...outcome }) }));
|
|
69
|
+
while (t.size > SETTLED_APPROVALS_MAX_ENTRIES) {
|
|
70
|
+
const oldest = t.keys().next();
|
|
71
|
+
if (oldest.done === true)
|
|
72
|
+
break;
|
|
73
|
+
t.delete(oldest.value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const ENGINE_CLOSED_OUTCOME = Object.freeze({ decision: 'unresolved', retracted: true });
|
|
77
|
+
export function noteEngineClosedApproval(approvalId, parked) {
|
|
78
|
+
noteSettled(approvalId, 'closed_by_engine', parked, ENGINE_CLOSED_OUTCOME);
|
|
79
|
+
}
|
|
80
|
+
export function settledLiveCardOutcome(approvalId) {
|
|
81
|
+
const e = settledApprovalOf(approvalId);
|
|
82
|
+
return e === undefined ? undefined : { ...e.outcome, joinedInFlight: true };
|
|
51
83
|
}
|
|
52
|
-
export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
|
|
53
84
|
export function liveCardHoldOf(key) {
|
|
54
85
|
const h = approvalDecisionHolds.inFlight.get(key);
|
|
55
86
|
return h !== undefined && h.lane === 'live' ? h : undefined;
|
|
@@ -76,7 +107,7 @@ export function holdLiveCard(identity, callerSignal, present) {
|
|
|
76
107
|
if (h.inFlight.get(key) === hold)
|
|
77
108
|
h.inFlight.delete(key);
|
|
78
109
|
};
|
|
79
|
-
const settle = (give) => {
|
|
110
|
+
const settle = (give, onLanded) => {
|
|
80
111
|
settled = true;
|
|
81
112
|
unsubscribe();
|
|
82
113
|
const trailing = hold.trailing;
|
|
@@ -86,7 +117,11 @@ export function holdLiveCard(identity, callerSignal, present) {
|
|
|
86
117
|
return;
|
|
87
118
|
}
|
|
88
119
|
give();
|
|
89
|
-
trailing.then(
|
|
120
|
+
trailing.then((landed) => {
|
|
121
|
+
if (landed === true)
|
|
122
|
+
onLanded?.();
|
|
123
|
+
release();
|
|
124
|
+
}, release);
|
|
90
125
|
};
|
|
91
126
|
let run;
|
|
92
127
|
try {
|
|
@@ -95,7 +130,12 @@ export function holdLiveCard(identity, callerSignal, present) {
|
|
|
95
130
|
catch (e) {
|
|
96
131
|
run = Promise.reject(e);
|
|
97
132
|
}
|
|
98
|
-
run.then((o) =>
|
|
133
|
+
run.then((o) => {
|
|
134
|
+
const how = liveCardAnsweredHow(o);
|
|
135
|
+
if (how === 'answered')
|
|
136
|
+
noteSettled(identity.approvalId, how, false, o);
|
|
137
|
+
settle(() => resolveOutcome(o), how === 'interrupted' ? () => noteSettled(identity.approvalId, how, false, o) : undefined);
|
|
138
|
+
}, (e) => settle(() => rejectOutcome(e)));
|
|
99
139
|
return outcome;
|
|
100
140
|
}
|
|
101
141
|
export async function joinLiveCard(hold, signal) {
|