@sema-agent/client-core 0.91.0 → 0.92.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 +172 -0
- package/README.md +31 -21
- package/dist/adapt/arms.js +4 -12
- package/dist/adapt/panelTasks.d.ts +0 -2
- package/dist/adapt/panelTasks.js +6 -26
- package/dist/adapt.js +2 -2
- package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
- package/dist/adapter/activeRunSelfHeal.js +5 -27
- package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
- package/dist/adapter/runStream.js +3 -1
- package/dist/askSurvivesStandingAnswer.d.ts +4 -1
- package/dist/askSurvivesStandingAnswer.js +13 -0
- package/dist/autoModeUnavailable.js +3 -2
- package/dist/cloudConfigWireCaps.js +5 -4
- package/dist/compensations.js +5 -5
- package/dist/controlRouter.d.ts +23 -23
- package/dist/controlRouter.js +114 -49
- package/dist/coreValuePorts.d.ts +4 -2
- package/dist/coreValuePorts.js +5 -0
- package/dist/decideFailureNote.js +4 -2
- package/dist/decideReceipt.d.ts +9 -0
- package/dist/decideReceipt.js +62 -1
- package/dist/displayUntrusted.js +2 -1
- package/dist/effectiveFacts.d.ts +14 -4
- package/dist/effectiveFacts.js +45 -5
- package/dist/engineAgentAbsence.js +2 -1
- package/dist/engineCapReader.js +16 -10
- package/dist/engineCapsCache.d.ts +2 -0
- package/dist/engineCapsCache.js +13 -2
- package/dist/engineErrorCodes.d.ts +14 -0
- package/dist/engineErrorCodes.js +37 -0
- package/dist/engineNoticeCodes.d.ts +14 -0
- package/dist/engineNoticeCodes.js +71 -0
- package/dist/executionLaneCapability.js +2 -0
- package/dist/gateOutcome.js +2 -17
- package/dist/gateVocabulary.d.ts +2 -4
- package/dist/gateVocabulary.js +3 -11
- package/dist/generated/engineFactTables.d.ts +16 -1
- package/dist/generated/engineFactTables.js +81 -0
- package/dist/generated/engineNoticeTables.js +3 -0
- package/dist/generated/settingsSchemaTables.d.ts +8 -0
- package/dist/generated/settingsSchemaTables.js +40 -0
- package/dist/hitl/allowRuleShadow.d.ts +21 -0
- package/dist/hitl/allowRuleShadow.js +167 -0
- package/dist/hitl/askClassPair.d.ts +14 -0
- package/dist/hitl/askClassPair.js +42 -0
- package/dist/hitl/askGateWire.js +1 -0
- package/dist/hitl/askSurvivesPosture.d.ts +5 -0
- package/dist/hitl/askSurvivesPosture.js +17 -0
- package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
- package/dist/hitl/automaticAnswerVerdict.js +143 -0
- package/dist/hitl/crashConverged.d.ts +1 -0
- package/dist/hitl/crashConverged.js +1 -1
- package/dist/hitl/frameRouter.d.ts +2 -0
- package/dist/hitl/frameRouter.js +66 -14
- package/dist/hitl/gateLedger.d.ts +6 -0
- package/dist/hitl/gateLedger.js +34 -5
- package/dist/hitl/hitlHostSurface.d.ts +2 -0
- package/dist/hitl/hitlHostSurface.js +7 -0
- package/dist/hitl/livePendingAsk.js +24 -5
- package/dist/hitl/parkResolver.js +3 -1
- package/dist/hitl/persistedRulesWire.d.ts +4 -1
- package/dist/hitl/persistedRulesWire.js +9 -2
- package/dist/hitl/planReviewWire.js +2 -2
- package/dist/hitl/replayedApproval.d.ts +21 -0
- package/dist/hitl/replayedApproval.js +89 -0
- package/dist/hitl/sessionPolicyDeliverable.js +20 -2
- package/dist/hitl/sessionPolicyWire.d.ts +8 -0
- package/dist/hitl/sessionPolicyWire.js +12 -2
- package/dist/hitl/toolApprovalWire.d.ts +6 -1
- package/dist/hitl/toolApprovalWire.js +20 -40
- package/dist/hookMatcherVerdict.js +2 -1
- package/dist/humanTurn.js +3 -4
- package/dist/index.d.ts +15 -5
- package/dist/index.js +12 -3
- package/dist/inheritEnvWire.js +3 -4
- package/dist/mcpLiveness.js +2 -1
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +3 -0
- package/dist/model/catalog.js +2 -1
- package/dist/model/providerPresets.d.ts +3 -1
- package/dist/model/tierVocabulary.d.ts +2 -1
- package/dist/model/tierVocabulary.js +3 -8
- package/dist/peerFrames.js +2 -2
- package/dist/permissionRuleIssue.js +9 -6
- package/dist/permissionsDeclaration.d.ts +7 -1
- package/dist/permissionsDeclaration.js +29 -20
- package/dist/pluginHooksWire.js +2 -11
- package/dist/promptProfileWireCaps.d.ts +2 -1
- package/dist/protocolSegment.d.ts +9 -0
- package/dist/protocolSegment.js +28 -0
- package/dist/request/taskRequest.js +1 -15
- package/dist/ruleCompileVerdict.d.ts +2 -0
- package/dist/ruleCompileVerdict.js +13 -0
- package/dist/ruleRemovalConsequence.d.ts +2 -1
- package/dist/runCancelContext.d.ts +12 -0
- package/dist/runCancelContext.js +83 -1
- package/dist/seam.js +1 -1
- package/dist/seatContract.d.ts +2 -1
- package/dist/sessionMemoryStatus.d.ts +2 -4
- package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
- package/dist/sessionSyncFileHistoryCapability.js +50 -0
- package/dist/skillToolListsCapability.d.ts +18 -0
- package/dist/skillToolListsCapability.js +50 -0
- package/dist/sqlEngineCapability.js +1 -8
- package/dist/steerPriorityCapability.d.ts +18 -0
- package/dist/steerPriorityCapability.js +80 -0
- package/dist/steerReceipt.d.ts +9 -0
- package/dist/steerReceipt.js +25 -0
- package/dist/subagent/engineSubagentSteer.js +2 -9
- package/dist/supportFloor.js +2 -2
- package/dist/toolResult.d.ts +8 -0
- package/dist/toolResult.js +47 -3
- package/dist/types/engineState.d.ts +2 -12
- package/dist/userInvokedSkillsCapability.d.ts +18 -0
- package/dist/userInvokedSkillsCapability.js +50 -0
- package/dist/wireFailureShape.d.ts +2 -0
- package/dist/wireFailureShape.js +4 -0
- package/dist/workflowsJournalCapability.d.ts +18 -0
- package/dist/workflowsJournalCapability.js +50 -0
- package/dist/writeProtectionCapability.d.ts +2 -4
- package/docs/INTEGRATION-CLIENTS.md +624 -12
- package/package.json +2 -2
package/dist/controlRouter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cancelConflictContent, cancelConflictFromError } from './wireRefusalCopy.js';
|
|
2
|
-
import {
|
|
2
|
+
import { steerPriorityMode } from './steerPriorityCapability.js';
|
|
3
3
|
export class ControlSafetyError extends Error {
|
|
4
4
|
code;
|
|
5
5
|
cause;
|
|
@@ -16,7 +16,6 @@ export class ControlSafetyError extends Error {
|
|
|
16
16
|
this.status = status;
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
-
const BAND_RANK = { now: 0, next: 1, later: 2 };
|
|
20
19
|
export class ControlRouter {
|
|
21
20
|
client;
|
|
22
21
|
taskId = null;
|
|
@@ -24,8 +23,6 @@ export class ControlRouter {
|
|
|
24
23
|
jobId;
|
|
25
24
|
scenario;
|
|
26
25
|
systemPrompt;
|
|
27
|
-
queue = [];
|
|
28
|
-
seq = 0;
|
|
29
26
|
constructor(client, opts = {}) {
|
|
30
27
|
this.client = client;
|
|
31
28
|
this.sessionId = opts.sessionId;
|
|
@@ -63,7 +60,16 @@ export class ControlRouter {
|
|
|
63
60
|
if (this.taskId === null) {
|
|
64
61
|
throw controlSafetyRefusal('not_running', 'no run in flight to steer', 'submit a turn first');
|
|
65
62
|
}
|
|
66
|
-
|
|
63
|
+
let priority;
|
|
64
|
+
let reading;
|
|
65
|
+
try {
|
|
66
|
+
priority = opts?.priority;
|
|
67
|
+
reading = opts?.steerPriority;
|
|
68
|
+
}
|
|
69
|
+
catch (e) {
|
|
70
|
+
throw steerLocalRefusal('steer_input_invalid', 'unknown', e);
|
|
71
|
+
}
|
|
72
|
+
const body = steerBodyOf({ text, ...(mode !== undefined ? { mode } : {}), ...(priority !== undefined ? { priority: priority } : {}) }, (reading ?? UNOBSERVED_STEER_PRIORITY));
|
|
67
73
|
try {
|
|
68
74
|
return await this.client.runs.steer(this.taskId, body, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
|
|
69
75
|
}
|
|
@@ -92,38 +98,11 @@ export class ControlRouter {
|
|
|
92
98
|
'check what that decision did to the run before retrying the cancel', e);
|
|
93
99
|
}
|
|
94
100
|
if (isNotFound(e)) {
|
|
95
|
-
throw controlSafetyRefusal('not_found', 'runs.cancel 404 —
|
|
101
|
+
throw controlSafetyRefusal('not_found', 'runs.cancel 404', `${CANCEL_NOT_FOUND_COPY.happened} — ${CANCEL_NOT_FOUND_COPY.nextStep}`, e);
|
|
96
102
|
}
|
|
97
103
|
throw e;
|
|
98
104
|
}
|
|
99
105
|
}
|
|
100
|
-
enqueue(text, priority = 'next') {
|
|
101
|
-
const cmd = { id: this.nextId(), text, priority };
|
|
102
|
-
this.queue.push(cmd);
|
|
103
|
-
return cmd;
|
|
104
|
-
}
|
|
105
|
-
dequeue(id) {
|
|
106
|
-
const i = this.queue.findIndex((c) => c.id === id);
|
|
107
|
-
if (i < 0)
|
|
108
|
-
return false;
|
|
109
|
-
this.queue.splice(i, 1);
|
|
110
|
-
return true;
|
|
111
|
-
}
|
|
112
|
-
pending() {
|
|
113
|
-
return [...this.queue].sort((a, b) => BAND_RANK[a.priority] - BAND_RANK[b.priority]);
|
|
114
|
-
}
|
|
115
|
-
async drainNext(opts) {
|
|
116
|
-
const ordered = this.pending();
|
|
117
|
-
const head = ordered[0];
|
|
118
|
-
if (!head)
|
|
119
|
-
return null;
|
|
120
|
-
this.dequeue(head.id);
|
|
121
|
-
return this.submit(head.text, opts);
|
|
122
|
-
}
|
|
123
|
-
nextId() {
|
|
124
|
-
this.seq += 1;
|
|
125
|
-
return `q-${this.seq}-${uuid()}`;
|
|
126
|
-
}
|
|
127
106
|
}
|
|
128
107
|
export function errCodes(e) {
|
|
129
108
|
if (!e || typeof e !== 'object')
|
|
@@ -152,20 +131,72 @@ const STEERING_NAME_TO_SAFETY = new Map([
|
|
|
152
131
|
['SteeringAmbiguousTargetError', 'ambiguous_target'],
|
|
153
132
|
['SteeringStillRunningError', 'still_running'],
|
|
154
133
|
['SteeringLedgerUnavailableError', 'ledger_unavailable'],
|
|
134
|
+
['SteeringQueueFullError', 'queue_full'],
|
|
135
|
+
['SteeringDuplicateInputIdError', 'duplicate_input_id'],
|
|
155
136
|
['SteeringError', 'steering_other'],
|
|
156
137
|
]);
|
|
157
|
-
const
|
|
158
|
-
not_running:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
138
|
+
const STEERING_COPY = {
|
|
139
|
+
not_running: {
|
|
140
|
+
happened: 'that run is not accepting messages right now — it has just finished, is running on another server, or is not the active run of its session',
|
|
141
|
+
nextStep: 'check its current state and send the message to the run that is active',
|
|
142
|
+
},
|
|
143
|
+
invalid_content: {
|
|
144
|
+
happened: 'the message was refused because its text contains control markers the engine does not accept, so nothing was delivered',
|
|
145
|
+
nextStep: 'rewrite the message and send it again',
|
|
146
|
+
},
|
|
147
|
+
queue_full: {
|
|
148
|
+
happened: 'that run is paused and already holds as many waiting messages as it can, so this one was not accepted',
|
|
149
|
+
nextStep: 'send it again once the waiting messages have been delivered (when the run resumes or the session is woken)',
|
|
150
|
+
},
|
|
151
|
+
duplicate_input_id: {
|
|
152
|
+
happened: 'a different instruction was already accepted under this idempotency key, and that earlier instruction stands',
|
|
153
|
+
nextStep: 'if you changed the text, send the new text under a new key; otherwise do not resend it — a new key would deliver the same instruction twice',
|
|
154
|
+
},
|
|
155
|
+
ambiguous_target: {
|
|
156
|
+
happened: 'more than one running agent matches that target, so the message was not delivered',
|
|
157
|
+
nextStep: 'address a sub-agent by its tool-call id; a workflow agent cannot be singled out while another running agent shares its label, so send it again once only one does',
|
|
158
|
+
},
|
|
159
|
+
still_running: {
|
|
160
|
+
happened: 'that agent is still running, so it cannot be resumed',
|
|
161
|
+
nextStep: 'send it a message instead, or wait for it to finish',
|
|
162
|
+
},
|
|
163
|
+
blocked_by_hook: {
|
|
164
|
+
happened: "the message was not accepted: a prompt check on this deployment blocked it, so nothing was delivered",
|
|
165
|
+
nextStep: 'edit the message and send it again — that is not a duplicate submission',
|
|
166
|
+
},
|
|
167
|
+
ledger_unavailable: {
|
|
168
|
+
happened: 'the server could not record the message and refused it before anything reached the engine, so nothing was delivered',
|
|
169
|
+
nextStep: 'send the same text again later',
|
|
170
|
+
},
|
|
171
|
+
steering_other: {
|
|
172
|
+
happened: 'the message was refused for a reason this version does not recognise, so it did not land',
|
|
173
|
+
nextStep: 'report its error code if this keeps happening; do not guess what it means',
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
const adviceOfCopy = (c) => `${c.happened} — ${c.nextStep}`;
|
|
177
|
+
const STEERING_ADVICE = Object.freeze(Object.fromEntries(Object.entries(STEERING_COPY).map(([k, c]) => [k, adviceOfCopy(c)])));
|
|
178
|
+
const STEERING_OTHER_UNKNOWN_COPY = {
|
|
179
|
+
happened: 'the message was refused for a reason this version does not recognise, and whether it was delivered is not known',
|
|
180
|
+
nextStep: 'do not resend it as if it had certainly been dropped — check the run first, and report its error code if this keeps happening',
|
|
181
|
+
};
|
|
182
|
+
const CANCEL_NOT_FOUND_COPY = {
|
|
183
|
+
happened: 'this server has no run with that id for you — it does not exist, or it belongs to someone else',
|
|
184
|
+
nextStep: 'nothing was cancelled; refresh the run list',
|
|
185
|
+
};
|
|
186
|
+
const PRIORITY_NOT_APPLIED_COPY = {
|
|
187
|
+
advisory: {
|
|
188
|
+
happened: "this server accepts a steer priority but does not apply it — a 'now' message would not interrupt the running turn and a 'later' message would not wait",
|
|
189
|
+
nextStep: 'nothing was sent; to interrupt the turn now, send the text as an interrupt, or send it without a priority to have it delivered at the next turn boundary',
|
|
190
|
+
},
|
|
191
|
+
unknown: {
|
|
192
|
+
happened: 'whether this server applies a steer priority is not known — there is no usable capability reading for it',
|
|
193
|
+
nextStep: 'nothing was sent; wait for the capability reading and try again, or send it without a priority to have it delivered at the next turn boundary',
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
const STEER_INPUT_INVALID_COPY = {
|
|
197
|
+
happened: "the steer request could not be built — its priority must be 'now', 'next' or 'later', and its fields must be readable",
|
|
198
|
+
nextStep: 'nothing was sent; fix the request and send it again',
|
|
167
199
|
};
|
|
168
|
-
const STEERING_OTHER_UNKNOWN_ADVICE = 'an unrecognized steering.* refusal (open set) — treat delivery as unknown (do not resend as if it had certainly been dropped); log the errorCode verbatim, do not guess its meaning';
|
|
169
200
|
export function steeringStatusIs4xx(e) {
|
|
170
201
|
let status;
|
|
171
202
|
try {
|
|
@@ -176,10 +207,10 @@ export function steeringStatusIs4xx(e) {
|
|
|
176
207
|
}
|
|
177
208
|
return status !== undefined && status >= 400 && status < 500;
|
|
178
209
|
}
|
|
179
|
-
function
|
|
210
|
+
function steeringCopyOf(e, safety) {
|
|
180
211
|
if (safety === 'steering_other' && !steeringStatusIs4xx(e))
|
|
181
|
-
return
|
|
182
|
-
return
|
|
212
|
+
return STEERING_OTHER_UNKNOWN_COPY;
|
|
213
|
+
return STEERING_COPY[safety];
|
|
183
214
|
}
|
|
184
215
|
const STEERING_REFUSED_BEFORE_ENGINE = new Map([['ledger_unavailable', 503]]);
|
|
185
216
|
export function steeringRefusedBeforeEngine(e) {
|
|
@@ -190,7 +221,8 @@ export function steeringRefusedBeforeEngine(e) {
|
|
|
190
221
|
const safety = steeringVerdict(e);
|
|
191
222
|
if (safety === undefined || STEERING_REFUSED_BEFORE_ENGINE.get(safety) !== status)
|
|
192
223
|
return undefined;
|
|
193
|
-
|
|
224
|
+
const copy = STEERING_COPY[safety];
|
|
225
|
+
return { safety, advice: STEERING_ADVICE[safety], happened: copy.happened, nextStep: copy.nextStep };
|
|
194
226
|
}
|
|
195
227
|
catch {
|
|
196
228
|
return undefined;
|
|
@@ -217,7 +249,8 @@ export function steerRefusalAdviceOf(e) {
|
|
|
217
249
|
if (verdict === undefined)
|
|
218
250
|
return undefined;
|
|
219
251
|
const safety = steeringSafetyOf(e, verdict);
|
|
220
|
-
|
|
252
|
+
const copy = steeringCopyOf(e, safety);
|
|
253
|
+
return { safety, advice: adviceOfCopy(copy), happened: copy.happened, nextStep: copy.nextStep };
|
|
221
254
|
}
|
|
222
255
|
catch {
|
|
223
256
|
return undefined;
|
|
@@ -245,6 +278,38 @@ function controlSafetyRefusal(code, head, advice, cause) {
|
|
|
245
278
|
const detail = { ...(advice !== undefined ? { advice } : {}), ...(status !== undefined ? { status } : {}) };
|
|
246
279
|
return new ControlSafetyError(advice === undefined ? head : `${head} — ${advice}`, code, cause, detail);
|
|
247
280
|
}
|
|
281
|
+
export const UNOBSERVED_STEER_PRIORITY = Object.freeze({ kind: 'unobserved' });
|
|
282
|
+
function steerLocalRefusal(code, mode, cause) {
|
|
283
|
+
const copy = code === 'steer_input_invalid' ? STEER_INPUT_INVALID_COPY : PRIORITY_NOT_APPLIED_COPY[mode === 'advisory' ? 'advisory' : 'unknown'];
|
|
284
|
+
return controlSafetyRefusal(code, 'steer not sent', adviceOfCopy(copy), cause);
|
|
285
|
+
}
|
|
286
|
+
function ownInputField(input, key) {
|
|
287
|
+
return Object.hasOwn(input, key) ? input[key] : undefined;
|
|
288
|
+
}
|
|
289
|
+
export function steerBodyOf(input, reading) {
|
|
290
|
+
let text;
|
|
291
|
+
let mode;
|
|
292
|
+
let priority;
|
|
293
|
+
try {
|
|
294
|
+
if (input === null || typeof input !== 'object' || Array.isArray(input))
|
|
295
|
+
throw new TypeError('steer input is not an object');
|
|
296
|
+
text = ownInputField(input, 'text');
|
|
297
|
+
mode = ownInputField(input, 'mode');
|
|
298
|
+
priority = ownInputField(input, 'priority');
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
throw steerLocalRefusal('steer_input_invalid', 'unknown', e);
|
|
302
|
+
}
|
|
303
|
+
const base = mode !== undefined ? { text, mode } : { text };
|
|
304
|
+
if (priority === undefined || priority === 'next')
|
|
305
|
+
return Object.freeze(base);
|
|
306
|
+
const tierMode = steerPriorityMode(reading);
|
|
307
|
+
if (priority !== 'now' && priority !== 'later')
|
|
308
|
+
throw steerLocalRefusal('steer_input_invalid', tierMode);
|
|
309
|
+
if (tierMode !== 'engine')
|
|
310
|
+
throw steerLocalRefusal('priority_not_applied', tierMode);
|
|
311
|
+
return Object.freeze({ ...base, priority });
|
|
312
|
+
}
|
|
248
313
|
function isCancelSuspendedConflict(e) {
|
|
249
314
|
const { name, status } = errCodes(e);
|
|
250
315
|
return name === 'ConflictError' || status === 409;
|
package/dist/coreValuePorts.d.ts
CHANGED
|
@@ -32,7 +32,7 @@ export interface CoreProtocolNamespaceView {
|
|
|
32
32
|
}
|
|
33
33
|
export interface PermissionRuleView {
|
|
34
34
|
rule: string;
|
|
35
|
-
behavior: 'deny' | 'ask'
|
|
35
|
+
behavior: 'deny' | 'ask';
|
|
36
36
|
source?: string;
|
|
37
37
|
}
|
|
38
38
|
export interface PermissionRuleIssueView {
|
|
@@ -59,8 +59,9 @@ export interface CoreValuePorts {
|
|
|
59
59
|
ruleToolGrammarOf: (toolName: string) => 'command' | 'path' | undefined;
|
|
60
60
|
validatePermissionRules: (rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView) => PermissionRuleIssueView[];
|
|
61
61
|
DISCUSSION_WORKFLOW_NAME: string;
|
|
62
|
+
mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string;
|
|
62
63
|
}
|
|
63
|
-
export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME"];
|
|
64
|
+
export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME", "mintNamespacePrefix"];
|
|
64
65
|
export type CoreValuePortName = (typeof CORE_VALUE_PORT_NAMES)[number];
|
|
65
66
|
export declare function installCoreValuePorts(ports: Partial<CoreValuePorts> | null): () => void;
|
|
66
67
|
export declare function hasCoreValuePorts(): boolean;
|
|
@@ -76,3 +77,4 @@ export declare function protocolOf(name: string): CoreProtocolNamespaceView | un
|
|
|
76
77
|
export declare function ruleToolGrammarOf(toolName: string): 'command' | 'path' | undefined;
|
|
77
78
|
export declare function validatePermissionRules(rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView): PermissionRuleIssueView[] | undefined;
|
|
78
79
|
export declare function discussionWorkflowName(): string | undefined;
|
|
80
|
+
export declare function mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string | undefined;
|
package/dist/coreValuePorts.js
CHANGED
|
@@ -9,6 +9,7 @@ export const CORE_VALUE_PORT_NAMES = Object.freeze([
|
|
|
9
9
|
'ruleToolGrammarOf',
|
|
10
10
|
'validatePermissionRules',
|
|
11
11
|
'DISCUSSION_WORKFLOW_NAME',
|
|
12
|
+
'mintNamespacePrefix',
|
|
12
13
|
]);
|
|
13
14
|
let installed = null;
|
|
14
15
|
export function installCoreValuePorts(ports) {
|
|
@@ -67,3 +68,7 @@ export function validatePermissionRules(rules, opts) {
|
|
|
67
68
|
export function discussionWorkflowName() {
|
|
68
69
|
return port('DISCUSSION_WORKFLOW_NAME');
|
|
69
70
|
}
|
|
71
|
+
export function mintNamespacePrefix(ns, peer) {
|
|
72
|
+
const fn = port('mintNamespacePrefix');
|
|
73
|
+
return fn === undefined ? undefined : fn(ns, peer);
|
|
74
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { corruptStoredRowContent, corruptStoredRowWhere } from './wireErrorTriage.js';
|
|
2
2
|
import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, parkedResumeStartupContent, parkedResumeStartupFromError, resumePolicyBlockContent, resumePolicyBlockFromError, } from './resumeRefusalCopy.js';
|
|
3
|
-
import { decideParkMovedContent, decideParkMovedFromError } from './decideReceipt.js';
|
|
3
|
+
import { askGoneContent, askGoneFromError, decideParkMovedContent, decideParkMovedFromError } from './decideReceipt.js';
|
|
4
4
|
import { settingsPermissionBucketRefusalContent, settingsPermissionBucketRefusalFromError } from './wireRefusalCopy.js';
|
|
5
5
|
export function decideFailureNote(err, decision) {
|
|
6
6
|
const where = corruptStoredRowWhere(err);
|
|
@@ -9,10 +9,12 @@ export function decideFailureNote(err, decision) {
|
|
|
9
9
|
const moved = decideParkMovedFromError(err);
|
|
10
10
|
const bucket = settingsPermissionBucketRefusalFromError(err);
|
|
11
11
|
const unsupported = checkpointUnsupportedVersionFromError(err);
|
|
12
|
+
const gone = askGoneFromError(err);
|
|
12
13
|
return ((where === undefined ? '' : ` — ${corruptStoredRowContent(where)}`) +
|
|
13
14
|
(fold === null ? '' : ` — ${resumePolicyBlockContent(fold)}`) +
|
|
14
15
|
(bucket === null ? '' : ` — ${settingsPermissionBucketRefusalContent(bucket)}`) +
|
|
15
16
|
(startup === null ? '' : ` — ${parkedResumeStartupContent(startup)}`) +
|
|
16
17
|
(moved === null ? '' : ` — ${decideParkMovedContent(moved)}`) +
|
|
17
|
-
(unsupported === null ? '' : ` — ${checkpointUnsupportedVersionContent(unsupported)}`)
|
|
18
|
+
(unsupported === null ? '' : ` — ${checkpointUnsupportedVersionContent(unsupported)}`) +
|
|
19
|
+
(gone === null ? '' : ` — ${askGoneContent(gone)}`));
|
|
18
20
|
}
|
package/dist/decideReceipt.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type GateOutcomeView } from './gateOutcome.js';
|
|
2
2
|
import { type ResumeReopenDetail } from './hitl/suspendedReopen.js';
|
|
3
|
+
import { type CrashConvergedRow } from './hitl/crashConverged.js';
|
|
3
4
|
export interface DecideReceiptView {
|
|
4
5
|
status?: string;
|
|
5
6
|
taskId?: string;
|
|
@@ -27,3 +28,11 @@ export interface DecideParkMovedDetail {
|
|
|
27
28
|
}
|
|
28
29
|
export declare function decideParkMovedFromError(e: unknown): DecideParkMovedDetail | null;
|
|
29
30
|
export declare function decideParkMovedContent(detail: Pick<DecideParkMovedDetail, 'code'>): string;
|
|
31
|
+
export interface AskGoneDetail {
|
|
32
|
+
code: 'gone.ask';
|
|
33
|
+
state?: 'VOID' | 'DENIED';
|
|
34
|
+
deniedReason?: string;
|
|
35
|
+
holderGone?: CrashConvergedRow['cause'];
|
|
36
|
+
}
|
|
37
|
+
export declare function askGoneFromError(e: unknown): AskGoneDetail | null;
|
|
38
|
+
export declare function askGoneContent(detail: AskGoneDetail): string;
|
package/dist/decideReceipt.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { gateOutcomeOf } from './gateOutcome.js';
|
|
2
2
|
import { resumeReopenFromError } from './hitl/suspendedReopen.js';
|
|
3
|
-
import { DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
|
|
3
|
+
import { ASK_GONE, ASK_GONE_DENIED_WORD, DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
|
|
4
4
|
import { effectiveWireErrorCode } from './wireErrorTriage.js';
|
|
5
5
|
import { readErrorString } from './wireFailureShape.js';
|
|
6
|
+
import { isCrashConvergedCause } from './hitl/crashConverged.js';
|
|
6
7
|
const STATUS_RESUMING = 'resuming';
|
|
7
8
|
function str(v) {
|
|
8
9
|
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
@@ -106,3 +107,63 @@ export function decideParkMovedContent(detail) {
|
|
|
106
107
|
const extra = code === DECIDE_CLAIM_LOST ? '; if this approval is still listed, wait a little before deciding it again' : '';
|
|
107
108
|
return `${what} · This decision was not applied — fetch the pending approvals again and decide from what is pending now${extra}`;
|
|
108
109
|
}
|
|
110
|
+
export function askGoneFromError(e) {
|
|
111
|
+
if (typeof e !== 'object' || e === null)
|
|
112
|
+
return null;
|
|
113
|
+
if (effectiveWireErrorCode(e) !== ASK_GONE)
|
|
114
|
+
return null;
|
|
115
|
+
const rawState = readErrorString(e, 'state');
|
|
116
|
+
const state = rawState === 'VOID' || rawState === 'DENIED' ? rawState : undefined;
|
|
117
|
+
const rawReason = readErrorString(e, 'deniedReason');
|
|
118
|
+
const deniedReason = rawReason === undefined || rawReason.length === 0
|
|
119
|
+
? undefined
|
|
120
|
+
: state === 'DENIED'
|
|
121
|
+
? rawReason === ASK_GONE_DENIED_WORD ? rawReason : undefined
|
|
122
|
+
: state === 'VOID' ? rawReason : undefined;
|
|
123
|
+
const holderGone = state === 'VOID' && isCrashConvergedCause(deniedReason) ? deniedReason : undefined;
|
|
124
|
+
return {
|
|
125
|
+
code: ASK_GONE,
|
|
126
|
+
...(state !== undefined ? { state } : {}),
|
|
127
|
+
...(deniedReason !== undefined ? { deniedReason } : {}),
|
|
128
|
+
...(holderGone !== undefined ? { holderGone } : {}),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
export function askGoneContent(detail) {
|
|
132
|
+
let state;
|
|
133
|
+
let deniedReason;
|
|
134
|
+
let holderGone;
|
|
135
|
+
try {
|
|
136
|
+
state = detail.state;
|
|
137
|
+
deniedReason = detail.deniedReason;
|
|
138
|
+
holderGone = detail.holderGone;
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
state = undefined;
|
|
142
|
+
deniedReason = undefined;
|
|
143
|
+
holderGone = undefined;
|
|
144
|
+
}
|
|
145
|
+
const st = state === 'VOID' || state === 'DENIED' ? state : undefined;
|
|
146
|
+
const safety = 'Your answer was not applied and nothing was run on it';
|
|
147
|
+
if (st === 'VOID' && (isCrashConvergedCause(holderGone) || isCrashConvergedCause(deniedReason))) {
|
|
148
|
+
return [
|
|
149
|
+
'The engine run that was waiting for this answer ended before the answer arrived',
|
|
150
|
+
safety,
|
|
151
|
+
'That run will not continue: submit the work again as a new task, and it will ask again',
|
|
152
|
+
].join(' · ');
|
|
153
|
+
}
|
|
154
|
+
if (st === 'DENIED') {
|
|
155
|
+
return ['This approval was closed without a human decision and the request was denied', safety, 'The denial stands; this approval cannot be reopened'].join(' · ');
|
|
156
|
+
}
|
|
157
|
+
if (st === 'VOID') {
|
|
158
|
+
return [
|
|
159
|
+
'This approval was withdrawn without a human decision',
|
|
160
|
+
safety,
|
|
161
|
+
'Nothing is waiting for this answer any more; if the work still needs this step, wait for it to be asked again or submit the work again',
|
|
162
|
+
].join(' · ');
|
|
163
|
+
}
|
|
164
|
+
return [
|
|
165
|
+
'This approval was closed without a human decision',
|
|
166
|
+
safety,
|
|
167
|
+
'It can no longer be decided; fetch the pending approvals again and decide from what is pending now',
|
|
168
|
+
].join(' · ');
|
|
169
|
+
}
|
package/dist/displayUntrusted.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SETTINGS_SECRET_LITERAL_RE } from './generated/settingsSchemaTables.js';
|
|
1
2
|
export const REDACTION_MARKER_PREFIX = '\u00abredacted';
|
|
2
3
|
const MARKER_RE = /^\u00abredacted(?::[a-z-]{1,16}){0,2}\u00bb$/;
|
|
3
4
|
const REDACTED_USERINFO = '\u00abredacted:userinfo\u00bb';
|
|
@@ -26,7 +27,7 @@ function pushEdit(edits, src, start, end, text) {
|
|
|
26
27
|
const UNIT_NONE = 0;
|
|
27
28
|
const UNIT_SEQUENCE = 1;
|
|
28
29
|
const UNIT_SINGLE = 2;
|
|
29
|
-
const SECRET_LITERAL_RE =
|
|
30
|
+
const SECRET_LITERAL_RE = SETTINGS_SECRET_LITERAL_RE;
|
|
30
31
|
const SCHEME_TOKEN_RE = /(?:^|[^A-Za-z0-9_-])(?:bearer|basic)[ \t]+\S{8,4096}/i;
|
|
31
32
|
const JWT_RE = /(?:^|[^A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{8,2048}\.[A-Za-z0-9_-]{8,2048}\.[A-Za-z0-9_-]{4,2048}/i;
|
|
32
33
|
function scanForSecretLiteral(s) {
|
package/dist/effectiveFacts.d.ts
CHANGED
|
@@ -7,15 +7,25 @@ export interface EffectiveReasoningView {
|
|
|
7
7
|
endpoint: string;
|
|
8
8
|
dropped?: true;
|
|
9
9
|
}
|
|
10
|
+
export type EffectiveMemoryProjectKey = {
|
|
11
|
+
readonly scope: string;
|
|
12
|
+
readonly absent?: never;
|
|
13
|
+
} | {
|
|
14
|
+
readonly absent: string;
|
|
15
|
+
readonly scope?: never;
|
|
16
|
+
};
|
|
17
|
+
export interface EffectiveMemoryScopeRow {
|
|
18
|
+
scope: string;
|
|
19
|
+
origin: 'deployment' | 'request';
|
|
20
|
+
shadowed?: number;
|
|
21
|
+
}
|
|
10
22
|
export interface EffectiveMemoryScopesView {
|
|
11
23
|
state: 'mounted' | 'memoryless' | 'none';
|
|
12
24
|
reason?: string;
|
|
13
25
|
contract?: 'v2' | 'legacy';
|
|
14
|
-
scopes: readonly
|
|
15
|
-
scope: string;
|
|
16
|
-
origin: 'deployment' | 'request';
|
|
17
|
-
}[];
|
|
26
|
+
scopes: readonly EffectiveMemoryScopeRow[];
|
|
18
27
|
writeScope: string | null;
|
|
28
|
+
projectKey?: EffectiveMemoryProjectKey;
|
|
19
29
|
materializedResidue?: readonly string[];
|
|
20
30
|
}
|
|
21
31
|
export declare function readEffectiveReasoning(v: unknown): EffectiveReasoningView | undefined;
|
package/dist/effectiveFacts.js
CHANGED
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
|
|
2
|
+
const nonBlank = (v) => typeof v === 'string' && v.trim().length > 0;
|
|
3
|
+
const UNREADABLE = Symbol('unreadable');
|
|
4
|
+
const protectedRead = (o, key) => {
|
|
5
|
+
try {
|
|
6
|
+
return o[key];
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return UNREADABLE;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
function readProjectKey(v) {
|
|
13
|
+
try {
|
|
14
|
+
if (typeof v !== 'object' || v === null || Array.isArray(v))
|
|
15
|
+
return undefined;
|
|
16
|
+
const o = v;
|
|
17
|
+
const scope = protectedRead(o, 'scope');
|
|
18
|
+
const absent = protectedRead(o, 'absent');
|
|
19
|
+
if (scope === UNREADABLE || absent === UNREADABLE)
|
|
20
|
+
return undefined;
|
|
21
|
+
if ((scope === undefined) === (absent === undefined))
|
|
22
|
+
return undefined;
|
|
23
|
+
if (scope !== undefined)
|
|
24
|
+
return nonBlank(scope) ? { scope } : undefined;
|
|
25
|
+
return nonBlank(absent) ? { absent } : undefined;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function readShadowed(r, isWriteHome) {
|
|
32
|
+
const n = protectedRead(r, 'shadowed');
|
|
33
|
+
return !isWriteHome && typeof n === 'number' && Number.isSafeInteger(n) && n > 0 ? n : undefined;
|
|
34
|
+
}
|
|
2
35
|
export function readEffectiveReasoning(v) {
|
|
3
36
|
if (typeof v !== 'object' || v === null)
|
|
4
37
|
return undefined;
|
|
@@ -27,7 +60,8 @@ export function readEffectiveMemoryScopes(v) {
|
|
|
27
60
|
return undefined;
|
|
28
61
|
if (!Array.isArray(o.scopes))
|
|
29
62
|
return undefined;
|
|
30
|
-
|
|
63
|
+
const writeScope = o.writeScope;
|
|
64
|
+
if (writeScope !== null && typeof writeScope !== 'string')
|
|
31
65
|
return undefined;
|
|
32
66
|
const contract = o.contract === 'v2' || o.contract === 'legacy' ? o.contract : undefined;
|
|
33
67
|
const reason = nonEmpty(o.reason) ? o.reason : undefined;
|
|
@@ -39,13 +73,19 @@ export function readEffectiveMemoryScopes(v) {
|
|
|
39
73
|
if (typeof row !== 'object' || row === null)
|
|
40
74
|
continue;
|
|
41
75
|
const r = row;
|
|
42
|
-
|
|
76
|
+
const scope = r.scope;
|
|
77
|
+
if (!nonEmpty(scope))
|
|
78
|
+
continue;
|
|
79
|
+
const origin = r.origin;
|
|
80
|
+
if (typeof origin !== 'string' || !ORIGINS.has(origin))
|
|
43
81
|
continue;
|
|
44
|
-
|
|
82
|
+
const shadowed = readShadowed(r, scope === writeScope);
|
|
83
|
+
scopes.push({ scope, origin: origin, ...(shadowed !== undefined ? { shadowed } : {}) });
|
|
45
84
|
}
|
|
46
|
-
|
|
85
|
+
const projectKey = readProjectKey(protectedRead(o, 'projectKey'));
|
|
86
|
+
return { state: 'mounted', contract, scopes, writeScope, ...(projectKey !== undefined ? { projectKey } : {}) };
|
|
47
87
|
}
|
|
48
|
-
if (o.scopes.length !== 0 ||
|
|
88
|
+
if (o.scopes.length !== 0 || writeScope !== null)
|
|
49
89
|
return undefined;
|
|
50
90
|
if (o.state === 'memoryless') {
|
|
51
91
|
if (reason !== 'mount-failed' && reason !== 'no-backend')
|
|
@@ -2,6 +2,7 @@ import { registryClockNowMs, registryListingProvenanceOf } from './agentSession/
|
|
|
2
2
|
import { displayUntrusted } from './displayUntrusted.js';
|
|
3
3
|
import { ABSENT_SETTLE_MS } from './fleetAgentPanelProjection.js';
|
|
4
4
|
import { isEnginePanelTaskResident, isStaleEngineAgentPanelEnd, } from './engineAgentPanelStore.js';
|
|
5
|
+
import { CORE_DURABLE_AGENT_HANDLE_RE } from './generated/engineFactTables.js';
|
|
5
6
|
export const ENGINE_AGENT_ABSENT_ROW_TEXT = 'engine no longer reports this agent · it may still be running';
|
|
6
7
|
export const ENGINE_AGENT_ABSENCE_TTL_MS = 30 * 60_000;
|
|
7
8
|
function effectiveTtl(ttlMs) {
|
|
@@ -132,7 +133,7 @@ export function engineAgentTerminalAfterDropLine(label, status, hasReport) {
|
|
|
132
133
|
return `${displayUntrusted(label)} reported ${displayUntrusted(status)} after it was dropped from the task panel${tail}`;
|
|
133
134
|
}
|
|
134
135
|
const REGISTRY_LIST_LIMIT = 500;
|
|
135
|
-
const REGISTRY_AGENT_HANDLE_RE =
|
|
136
|
+
const REGISTRY_AGENT_HANDLE_RE = CORE_DURABLE_AGENT_HANDLE_RE;
|
|
136
137
|
const REGISTRY_AGENT_TYPE = 'background_agent';
|
|
137
138
|
function registryStatusReading(status) {
|
|
138
139
|
const s = status;
|
package/dist/engineCapReader.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { snapshotCapsGeneration, capsGenerationStillCurrent } from './engineCapsGenerationGuard.js';
|
|
2
|
+
import { capsGenerationMarkOf, retainCapsGenerationMark } from './engineCapsCache.js';
|
|
2
3
|
function freezeReading(reading, seen = new Set()) {
|
|
3
4
|
if (reading === null || typeof reading !== 'object' || seen.has(reading))
|
|
4
5
|
return reading;
|
|
@@ -11,7 +12,7 @@ function freezeReading(reading, seen = new Set()) {
|
|
|
11
12
|
return reading;
|
|
12
13
|
}
|
|
13
14
|
export function createEngineCapReader(spec) {
|
|
14
|
-
const
|
|
15
|
+
const cellByBase = new Map();
|
|
15
16
|
return {
|
|
16
17
|
note(baseUrl, caps, opts) {
|
|
17
18
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
@@ -21,6 +22,7 @@ export function createEngineCapReader(spec) {
|
|
|
21
22
|
return;
|
|
22
23
|
if (!capsGenerationStillCurrent(baseUrl, gen))
|
|
23
24
|
return;
|
|
25
|
+
const mark = retainCapsGenerationMark(baseUrl);
|
|
24
26
|
let reading;
|
|
25
27
|
try {
|
|
26
28
|
reading = spec.project(caps);
|
|
@@ -28,29 +30,33 @@ export function createEngineCapReader(spec) {
|
|
|
28
30
|
catch {
|
|
29
31
|
reading = undefined;
|
|
30
32
|
}
|
|
31
|
-
if (
|
|
33
|
+
if (capsGenerationMarkOf(baseUrl) !== mark)
|
|
32
34
|
return;
|
|
33
35
|
if (reading === undefined) {
|
|
34
|
-
|
|
36
|
+
cellByBase.delete(baseUrl);
|
|
35
37
|
return;
|
|
36
38
|
}
|
|
37
|
-
|
|
39
|
+
cellByBase.set(baseUrl, { reading: freezeReading(reading), mark });
|
|
38
40
|
},
|
|
39
41
|
observed(baseUrl) {
|
|
40
42
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
41
43
|
return spec.makeUnobserved();
|
|
42
|
-
const
|
|
43
|
-
if (
|
|
44
|
-
return
|
|
45
|
-
|
|
44
|
+
const cell = cellByBase.get(baseUrl);
|
|
45
|
+
if (cell === undefined)
|
|
46
|
+
return spec.makeUnobserved();
|
|
47
|
+
if (cell.mark !== capsGenerationMarkOf(baseUrl)) {
|
|
48
|
+
cellByBase.delete(baseUrl);
|
|
49
|
+
return spec.makeUnobserved();
|
|
50
|
+
}
|
|
51
|
+
return cell.reading;
|
|
46
52
|
},
|
|
47
53
|
forget(baseUrl) {
|
|
48
54
|
if (typeof baseUrl !== 'string' || baseUrl === '')
|
|
49
55
|
return;
|
|
50
|
-
|
|
56
|
+
cellByBase.delete(baseUrl);
|
|
51
57
|
},
|
|
52
58
|
__resetForTests() {
|
|
53
|
-
|
|
59
|
+
cellByBase.clear();
|
|
54
60
|
},
|
|
55
61
|
};
|
|
56
62
|
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare function engineCapsGeneration(baseUrl: string): number;
|
|
2
|
+
export declare function capsGenerationMarkOf(baseUrl: string): object | undefined;
|
|
3
|
+
export declare function retainCapsGenerationMark(baseUrl: string): object;
|
|
2
4
|
export declare function kickEngineCapsProbe(baseUrl: string, probe: () => Promise<unknown>): void;
|
|
3
5
|
export declare function engineCapsSettled(baseUrl: string | undefined, opts?: {
|
|
4
6
|
withinMs?: number;
|
package/dist/engineCapsCache.js
CHANGED
|
@@ -3,11 +3,22 @@ const inFlight = new Set();
|
|
|
3
3
|
const settleByBase = new Map();
|
|
4
4
|
const genByBase = new Map();
|
|
5
5
|
function capsGeneration(baseUrl) {
|
|
6
|
-
return genByBase.get(baseUrl) ?? 0;
|
|
6
|
+
return genByBase.get(baseUrl)?.n ?? 0;
|
|
7
7
|
}
|
|
8
8
|
export function engineCapsGeneration(baseUrl) {
|
|
9
9
|
return capsGeneration(baseUrl);
|
|
10
10
|
}
|
|
11
|
+
export function capsGenerationMarkOf(baseUrl) {
|
|
12
|
+
return genByBase.get(baseUrl);
|
|
13
|
+
}
|
|
14
|
+
export function retainCapsGenerationMark(baseUrl) {
|
|
15
|
+
let mark = genByBase.get(baseUrl);
|
|
16
|
+
if (mark === undefined) {
|
|
17
|
+
mark = Object.freeze({ n: 0 });
|
|
18
|
+
genByBase.set(baseUrl, mark);
|
|
19
|
+
}
|
|
20
|
+
return mark;
|
|
21
|
+
}
|
|
11
22
|
export function kickEngineCapsProbe(baseUrl, probe) {
|
|
12
23
|
if (!baseUrl || capsByBase.has(baseUrl) || inFlight.has(baseUrl))
|
|
13
24
|
return;
|
|
@@ -165,7 +176,7 @@ export function invalidateEngineCaps(baseUrl, probe) {
|
|
|
165
176
|
settleByBase.has(baseUrl) ||
|
|
166
177
|
genByBase.has(baseUrl);
|
|
167
178
|
if (hadState) {
|
|
168
|
-
genByBase.set(baseUrl, capsGeneration(baseUrl) + 1);
|
|
179
|
+
genByBase.set(baseUrl, Object.freeze({ n: capsGeneration(baseUrl) + 1 }));
|
|
169
180
|
capsByBase.delete(baseUrl);
|
|
170
181
|
inFlight.delete(baseUrl);
|
|
171
182
|
settleByBase.get(baseUrl)?.wake();
|