@sema-agent/core 7.56.0 → 7.57.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 +541 -0
- package/LICENSE +1 -1
- package/dist/agents/org-delivery-gate.js +3 -4
- package/dist/agents/peer-held-queue.d.ts +69 -49
- package/dist/agents/peer-held-queue.js +255 -106
- package/dist/agents/peer-session-drain.js +63 -43
- package/dist/agents/send-message-tool.js +3 -2
- package/dist/agents/subagent.js +8 -8
- package/dist/brain/anthropic.js +16 -8
- package/dist/brain/open-responses.js +10 -8
- package/dist/brain/openai.js +11 -9
- package/dist/brain/provider-dialect.d.ts +3 -2
- package/dist/brain/provider-dialect.js +2 -2
- package/dist/brain/request-params.d.ts +6 -0
- package/dist/brain/request-params.js +14 -1
- package/dist/brain/stream-engine.d.ts +9 -0
- package/dist/brain/stream-engine.js +24 -10
- package/dist/brain/stream-shared.d.ts +5 -4
- package/dist/brain/stream-shared.js +4 -4
- package/dist/core/allow-entry.d.ts +3 -10
- package/dist/core/allow-entry.js +17 -25
- package/dist/core/approval-object.d.ts +21 -5
- package/dist/core/approval-object.js +44 -17
- package/dist/core/ask-origin.d.ts +2 -2
- package/dist/core/auto-compaction.d.ts +71 -6
- package/dist/core/auto-compaction.js +42 -26
- package/dist/core/background-agent-store.d.ts +6 -2
- package/dist/core/background-agent-store.js +1 -1
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +17 -29
- package/dist/core/checkpoint-store.js +19 -11
- package/dist/core/cross-boundary-taint.js +4 -2
- package/dist/core/engine-notice.d.ts +3 -2
- package/dist/core/engine-notice.js +6 -0
- package/dist/core/file-history-store.d.ts +14 -8
- package/dist/core/file-history-store.js +14 -4
- package/dist/core/gate-lanes.js +2 -3
- package/dist/core/hooks.d.ts +2 -2
- package/dist/core/mailbox-store.d.ts +62 -1
- package/dist/core/mailbox-store.js +59 -0
- package/dist/core/mcp-name-judge.d.ts +46 -0
- package/dist/core/mcp-name-judge.js +61 -0
- package/dist/core/mcp-probe.d.ts +1 -1
- package/dist/core/mcp-probe.js +2 -5
- package/dist/core/mcp.js +10 -30
- package/dist/core/memory-engine/consolidation-driver.js +4 -3
- package/dist/core/memory-engine/distiller.js +26 -17
- package/dist/core/memory-engine/layout.js +5 -2
- package/dist/core/park-selfcheck.js +2 -0
- package/dist/core/permission-rule-consent.d.ts +5 -3
- package/dist/core/permission-rule-consent.js +20 -15
- package/dist/core/permission-rule-model.d.ts +43 -2
- package/dist/core/permission-rule-model.js +52 -8
- package/dist/core/permission-rule-org.js +1 -1
- package/dist/core/protocol-http-auth.d.ts +16 -2
- package/dist/core/protocol-http-auth.js +42 -11
- package/dist/core/protocol-naming.d.ts +20 -0
- package/dist/core/protocol-naming.js +20 -3
- package/dist/core/read-only-shell.d.ts +20 -5
- package/dist/core/read-only-shell.js +29 -14
- package/dist/core/remote-env.d.ts +37 -1
- package/dist/core/remote-env.js +11 -0
- package/dist/core/resume-startup-cause.d.ts +24 -2
- package/dist/core/resume-startup-cause.js +20 -1
- package/dist/core/roles.js +50 -7
- package/dist/core/runner/compact-session.d.ts +10 -0
- package/dist/core/runner/compact-session.js +202 -0
- package/dist/core/runner/compaction-call-options.d.ts +2 -2
- package/dist/core/runner/compaction-seams.d.ts +21 -1
- package/dist/core/runner/compaction-seams.js +11 -8
- package/dist/core/runner/contracts.d.ts +23 -16
- package/dist/core/runner/derived-route-fallback.d.ts +13 -0
- package/dist/core/runner/derived-route-fallback.js +6 -0
- package/dist/core/runner/env-capability-census.d.ts +3 -2
- package/dist/core/runner/env-capability-census.js +9 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +7 -7
- package/dist/core/runner/permission-rule-lanes.js +17 -11
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -0
- package/dist/core/runner/prepare-config-doors.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -1
- package/dist/core/runner/prepare-hands-readface.js +2 -0
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +2 -2
- package/dist/core/runner/prepare-policy-chain.js +2 -4
- package/dist/core/runner/prepare-task.d.ts +4 -1
- package/dist/core/runner/prepare-task.js +23 -27
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +13 -0
- package/dist/core/runner/prepare-tool-disclosure-mount.js +13 -7
- package/dist/core/runner/rewind-files.d.ts +2 -5
- package/dist/core/runner/rewind-files.js +9 -51
- package/dist/core/runner/run-leg.js +10 -21
- package/dist/core/runner/run-notification-lane.d.ts +2 -0
- package/dist/core/runner/run-notification-lane.js +2 -2
- package/dist/core/runner/run-recovery-lanes.js +3 -4
- package/dist/core/runner/run-settle-and-teardown.js +5 -11
- package/dist/core/runner/run-terminal-adoption.js +3 -4
- package/dist/core/runner/run-turn-boundary.js +3 -5
- package/dist/core/runner/runtask.d.ts +8 -1
- package/dist/core/runner/runtask.js +28 -34
- package/dist/core/runner/send-message-continuation.js +1 -1
- package/dist/core/runner/session-verb-doors.d.ts +28 -0
- package/dist/core/runner/session-verb-doors.js +48 -0
- package/dist/core/runner/session-write-ledger.d.ts +30 -0
- package/dist/core/runner/session-write-ledger.js +101 -0
- package/dist/core/runner/stream-settle-backstop.js +11 -14
- package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
- package/dist/core/runner/sub-agent-deny-lists.js +21 -10
- package/dist/core/runner/teardown-bounded.d.ts +1 -0
- package/dist/core/runner/teardown-bounded.js +1 -0
- package/dist/core/runner-deps.d.ts +2 -2
- package/dist/core/secret-env.d.ts +4 -0
- package/dist/core/secret-env.js +3 -0
- package/dist/core/session-policy-store.d.ts +7 -2
- package/dist/core/session-policy-store.js +1 -1
- package/dist/core/shell-wrapper-projection.d.ts +1 -1
- package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
- package/dist/core/store-contracts/file-history-store-contract.js +9 -0
- package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
- package/dist/core/task-registry-agent.d.ts +8 -4
- package/dist/core/task-registry-agent.js +14 -8
- package/dist/core/task-registry-shared.d.ts +35 -6
- package/dist/core/task-registry-shared.js +11 -0
- package/dist/core/task-registry.d.ts +1 -1
- package/dist/core/task-registry.js +1 -1
- package/dist/core/tool-catalog-entries.d.ts +6 -0
- package/dist/core/tool-catalog-entries.js +1 -0
- package/dist/core/tool-name-aliases.d.ts +32 -2
- package/dist/core/tool-name-aliases.js +23 -0
- package/dist/core/tool-name-readings.d.ts +4 -0
- package/dist/core/tool-name-readings.js +1 -0
- package/dist/core/tool-policy.d.ts +10 -6
- package/dist/core/tool-policy.js +4 -7
- package/dist/core/trace.d.ts +4 -1
- package/dist/core/trace.js +2 -1
- package/dist/core/untrusted-egress.d.ts +20 -0
- package/dist/core/untrusted-egress.js +77 -3
- package/dist/engine/harness/agent-harness.d.ts +7 -5
- package/dist/engine/harness/agent-harness.js +11 -2
- package/dist/engine/loop/agent-loop.d.ts +1 -4
- package/dist/engine/loop/agent-loop.js +26 -4
- package/dist/index.d.ts +12 -7
- package/dist/index.js +7 -4
- package/dist/internal/harness.d.ts +2 -1
- package/dist/internal/harness.js +1 -0
- package/dist/primitives/credential-ref.d.ts +89 -0
- package/dist/primitives/credential-ref.js +125 -0
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/stores/file/checkpoint-store.d.ts +0 -4
- package/dist/stores/file/checkpoint-store.js +0 -1
- package/dist/stores/file/file-history-store.js +12 -4
- package/dist/stores/file/mailbox-store.d.ts +2 -1
- package/dist/stores/file/mailbox-store.js +26 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
- package/dist/tools/fs/bash-readonly-classifier.js +5 -10
- package/dist/tools/fs/fs-bash.js +10 -3
- package/dist/tools/fs/pattern-kill-guard.d.ts +3 -2
- package/dist/tools/fs/pattern-kill-guard.js +68 -36
- package/dist/tools/fs/shell-read-check.d.ts +10 -0
- package/dist/tools/fs/shell-read-check.js +7 -1
- package/dist/tools/fs/shell-read-identity.d.ts +12 -9
- package/dist/tools/fs/shell-read-identity.js +9 -4
- package/dist/tools/web.js +9 -7
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +79 -3
- package/wire-changes/core-stores-sql@7.57.0.json +29 -0
- package/wire-changes/core@7.57.0.json +1487 -0
- package/wire-changes/mods-kernel@7.57.0.json +29 -0
- package/wire-changes/primitives@7.57.0.json +245 -0
|
@@ -8,6 +8,7 @@ import { brainToRuntime } from "./runtime.js";
|
|
|
8
8
|
import { defuseFenceMarkers, sanitizeUntrustedText } from "./untrusted-text.js";
|
|
9
9
|
import { createSafeNotifier, observeThenableRejection } from "./safe-notify.js";
|
|
10
10
|
import { thrownText } from "./thrown-value.js";
|
|
11
|
+
import { egressThrownText } from "./untrusted-egress.js";
|
|
11
12
|
export const DEFAULT_COMPACTION_INSTRUCTIONS = "Preserve verbatim every code, identifier, name, number, file path, error message, credential " +
|
|
12
13
|
"reference, and explicit user instruction or decision mentioned anywhere in the conversation. " +
|
|
13
14
|
"When in doubt, keep the specific detail rather than generalizing it.";
|
|
@@ -21,9 +22,33 @@ export function sanitizeCompactionInstructions(text) {
|
|
|
21
22
|
: defused;
|
|
22
23
|
}
|
|
23
24
|
const COMPACTION_MANUAL_CANCEL_FLAG = "semaCompactionManualCancel";
|
|
25
|
+
const PASS_CUT = Symbol("compaction-pass-cut");
|
|
26
|
+
async function untilPassCut(start, signal) {
|
|
27
|
+
if (signal?.aborted === true)
|
|
28
|
+
return PASS_CUT;
|
|
29
|
+
if (signal === undefined)
|
|
30
|
+
return await start();
|
|
31
|
+
let release = () => undefined;
|
|
32
|
+
const cut = new Promise((resolve) => {
|
|
33
|
+
const onAbort = () => resolve(PASS_CUT);
|
|
34
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
35
|
+
release = () => signal.removeEventListener("abort", onAbort);
|
|
36
|
+
});
|
|
37
|
+
try {
|
|
38
|
+
return await Promise.race([Promise.resolve(start()), cut]);
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
release();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
24
44
|
export function isCompactionManualCancel(err) {
|
|
25
45
|
return (typeof err === "object" && err !== null && err[COMPACTION_MANUAL_CANCEL_FLAG] === true);
|
|
26
46
|
}
|
|
47
|
+
const COMPACTION_FAILURE_REASON_MAX = 512;
|
|
48
|
+
export function compactionFailureReason(err) {
|
|
49
|
+
const words = egressThrownText("same-principal", err);
|
|
50
|
+
return words.length > COMPACTION_FAILURE_REASON_MAX ? `${words.slice(0, COMPACTION_FAILURE_REASON_MAX)}…` : words;
|
|
51
|
+
}
|
|
27
52
|
function summarizationCharsCapacity(model) {
|
|
28
53
|
return model.contextWindow > 0
|
|
29
54
|
? model.contextWindow * (model.charsPerToken ?? DEFAULT_CHARS_PER_TOKEN)
|
|
@@ -161,29 +186,15 @@ export async function maybeCompact(opts) {
|
|
|
161
186
|
let providerSummary;
|
|
162
187
|
if (opts.summaryProvider && !forceRealSummary && !prep.value.isSplitTurn) {
|
|
163
188
|
const providerModifiedFiles = computeFileLists(prep.value.fileOps).modifiedFilesByRecency;
|
|
164
|
-
const
|
|
165
|
-
const
|
|
166
|
-
let release = () => undefined;
|
|
167
|
-
const cutByAbort = new Promise((resolve) => {
|
|
168
|
-
if (signal === undefined || signal.aborted)
|
|
169
|
-
return;
|
|
170
|
-
const onAbort = () => resolve(cut);
|
|
171
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
172
|
-
release = () => signal.removeEventListener("abort", onAbort);
|
|
173
|
-
});
|
|
189
|
+
const summaryProvider = opts.summaryProvider;
|
|
190
|
+
const boundary = prep.value;
|
|
174
191
|
let consulted;
|
|
175
192
|
try {
|
|
176
|
-
consulted =
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
messagesToSummarize: prep.value.messagesToSummarize,
|
|
182
|
-
previousSummary: prep.value.previousSummary,
|
|
183
|
-
modifiedFiles: providerModifiedFiles,
|
|
184
|
-
})),
|
|
185
|
-
cutByAbort,
|
|
186
|
-
]);
|
|
193
|
+
consulted = await untilPassCut(() => summaryProvider({
|
|
194
|
+
messagesToSummarize: boundary.messagesToSummarize,
|
|
195
|
+
previousSummary: boundary.previousSummary,
|
|
196
|
+
modifiedFiles: providerModifiedFiles,
|
|
197
|
+
}), opts.signal);
|
|
187
198
|
const trimmed = typeof consulted === "string" ? consulted.trim() : "";
|
|
188
199
|
if (trimmed) {
|
|
189
200
|
providerSummary = trimmed;
|
|
@@ -191,10 +202,7 @@ export async function maybeCompact(opts) {
|
|
|
191
202
|
}
|
|
192
203
|
catch {
|
|
193
204
|
}
|
|
194
|
-
|
|
195
|
-
release();
|
|
196
|
-
}
|
|
197
|
-
if (consulted === cut) {
|
|
205
|
+
if (consulted === PASS_CUT) {
|
|
198
206
|
throw Object.assign(new CompactionError("aborted", "compaction cancelled while the summary provider was answering — nothing was persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
|
|
199
207
|
}
|
|
200
208
|
}
|
|
@@ -298,7 +306,12 @@ export async function maybeCompact(opts) {
|
|
|
298
306
|
});
|
|
299
307
|
}
|
|
300
308
|
}
|
|
301
|
-
const
|
|
309
|
+
const getApiKeyAndHeaders = opts.getApiKeyAndHeaders;
|
|
310
|
+
const authed = getApiKeyAndHeaders === undefined ? undefined : await untilPassCut(() => getApiKeyAndHeaders(summaryModel), opts.signal);
|
|
311
|
+
if (authed === PASS_CUT) {
|
|
312
|
+
throw Object.assign(new CompactionError("aborted", "compaction cancelled while the summary model's credentials were being fetched — nothing was summarized or persisted"), opts.manualCancelSignal?.aborted === true ? { [COMPACTION_MANUAL_CANCEL_FLAG]: true } : {});
|
|
313
|
+
}
|
|
314
|
+
const auth = authed;
|
|
302
315
|
const summarySignal = opts.signal;
|
|
303
316
|
const runtime = brainToRuntime(opts.brain);
|
|
304
317
|
const forkCandidate = opts.compactionModel === undefined ? opts.forkContext?.() : undefined;
|
|
@@ -601,6 +614,9 @@ export function mintCompactedEvent(comp, trigger, identity) {
|
|
|
601
614
|
...identity,
|
|
602
615
|
};
|
|
603
616
|
}
|
|
617
|
+
export function manualCompactOutcomeOf(comp) {
|
|
618
|
+
return comp.compacted ? "compacted" : comp.blocked ? "blocked" : comp.disabled ? "disabled" : "noop";
|
|
619
|
+
}
|
|
604
620
|
export function mintCompactionStartedEvent(start, identity) {
|
|
605
621
|
return { type: "compaction_started", trigger: start.trigger, pass: start.pass, startedAt: start.startedAt, ...identity };
|
|
606
622
|
}
|
|
@@ -37,7 +37,11 @@ export interface BackgroundAgentRecord {
|
|
|
37
37
|
* keys on THIS field (listBySession matches it as a second arm), not on an alias walk. */
|
|
38
38
|
rootSessionId?: string;
|
|
39
39
|
parentTaskId?: string;
|
|
40
|
-
name
|
|
40
|
+
/** The agent's name — the spawner's explicit one, or the one the engine derives from `handle`
|
|
41
|
+
* (`engineAgentName`) when the spawn named none. Written by the registration that creates the row, so
|
|
42
|
+
* every row core writes carries one; a revival re-reads it verbatim. A host store that reads a row an
|
|
43
|
+
* earlier version wrote without one derives it from `handle` with the same function. */
|
|
44
|
+
name: string;
|
|
41
45
|
agentType?: string;
|
|
42
46
|
description?: string;
|
|
43
47
|
/** Revival lookup key (CC meta-sidecar parity); populated when known, never required. The team
|
|
@@ -180,7 +184,7 @@ export interface BackgroundAgentRowSummary {
|
|
|
180
184
|
sessionId?: string;
|
|
181
185
|
parentSessionId?: string;
|
|
182
186
|
rootSessionId?: string;
|
|
183
|
-
name
|
|
187
|
+
name: string;
|
|
184
188
|
agentType?: string;
|
|
185
189
|
status: BackgroundAgentRecord["status"];
|
|
186
190
|
spawnedAt: number;
|
|
@@ -183,7 +183,7 @@ function toSummary(r) {
|
|
|
183
183
|
...(r.sessionId !== undefined ? { sessionId: r.sessionId } : {}),
|
|
184
184
|
...(r.parentSessionId !== undefined ? { parentSessionId: r.parentSessionId } : {}),
|
|
185
185
|
...(r.rootSessionId !== undefined ? { rootSessionId: r.rootSessionId } : {}),
|
|
186
|
-
|
|
186
|
+
name: r.name,
|
|
187
187
|
...(r.agentType !== undefined ? { agentType: r.agentType } : {}),
|
|
188
188
|
status: r.status,
|
|
189
189
|
spawnedAt: r.spawnedAt,
|
|
@@ -6,7 +6,7 @@ import { type StoreFidelity, type Checkpoint, type CheckpointFeature, type Check
|
|
|
6
6
|
* had carried beside the one its word now names, and the members added after the table, each a capability a reader
|
|
7
7
|
* must have. Downstream reads them for display only (`CheckpointError.detail.requires`).
|
|
8
8
|
*/
|
|
9
|
-
export declare const REQUIREMENT_WORDS: readonly ["resource", "binding", "token", "orgAdmission", "f012", "realApproval", "face", "requirements_digest", "org_admission_inherited", "org_write_grant", "org_governed", "delegation_provenance", "skill_grants", "skill_card_binding", "hands_coordinates", "hands_home", "path_rule_anchors", "path_rule_installations", "permission_mode", "plan_mode_restore", "persisted_rule_mandate", "deployment_authored", "call_names", "write_face", "denial_limit_fallback", "leg_scope", "tool_ceiling", "tool_lists_judged", "own_tool_lists", "approval_targets", "cross_boundary", "mount_site", "skill_scopes"];
|
|
9
|
+
export declare const REQUIREMENT_WORDS: readonly ["resource", "binding", "token", "orgAdmission", "f012", "realApproval", "face", "requirements_digest", "org_admission_inherited", "org_write_grant", "org_governed", "delegation_provenance", "skill_grants", "skill_card_binding", "hands_coordinates", "hands_home", "path_rule_anchors", "path_rule_installations", "permission_mode", "plan_mode_restore", "persisted_rule_mandate", "deployment_authored", "call_names", "write_face", "denial_limit_fallback", "leg_scope", "tool_ceiling", "tool_lists_judged", "own_tool_lists", "approval_targets", "approval_target_reads", "cross_boundary", "mount_site", "skill_scopes"];
|
|
10
10
|
export type RequirementWord = (typeof REQUIREMENT_WORDS)[number];
|
|
11
11
|
/** Runtime twin of {@link RequirementWord}. */
|
|
12
12
|
export declare function isRequirementWord(word: unknown): word is RequirementWord;
|
|
@@ -332,6 +332,9 @@ export declare const PENDING_ACTION_REQUIREMENTS: {
|
|
|
332
332
|
readonly targets: {
|
|
333
333
|
readonly word: "approval_targets";
|
|
334
334
|
};
|
|
335
|
+
readonly targetReads: {
|
|
336
|
+
readonly word: "approval_target_reads";
|
|
337
|
+
};
|
|
335
338
|
readonly hasBidiControls: {
|
|
336
339
|
readonly ignorable: "shown, never decided (card, listing, transcript or reported count): every read of the name renders, carries transcript or counts";
|
|
337
340
|
};
|
|
@@ -844,6 +847,9 @@ export declare const CHECKPOINT_REQUIREMENTS: {
|
|
|
844
847
|
readonly targets: {
|
|
845
848
|
readonly word: "approval_targets";
|
|
846
849
|
};
|
|
850
|
+
readonly targetReads: {
|
|
851
|
+
readonly word: "approval_target_reads";
|
|
852
|
+
};
|
|
847
853
|
readonly hasBidiControls: {
|
|
848
854
|
readonly ignorable: "shown, never decided (card, listing, transcript or reported count): every read of the name renders, carries transcript or counts";
|
|
849
855
|
};
|
|
@@ -32,6 +32,7 @@ export const REQUIREMENT_WORDS = Object.freeze([
|
|
|
32
32
|
"tool_lists_judged",
|
|
33
33
|
"own_tool_lists",
|
|
34
34
|
"approval_targets",
|
|
35
|
+
"approval_target_reads",
|
|
35
36
|
"cross_boundary",
|
|
36
37
|
"mount_site",
|
|
37
38
|
"skill_scopes",
|
|
@@ -133,6 +134,7 @@ export const PENDING_ACTION_REQUIREMENTS = {
|
|
|
133
134
|
names: { word: "call_names" },
|
|
134
135
|
engineMounted: { word: "mount_site" },
|
|
135
136
|
targets: { word: "approval_targets" },
|
|
137
|
+
targetReads: { word: "approval_target_reads" },
|
|
136
138
|
hasBidiControls: SHOWN,
|
|
137
139
|
batchToolCallIds: DECISION_READ,
|
|
138
140
|
completedCallIds: SHOWN,
|
|
@@ -907,6 +907,8 @@ export type PendingAction = {
|
|
|
907
907
|
/** The approval object's TARGETS (`approvalTargetsOf`): per reading of the path slot, where it resolved when the card
|
|
908
908
|
* was asked; absent ⇒ not judged. A role resolving elsewhere at the execution vetoes the call (`resume.target_moved`). */
|
|
909
909
|
targets?: import("./approval-object.js").ApprovalTargets;
|
|
910
|
+
/** The same member's shell reading (`approvalTargetsOf`): per read candidate the shell read station judged for the parked bytes, where it landed (digests); absent ⇒ not judged. A read landing elsewhere at the execution vetoes the call (`resume.target_moved`). Word `approval_target_reads`. */
|
|
911
|
+
targetReads?: import("./approval-object.js").ApprovalTargetReads;
|
|
910
912
|
/**
|
|
911
913
|
* #438 (additive; no checkpoint-version bump — the `reminderMark` precedent: an optional field an
|
|
912
914
|
* older reader ignores. Unlike that precedent seat — which resume DOES read, through its
|
|
@@ -2771,19 +2773,6 @@ export interface CheckpointStore {
|
|
|
2771
2773
|
* that still matches.
|
|
2772
2774
|
*/
|
|
2773
2775
|
readonly fidelity?: StoreFidelity;
|
|
2774
|
-
/**
|
|
2775
|
-
* F-012 L2/L3 — the RE-DECISION capability declaration: whether this store's `reopen` (and, when
|
|
2776
|
-
* present, a durable validating-lease discipline) actually works — a promise, not a method-presence
|
|
2777
|
-
* sniff (`reopen` is optional and a stub that returns `false` still satisfies the type). The
|
|
2778
|
-
* sandbox-admission mode's pre-flight REQUIRES `redecision.reopen === true` (its boundary asks park
|
|
2779
|
-
* to a human and must be re-decidable); absent reads fail-closed as "no declared re-decision face"
|
|
2780
|
-
* and the mode refuses to arm, loudly. Same "declaration, never duck-typing" posture as
|
|
2781
|
-
* {@link retention}/{@link durability}/{@link fidelity}.
|
|
2782
|
-
*/
|
|
2783
|
-
readonly redecision?: {
|
|
2784
|
-
reopen: boolean;
|
|
2785
|
-
validatingLease?: boolean;
|
|
2786
|
-
};
|
|
2787
2776
|
/**
|
|
2788
2777
|
* The EXECUTION-OUTCOME declaration — REQUIRED, and required to be exactly `{ outcome: true }`: the
|
|
2789
2778
|
* store promises that {@link recordExecutionOutcome} is the real CAS this contract describes (the
|
|
@@ -2846,9 +2835,12 @@ export interface CheckpointStore {
|
|
|
2846
2835
|
* `resolve` CAS *before* the workspace `resumeVM` runs; if that restore then fails (`resume.env_failed`)
|
|
2847
2836
|
* the pending action never executed yet the checkpoint is consumed — without this the suspended work is
|
|
2848
2837
|
* lost to a forced "re-initiate" (fine for a short approval, ruinous for a long unattended task).
|
|
2849
|
-
* Reopening lets a retry re-resume the SAME work.
|
|
2850
|
-
*
|
|
2851
|
-
*
|
|
2838
|
+
* Reopening lets a retry re-resume the SAME work. REQUIRED — the verb is the contract (no declaration stands
|
|
2839
|
+
* for it; the store seat, {@link resolveCheckpointStore}, refuses a store that does not carry it): a claimed
|
|
2840
|
+
* resume that ends before its decided action is disposed — a failed restore, a refusal at the leg's prepare, an
|
|
2841
|
+
* abort, a leg that returns failed — returns the row here, and the engine has no lane for a store that cannot. Safe by
|
|
2842
|
+
* the `status='resolved'` guard — only the run that consumed the checkpoint (and then failed to restore) can
|
|
2843
|
+
* reopen it, and only while it is still `resolved`.
|
|
2852
2844
|
*
|
|
2853
2845
|
* **design/80 D-1 (reopen-by-reason):** the `reason` distinguishes the two reopen triggers (both shipped at
|
|
2854
2846
|
* runtask.ts) so re-resume can validate per reason (§3 inv #1): `env_failed` (the action is still valid,
|
|
@@ -2863,7 +2855,7 @@ export interface CheckpointStore {
|
|
|
2863
2855
|
* already ran or re-decide one already refused. Answers `false` like every other predicate miss; the
|
|
2864
2856
|
* reasons and the winner are untouched.
|
|
2865
2857
|
*/
|
|
2866
|
-
reopen
|
|
2858
|
+
reopen(token: CheckpointToken, scope: string, reason: ReopenReason): Promise<boolean>;
|
|
2867
2859
|
/**
|
|
2868
2860
|
* Record how the DECIDED action was finally disposed on the resumed leg — the {@link GateOutcome} its
|
|
2869
2861
|
* `tool_end` frame carried (see {@link CheckpointRow.executionOutcome} for what the record means and why
|
|
@@ -2987,9 +2979,8 @@ export interface CheckpointStore {
|
|
|
2987
2979
|
* needed semantics; "who beat me / with what" is claimant-identity territory this contract
|
|
2988
2980
|
* does not mint.
|
|
2989
2981
|
* 7. **No declaration bit** — presence of the method IS the contract (an implementation
|
|
2990
|
-
* obligation at the same level as `resolve`'s CAS promise)
|
|
2991
|
-
*
|
|
2992
|
-
* no such shape — the return form itself carries the obligation.
|
|
2982
|
+
* obligation at the same level as `resolve`'s CAS promise), as it is for the required {@link reopen}:
|
|
2983
|
+
* the return form itself carries the obligation.
|
|
2993
2984
|
*
|
|
2994
2985
|
* Deployment correspondence (an ask-row store implementing the same law maps its own vocabulary):
|
|
2995
2986
|
* token+scope ↔ the ask id (+ its run binding); pending/resolved/expired ↔ the ask row's
|
|
@@ -3079,12 +3070,13 @@ export declare function resolveCheckpointStore(spec: {
|
|
|
3079
3070
|
}, deps: {
|
|
3080
3071
|
checkpointStore?: CheckpointStore;
|
|
3081
3072
|
}): CheckpointStore | undefined;
|
|
3082
|
-
/** The ONE refusal of a store seat whose {@link CheckpointStore}
|
|
3083
|
-
*
|
|
3084
|
-
*
|
|
3085
|
-
|
|
3073
|
+
/** The ONE refusal of a store seat whose {@link CheckpointStore} lacks a required member (the {@link CheckpointStore.execution}
|
|
3074
|
+
* declaration, the {@link CheckpointStore.reopen} verb) — every missing one named, with the seat and the store's constructor when it
|
|
3075
|
+
* has one — or `undefined` when the store carries them all. Same door, same code, as the retired-`null` refusal below: a configuration
|
|
3076
|
+
* the run cannot honour is refused at the first read, never carried. */
|
|
3077
|
+
export declare function checkpointStoreIncomplete(seat: "TaskSpec.checkpointStore" | "RunnerDeps.checkpointStore", store: object): (Error & {
|
|
3086
3078
|
code: "config.invalid_checkpoint_store";
|
|
3087
|
-
};
|
|
3079
|
+
}) | undefined;
|
|
3088
3080
|
/** The ONE refusal of the retired `checkpointStore: null` spelling (the resolver and the workflow baseline overlay both throw it). */
|
|
3089
3081
|
export declare function retiredCheckpointStoreNull(): Error & {
|
|
3090
3082
|
code: "config.invalid_checkpoint_store";
|
|
@@ -3182,10 +3174,6 @@ export declare class InMemoryCheckpointStore implements CheckpointStore {
|
|
|
3182
3174
|
/** Honest declaration on the fidelity axis: `put`/`get` are `structuredClone`, so a row keeps the
|
|
3183
3175
|
* whole structured-clone domain — a `Date` filed here is a `Date` when it comes back. */
|
|
3184
3176
|
readonly fidelity: "structured-clone";
|
|
3185
|
-
/** F-012 L2: this store's `reopen` is a real resolved→pending CAS (below) — declared, not sniffed. */
|
|
3186
|
-
readonly redecision: {
|
|
3187
|
-
readonly reopen: true;
|
|
3188
|
-
};
|
|
3189
3177
|
/** The execution-outcome record verb below is the contract's CAS, and `reopen` honours the record. */
|
|
3190
3178
|
readonly execution: {
|
|
3191
3179
|
readonly outcome: true;
|
|
@@ -375,22 +375,31 @@ export function resolveCheckpointStore(spec, deps) {
|
|
|
375
375
|
if (spec.checkpointStore === "disabled")
|
|
376
376
|
return undefined;
|
|
377
377
|
if (spec.checkpointStore !== undefined) {
|
|
378
|
-
|
|
379
|
-
|
|
378
|
+
const refused = checkpointStoreIncomplete("TaskSpec.checkpointStore", spec.checkpointStore);
|
|
379
|
+
if (refused !== undefined)
|
|
380
|
+
throw refused;
|
|
380
381
|
return spec.checkpointStore;
|
|
381
382
|
}
|
|
382
|
-
if (deps.checkpointStore !== undefined
|
|
383
|
-
|
|
383
|
+
if (deps.checkpointStore !== undefined) {
|
|
384
|
+
const refused = checkpointStoreIncomplete("RunnerDeps.checkpointStore", deps.checkpointStore);
|
|
385
|
+
if (refused !== undefined)
|
|
386
|
+
throw refused;
|
|
384
387
|
}
|
|
385
388
|
return deps.checkpointStore;
|
|
386
389
|
}
|
|
387
|
-
|
|
388
|
-
|
|
390
|
+
const REQUIRED_STORE_MEMBERS = [
|
|
391
|
+
{ carried: (store) => store?.execution?.outcome === true, lacks: "does not declare `execution = { outcome: true }`", cost: "the execution-outcome record (recordExecutionOutcome, and reopen refusing a recorded row) — without it no reader can settle how a resumed approval was disposed" },
|
|
392
|
+
{ carried: (store) => typeof store?.reopen === "function", lacks: "does not carry the `reopen` verb", cost: "the claim's reversal (reopen) — without it a resume the engine claimed and then refused before its decided action was disposed would consume the approval" },
|
|
393
|
+
];
|
|
394
|
+
export function checkpointStoreIncomplete(seat, store) {
|
|
395
|
+
const read = store;
|
|
396
|
+
const missing = REQUIRED_STORE_MEMBERS.filter((m) => !m.carried(read));
|
|
397
|
+
if (missing.length === 0)
|
|
398
|
+
return undefined;
|
|
399
|
+
const ctor = read?.constructor?.name;
|
|
389
400
|
const name = typeof ctor === "string" && ctor.length > 0 && ctor !== "Object" ? ` (${ctor})` : "";
|
|
390
|
-
const e = new Error(`${seat}: the wired CheckpointStore${name}
|
|
391
|
-
"
|
|
392
|
-
"a store without it cannot record how a resumed approval was disposed, so the run is refused here rather than " +
|
|
393
|
-
"resolving rows no reader can settle. Implement the verb and add the declaration (the in-tree stores and the " +
|
|
401
|
+
const e = new Error(`${seat}: the wired CheckpointStore${name} ${missing.map((m) => m.lacks).join(" and ")} — ${missing.map((m) => m.cost).join("; ")}. ` +
|
|
402
|
+
"Each is a required member of the store contract, so the run is refused here. Implement it (the in-tree stores and the " +
|
|
394
403
|
"store-contract kit are the reference).");
|
|
395
404
|
e.code = "config.invalid_checkpoint_store";
|
|
396
405
|
return e;
|
|
@@ -548,7 +557,6 @@ export class InMemoryCheckpointStore {
|
|
|
548
557
|
retention = "none";
|
|
549
558
|
durability = "process-local";
|
|
550
559
|
fidelity = "structured-clone";
|
|
551
|
-
redecision = { reopen: true };
|
|
552
560
|
execution = { outcome: true };
|
|
553
561
|
cps = new Map();
|
|
554
562
|
fault = null;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { hasConversationContent } from "./session.js";
|
|
2
|
+
import { egressText } from "./untrusted-egress.js";
|
|
2
3
|
export const CROSS_BOUNDARY_TAINT_BITS = Object.freeze(["targetExecutionArmed", "offTargetReadObserved"]);
|
|
3
4
|
export const CROSS_BOUNDARY_POSTURES = Object.freeze(["single_user", "multi_tenant"]);
|
|
4
5
|
const postureSeatIsTheSet = true;
|
|
@@ -152,13 +153,14 @@ export function crossBoundaryPostureUndeclaredNotice(at) {
|
|
|
152
153
|
};
|
|
153
154
|
}
|
|
154
155
|
export function crossBoundaryRecordUnwrittenNotice(at) {
|
|
156
|
+
const cause = egressText("same-principal", at.cause).slice(0, 300);
|
|
155
157
|
return {
|
|
156
158
|
code: "config.cross_boundary_record_unwritten",
|
|
157
|
-
message: `The session's cross-boundary record could not be written at ${at.phase} (${
|
|
159
|
+
message: `The session's cross-boundary record could not be written at ${at.phase} (${cause}) — ` +
|
|
158
160
|
(!at.governed
|
|
159
161
|
? "the tree is not governed: no judgment reads the record, so its failure refused nothing; the tree's growth, or the leg's end, writes next, and a failure of this same state is not reported again."
|
|
160
162
|
: `the tree is governed: ${at.phase === "prepare" ? "the leg's next write (an exit before its call runs, a suspend before its row, its end) owes the record again; if none lands, " : ""}the next leg on this session reads the content after its newest record as off-target, so its device calls are put to a person.`),
|
|
161
|
-
detail: { sessionId: at.sessionId, runId: at.runId, phase: at.phase, governed: at.governed, cause
|
|
163
|
+
detail: { sessionId: at.sessionId, runId: at.runId, phase: at.phase, governed: at.governed, cause },
|
|
162
164
|
};
|
|
163
165
|
}
|
|
164
166
|
const NO_LEGS = Object.freeze([]);
|
|
@@ -400,8 +400,9 @@ export interface EngineNotice {
|
|
|
400
400
|
* is silent; a broken one must not look the same). Once per prepared leg;
|
|
401
401
|
* `detail: { problem, sessionId, runId }`.
|
|
402
402
|
* - `"config.execution_env_capability_invalid"` — a remote env DECLARES a boolean capability key
|
|
403
|
-
* (`isolation`, `suspendable`, `canonicalPathAuthoritative`) with a non-boolean value; ABSENCE is a
|
|
404
|
-
* supported reading of
|
|
403
|
+
* (`isolation`, `suspendable`, `canonicalPathAuthoritative`, `sharesProcessTable`) with a non-boolean value; ABSENCE is a
|
|
404
|
+
* supported reading of the first three and stays silent, and is announced for `sharesProcessTable`, which has no
|
|
405
|
+
* absent reading (`valueType: "undefined"`). Once per key per run; `detail: { key, valueType }`. Also minted for
|
|
405
406
|
* `withheldEnv` (key `"withheldEnv"`) when it is neither a list of findings nor `"unknown"`, read at a shell call of
|
|
406
407
|
* a root leg (once per run).
|
|
407
408
|
* - `"config.secret_env_scrubbed"` (#1081) — the D1 fail-closed `scrub` policy, or the deployment's
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { egressAccount, egressText } from "./untrusted-egress.js";
|
|
1
2
|
let malformedNoticeSeatAnnounced = false;
|
|
2
3
|
export function __resetMalformedNoticeSeatAnnouncement() {
|
|
3
4
|
malformedNoticeSeatAnnounced = false;
|
|
4
5
|
}
|
|
5
6
|
export function deliverEngineNotice(onNotice, notice) {
|
|
7
|
+
notice = {
|
|
8
|
+
...notice,
|
|
9
|
+
message: typeof notice.message === "string" ? egressText("same-principal", notice.message) : notice.message,
|
|
10
|
+
...(notice.detail !== undefined ? { detail: egressAccount("same-principal", notice.detail) } : {}),
|
|
11
|
+
};
|
|
6
12
|
if (notice.sessionId === undefined && typeof notice.detail?.["sessionId"] === "string") {
|
|
7
13
|
notice = { ...notice, sessionId: notice.detail["sessionId"] };
|
|
8
14
|
}
|
|
@@ -114,11 +114,13 @@ export interface FileHistoryError {
|
|
|
114
114
|
* whose history cannot be judged) must NOT wear this
|
|
115
115
|
* code or the failure disappears into that silence — those are `adopt_failed`, which the
|
|
116
116
|
* ADOPTION FAMILY shares: `importHistory` publishes under the same target law and answers the
|
|
117
|
-
* same code for the same non-conflict failures
|
|
118
|
-
* read
|
|
119
|
-
*
|
|
120
|
-
* answers
|
|
121
|
-
*
|
|
117
|
+
* same code for the same non-conflict failures — a source that cannot supply a referenced blob (it is
|
|
118
|
+
* absent, its read throws, or its bytes do not hash to their address), a target whose history cannot
|
|
119
|
+
* be judged, a fault in staging or publishing a good graph (the disk refusing it) — and `exportHistory`
|
|
120
|
+
* answers it for a history it cannot read whole. `unsupported_format` is the import DOOR's refusal and
|
|
121
|
+
* nothing else: a foreign-epoch or wrong-version envelope, or an envelope whose content the closed sets
|
|
122
|
+
* (or the backend's own record-naming rules) cannot hold, refused before any blob is fetched; the rest
|
|
123
|
+
* name the verb that failed. */
|
|
122
124
|
code: (typeof FILE_HISTORY_ERROR_CODES)[number];
|
|
123
125
|
message: string;
|
|
124
126
|
/** The backend's judgment of a FAULT — it could not do what it was asked — as a {@link GovernanceRetryClass}
|
|
@@ -330,8 +332,9 @@ export declare function fileHistoryExportDigest(data: FileHistoryExport): string
|
|
|
330
332
|
* The import DOOR's structural judgment, shared by every backend (a second implementation is a second
|
|
331
333
|
* opinion about what is safe to accept): the envelope must carry THIS format version and every row
|
|
332
334
|
* must be shaped and self-described from the closed sets — `unsupported_format` otherwise, never a
|
|
333
|
-
* coercion
|
|
334
|
-
* nothing and changes nothing
|
|
335
|
+
* coercion and never a throw (a payload that cannot be read is refused in the same word). Backends call
|
|
336
|
+
* this BEFORE fetching a single blob, so a foreign-epoch payload costs nothing and changes nothing, and
|
|
337
|
+
* `unsupported_format` is a word only this door (and a backend's own record-naming rule) says.
|
|
335
338
|
*/
|
|
336
339
|
export declare function validateFileHistoryExport(data: FileHistoryExport): FileHistoryResult;
|
|
337
340
|
/**
|
|
@@ -568,7 +571,10 @@ export interface FileHistoryStore {
|
|
|
568
571
|
* re-publish). A non-empty target with any other content ⇒ typed `conflict` refusal — atomic
|
|
569
572
|
* visibility prevents half-graphs, this law prevents publishing the WRONG complete graph over
|
|
570
573
|
* locally-grown history. A target whose history cannot be judged ⇒ `adopt_failed`, before any blob is
|
|
571
|
-
* fetched; a source that cannot supply a referenced blob
|
|
574
|
+
* fetched; a source that cannot supply a referenced blob — absent, its read throws, or bytes that fail
|
|
575
|
+
* their content address — ⇒ `adopt_failed`, and so is a fault in staging or publishing the graph.
|
|
576
|
+
* `unsupported_format` is the door's refusal alone ({@link validateFileHistoryExport}, before any blob
|
|
577
|
+
* is fetched). `exportHistory` answers a
|
|
572
578
|
* {@link FileHistoryExportResult}: the whole graph, `null` for nothing to export, or `adopt_failed` with the
|
|
573
579
|
* fault for a history it cannot read whole (an unreadable tracked set, boundaries that cannot be judged) —
|
|
574
580
|
* never a partial graph, and never a `null` that hides a fault.
|
|
@@ -158,6 +158,14 @@ export function fileHistoryExportDigest(data) {
|
|
|
158
158
|
return createHash("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
159
159
|
}
|
|
160
160
|
export function validateFileHistoryExport(data) {
|
|
161
|
+
try {
|
|
162
|
+
return judgeFileHistoryEnvelope(data);
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
return { ok: false, error: { code: "unsupported_format", message: `file-history import payload cannot be read: ${thrownText(err)}` } };
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function judgeFileHistoryEnvelope(data) {
|
|
161
169
|
const bad = (message) => ({ ok: false, error: { code: "unsupported_format", message } });
|
|
162
170
|
if (data === null || typeof data !== "object")
|
|
163
171
|
return bad("file-history import payload is not an envelope");
|
|
@@ -182,6 +190,8 @@ export function validateFileHistoryExport(data) {
|
|
|
182
190
|
if (typeof t.baseAvailable !== "boolean" || !Array.isArray(t.versions))
|
|
183
191
|
return bad(`tracked row ${t.relOrAbsPath} is missing its base-availability state or version chain`);
|
|
184
192
|
for (const v of t.versions) {
|
|
193
|
+
void v?.backupTime;
|
|
194
|
+
void v?.parentIdent;
|
|
185
195
|
if (typeof v?.version !== "number" || !Number.isInteger(v.version) || v.version < 1)
|
|
186
196
|
return bad(`tracked row ${t.relOrAbsPath} carries a non-integer version number`);
|
|
187
197
|
if (v.blobHash !== null && (typeof v.blobHash !== "string" || !/^[0-9a-f]{64}$/.test(v.blobHash)))
|
|
@@ -874,7 +884,7 @@ export class InMemoryFileHistoryStore {
|
|
|
874
884
|
}
|
|
875
885
|
}
|
|
876
886
|
catch (err) {
|
|
877
|
-
return { ok: false, error: { code: "
|
|
887
|
+
return { ok: false, error: { code: "adopt_failed", message: `importHistory failed: ${thrownText(err)}`, ...caughtFault(err) } };
|
|
878
888
|
}
|
|
879
889
|
}
|
|
880
890
|
async importStaged(scope, data, srcGetBlob, needed) {
|
|
@@ -888,12 +898,12 @@ export class InMemoryFileHistoryStore {
|
|
|
888
898
|
bytes = await srcGetBlob(hash);
|
|
889
899
|
}
|
|
890
900
|
catch (err) {
|
|
891
|
-
return { ok: false, error: { code: "
|
|
901
|
+
return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fetch failed: ${thrownText(err)}`, ...caughtFault(err) } };
|
|
892
902
|
}
|
|
893
903
|
if (bytes === undefined)
|
|
894
904
|
return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
|
|
895
905
|
if (createHash("sha256").update(bytes).digest("hex") !== hash) {
|
|
896
|
-
return { ok: false, error: { code: "
|
|
906
|
+
return { ok: false, error: { code: "adopt_failed", message: `source blob ${hash} fails content-address integrity — refused, nothing published` } };
|
|
897
907
|
}
|
|
898
908
|
staged.set(hash, bytes);
|
|
899
909
|
}
|
|
@@ -920,7 +930,7 @@ export class InMemoryFileHistoryStore {
|
|
|
920
930
|
return { ok: true };
|
|
921
931
|
}
|
|
922
932
|
catch (err) {
|
|
923
|
-
return { ok: false, error: { code: "
|
|
933
|
+
return { ok: false, error: { code: "adopt_failed", message: `importHistory failed: ${thrownText(err)}`, ...caughtFault(err) } };
|
|
924
934
|
}
|
|
925
935
|
}
|
|
926
936
|
}
|
package/dist/core/gate-lanes.js
CHANGED
|
@@ -7,7 +7,7 @@ import { classifierNoRulingArm, settleNoRulingAsk } from "./classifier-unavailab
|
|
|
7
7
|
import { SETTLEMENT_NOBODY_JUDGED } from "./gate-outcome.js";
|
|
8
8
|
import { inlineUntrusted } from "./untrusted-text.js";
|
|
9
9
|
import { ASK_USER_QUESTION_TOOL_NAME, isEngineQuestionFace } from "./ask-question.js";
|
|
10
|
-
import {
|
|
10
|
+
import { routesContent } from "./tool-catalog-entries.js";
|
|
11
11
|
import { applyPersistedTightening, disclosedRuleSet } from "./persisted-rule-arms.js";
|
|
12
12
|
import { skillAllowDecision, skillRowRefusal } from "./skill-grant.js";
|
|
13
13
|
import { allowRuleShadowOf, withAllowRuleShadow } from "./allow-entry.js";
|
|
@@ -27,7 +27,6 @@ import { readStationAnswer } from "./shell-read-silence.js";
|
|
|
27
27
|
import { agentIdOf, judgedInputOf, raiseToolCheck } from "./mods/stations.js";
|
|
28
28
|
import { extensionAllowOf, readToolChecks } from "./tool-check-reading.js";
|
|
29
29
|
import { policyThrowLine, reportPolicyThrow } from "./runner/policy-throw.js";
|
|
30
|
-
const routesContent = engineMountedAs(["ask-user-question", "structured-output", "report-blocked"]);
|
|
31
30
|
function parkWith(suspendAsk, parkArgs, carry) {
|
|
32
31
|
return suspendAsk(...parkArgs, carry);
|
|
33
32
|
}
|
|
@@ -336,7 +335,7 @@ export async function runGateLanes(pass) {
|
|
|
336
335
|
const command = typeof args === "object" && args !== null && !Array.isArray(args) ? args[commandParam] : undefined;
|
|
337
336
|
const backgrounded = typeof args === "object" && args !== null && args.run_in_background === true;
|
|
338
337
|
const shape = typeof command === "string" ? readShellCommand(command) : undefined;
|
|
339
|
-
if (typeof command === "string" && shape !== undefined && !backgrounded && readOnlyShellVerdict(command, shape, input.trackedCwd?.()).readOnly) {
|
|
338
|
+
if (typeof command === "string" && shape !== undefined && !backgrounded && readOnlyShellVerdict(command, { shape, cwd: input.trackedCwd?.() }).readOnly) {
|
|
340
339
|
pass.decision = {
|
|
341
340
|
action: "allow",
|
|
342
341
|
message: "the command is read-only (upstream's read-only command tables) — allowed without asking",
|
package/dist/core/hooks.d.ts
CHANGED
|
@@ -1252,8 +1252,8 @@ export interface ToolGateInput extends PermissionSeatInputs, SkillGateSeats, All
|
|
|
1252
1252
|
/**
|
|
1253
1253
|
* F-012 L2 — the SANDBOX ADMISSION leg. Present ONLY when the runner armed the mode: the execution
|
|
1254
1254
|
* env DECLARES isolation (`RemoteExecutionEnv.capabilities.isolation === true` — a Runner-resolved
|
|
1255
|
-
* fact, never caller self-report) AND the park prerequisites hold (durable park configured + a
|
|
1256
|
-
* checkpoint store
|
|
1255
|
+
* fact, never caller self-report) AND the park prerequisites hold (durable park configured + a wired
|
|
1256
|
+
* checkpoint store — every store carries the required `reopen`, read at its seat). Absent ⇒ the whole step does not
|
|
1257
1257
|
* exist and the decision path is byte-identical to a build without it.
|
|
1258
1258
|
*
|
|
1259
1259
|
* Semantics (the ruling): inside a declared sandbox, an engine-authored "confirm a potentially
|