@sema-agent/core 7.16.0 → 7.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +209 -0
- package/dist/agents/builtin-agents.d.ts +3 -3
- package/dist/agents/cross-session-envelope.d.ts +0 -1
- package/dist/agents/cross-session-envelope.js +0 -1
- package/dist/agents/peer-notices.d.ts +0 -9
- package/dist/agents/peer-notices.js +0 -63
- package/dist/agents/subagent.js +7 -15
- package/dist/brain/request-params.d.ts +2 -2
- package/dist/config/defaults.d.ts +0 -7
- package/dist/config/defaults.js +0 -2
- package/dist/core/artifact-host.d.ts +218 -0
- package/dist/core/artifact-host.js +92 -0
- package/dist/core/ask-origin.d.ts +29 -3
- package/dist/core/ask-origin.js +17 -9
- package/dist/core/ask-question.d.ts +25 -0
- package/dist/core/ask-question.js +4 -0
- package/dist/core/ask-unresolvable-notice.d.ts +30 -21
- package/dist/core/ask-unresolvable-notice.js +16 -8
- package/dist/core/auto-compaction.d.ts +10 -10
- package/dist/core/auto-mode-arming.d.ts +2 -2
- package/dist/core/background-agent-store.d.ts +5 -5
- package/dist/core/background-shell.d.ts +1 -1
- package/dist/core/checkpoint-execution-record.d.ts +0 -3
- package/dist/core/checkpoint-execution-record.js +0 -4
- package/dist/core/checkpoint-store.d.ts +71 -99
- package/dist/core/checkpoint-store.js +9 -16
- package/dist/core/context-edit.d.ts +36 -104
- package/dist/core/context-edit.js +37 -60
- package/dist/core/effective-path-target.d.ts +68 -8
- package/dist/core/effective-path-target.js +42 -30
- package/dist/core/engine-notice.d.ts +46 -32
- package/dist/core/env-budget.d.ts +31 -0
- package/dist/core/env-budget.js +39 -0
- package/dist/core/exec-output-tail.d.ts +5 -5
- package/dist/core/file-history-store.js +3 -6
- package/dist/core/fs-write-gate-policy.d.ts +1 -1
- package/dist/core/fs-write-gate-policy.js +3 -3
- package/dist/core/gate-lanes.js +9 -15
- package/dist/core/governance-codes.d.ts +1 -1
- package/dist/core/governance-codes.js +2 -0
- package/dist/core/hands-band.d.ts +1 -1
- package/dist/core/hooks.d.ts +18 -17
- package/dist/core/lsp-session.d.ts +1 -1
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/lsp.js +5 -4
- package/dist/core/mcp.d.ts +5 -5
- package/dist/core/mcp.js +4 -48
- package/dist/core/memory-engine/engine.js +2 -1
- package/dist/core/memory-engine/layout.d.ts +18 -6
- package/dist/core/memory-engine/layout.js +40 -21
- package/dist/core/memory-recall.d.ts +0 -8
- package/dist/core/memory.d.ts +1 -1
- package/dist/core/oracle-isolation.js +2 -2
- package/dist/core/parent-spec-seat.d.ts +66 -0
- package/dist/core/parent-spec-seat.js +47 -0
- package/dist/core/permission-rule-model.d.ts +11 -6
- package/dist/core/permission-rule-model.js +53 -37
- package/dist/core/permission-rules.js +8 -3
- package/dist/core/physical-path.d.ts +37 -0
- package/dist/core/physical-path.js +30 -0
- package/dist/core/protocol-naming.d.ts +2 -2
- package/dist/core/remote-env.d.ts +1 -1
- package/dist/core/retired-keys.d.ts +19 -0
- package/dist/core/retired-keys.js +15 -0
- package/dist/core/runner/active-skill-scope.js +3 -3
- package/dist/core/runner/assemble-result.d.ts +15 -13
- package/dist/core/runner/assemble-result.js +5 -4
- package/dist/core/runner/compaction-call-options.d.ts +25 -89
- package/dist/core/runner/contracts.d.ts +11 -10
- package/dist/core/runner/gate-exit.js +15 -1
- package/dist/core/runner/halt-attribution.d.ts +35 -0
- package/dist/core/runner/halt-attribution.js +16 -0
- package/dist/core/runner/memory-consolidation.d.ts +0 -2
- package/dist/core/runner/memory-consolidation.js +0 -1
- package/dist/core/runner/prepare-artifact.d.ts +52 -0
- package/dist/core/runner/prepare-artifact.js +63 -0
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -2
- package/dist/core/runner/prepare-caps-and-workflow.js +2 -3
- package/dist/core/runner/prepare-config-doors.d.ts +3 -3
- package/dist/core/runner/prepare-config-doors.js +5 -2
- package/dist/core/runner/prepare-context-lane.d.ts +2 -2
- package/dist/core/runner/prepare-context-lane.js +2 -13
- package/dist/core/runner/prepare-file-history.d.ts +1 -1
- package/dist/core/runner/prepare-file-history.js +3 -52
- package/dist/core/runner/prepare-hands-readface.d.ts +4 -7
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +5 -2
- package/dist/core/runner/prepare-inherited-gate.js +7 -8
- package/dist/core/runner/prepare-memory.d.ts +4 -6
- package/dist/core/runner/prepare-memory.js +4 -2
- package/dist/core/runner/prepare-policy-chain.d.ts +3 -3
- package/dist/core/runner/prepare-policy-chain.js +15 -30
- package/dist/core/runner/prepare-prompt-assembly.js +1 -1
- package/dist/core/runner/prepare-question-face.js +2 -1
- package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
- package/dist/core/runner/prepare-suspend-saga.js +0 -2
- package/dist/core/runner/prepare-task.js +12 -11
- package/dist/core/runner/prepare-wiring-manifest.js +9 -7
- package/dist/core/runner/resume-admission.js +2 -1
- package/dist/core/runner/resume-internals-and-config.js +4 -0
- package/dist/core/runner/retired-runner-deps.d.ts +3 -0
- package/dist/core/runner/retired-runner-deps.js +7 -0
- package/dist/core/runner/run-harness-handlers.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.d.ts +1 -1
- package/dist/core/runner/run-settle-and-teardown.js +3 -1
- package/dist/core/runner/session-file-state-replay.js +3 -3
- package/dist/core/runner/session-rule-policy.js +3 -4
- package/dist/core/runner/stream-halt-verbs.js +1 -1
- package/dist/core/runner/stream-steer-verb.js +1 -4
- package/dist/core/runner/workspace-path.js +3 -0
- package/dist/core/runner-deps.d.ts +30 -49
- package/dist/core/safe-notify.d.ts +1 -1
- package/dist/core/sensitive-path-policy.d.ts +1 -1
- package/dist/core/sensitive-path-policy.js +11 -12
- package/dist/core/session.d.ts +2 -2
- package/dist/core/skill-tool-specifier.d.ts +1 -1
- package/dist/core/skills-directory.d.ts +1 -1
- package/dist/core/skills-directory.js +4 -3
- package/dist/core/spec-contract.js +5 -4
- package/dist/core/store-contracts/checkpoint-store-contract.js +1 -1
- package/dist/core/strategy-store.d.ts +8 -11
- package/dist/core/task-event.d.ts +20 -17
- package/dist/core/task-limits.d.ts +1 -1
- package/dist/core/task-notification.d.ts +5 -5
- package/dist/core/task-registry-agent.d.ts +5 -5
- package/dist/core/task-registry-monitor.d.ts +2 -2
- package/dist/core/task-registry-shared.d.ts +32 -28
- package/dist/core/task-registry-shared.js +4 -13
- package/dist/core/task-registry.d.ts +8 -8
- package/dist/core/task-result.d.ts +37 -37
- package/dist/core/task-spec.d.ts +5 -5
- package/dist/core/task-stream.d.ts +16 -11
- package/dist/core/tool-catalog-entries.d.ts +1 -0
- package/dist/core/tool-catalog-entries.js +6 -1
- package/dist/core/tool-conformance.d.ts +0 -2
- package/dist/core/tool-conformance.js +1 -3
- package/dist/core/tool-errors.d.ts +5 -0
- package/dist/core/tool-errors.js +1 -0
- package/dist/core/tool-policy.d.ts +66 -22
- package/dist/core/tool-policy.js +31 -5
- package/dist/core/tool-result-budget.d.ts +1 -1
- package/dist/core/tool-result-store.d.ts +11 -11
- package/dist/core/tool-spec.d.ts +34 -38
- package/dist/core/tools.d.ts +2 -2
- package/dist/core/trace.d.ts +12 -15
- package/dist/core/untrusted-text.d.ts +1 -1
- package/dist/core/wiring-manifest.d.ts +4 -3
- package/dist/core/workflow-journal-store.d.ts +11 -11
- package/dist/engine/execution-env/node-execution-env.d.ts +3 -2
- package/dist/engine/execution-env/node-execution-env.js +8 -5
- package/dist/engine/harness/agent-harness.d.ts +47 -4
- package/dist/engine/harness/agent-harness.js +52 -9
- package/dist/engine/loop/agent-loop.js +15 -8
- package/dist/engine/loop/types.d.ts +5 -0
- package/dist/index.d.ts +20 -14
- package/dist/index.js +16 -10
- package/dist/internal/harness.d.ts +1 -0
- package/dist/orchestration/run-spec.d.ts +3 -0
- package/dist/orchestration/run-spec.js +3 -3
- package/dist/orchestration/run-workflow-tool.d.ts +12 -6
- package/dist/orchestration/run-workflow-tool.js +23 -5
- package/dist/orchestration/workflow-primitives.d.ts +4 -2
- package/dist/orchestration/workflow-primitives.js +1 -4
- package/dist/orchestration/workflow-script-store.js +9 -25
- package/dist/orchestration/workflow-types.d.ts +34 -4
- package/dist/orchestration/workflow-types.js +2 -0
- package/dist/orchestration/workflow.d.ts +39 -7
- package/dist/orchestration/workflow.js +237 -113
- package/dist/prompt-assembly/assemble.d.ts +2 -2
- package/dist/prompt-assembly/assemble.js +9 -9
- package/dist/prompt-assembly/composer.d.ts +6 -7
- package/dist/prompt-assembly/composer.js +10 -10
- package/dist/prompt-assembly/epoch.js +1 -1
- package/dist/prompt-assembly/event-registry.d.ts +0 -21
- package/dist/prompt-assembly/packs/sema-default.js +30 -30
- package/dist/prompt-assembly/types.d.ts +14 -14
- package/dist/prompts/coordinator.d.ts +0 -13
- package/dist/prompts/coordinator.js +0 -3
- package/dist/stores/cc/task-list-store.js +2 -10
- package/dist/stores/file/checkpoint-store.js +1 -5
- package/dist/stores/file/file-history-store.js +2 -2
- package/dist/stores/file/fs-atomic.d.ts +15 -18
- package/dist/stores/file/fs-atomic.js +4 -14
- package/dist/stores/file/mailbox-store.d.ts +7 -11
- package/dist/stores/file/mailbox-store.js +4 -11
- package/dist/stores/file/permission-rule-store.d.ts +4 -35
- package/dist/stores/file/permission-rule-store.js +4 -148
- package/dist/tools/artifact/artifact-text.d.ts +62 -0
- package/dist/tools/artifact/artifact-text.js +68 -0
- package/dist/tools/artifact/artifact-tool.d.ts +52 -0
- package/dist/tools/artifact/artifact-tool.js +351 -0
- package/dist/tools/artifact/local-stub.d.ts +26 -0
- package/dist/tools/artifact/local-stub.js +297 -0
- package/dist/tools/fs/bash-readonly-classifier.d.ts +90 -8
- package/dist/tools/fs/bash-readonly-classifier.js +294 -70
- package/dist/tools/fs/fs-bash.d.ts +14 -10
- package/dist/tools/fs/fs-bash.js +50 -33
- package/dist/tools/fs/fs-search-tools.js +5 -2
- package/dist/tools/fs/fs-shared.d.ts +2 -0
- package/dist/tools/fs/fs-shared.js +3 -11
- package/dist/tools/fs/index.d.ts +4 -0
- package/dist/tools/fs/index.js +4 -1
- package/dist/tools/fs/safety.d.ts +117 -1
- package/dist/tools/fs/safety.js +131 -31
- package/dist/tools/fs/search.js +8 -6
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +119 -39
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { forkGovernanceDenial, resolveDelegationEntryCaps } from "../../agents/subagent.js";
|
|
2
2
|
import { isLiveQuestionFace } from "../ask-question.js";
|
|
3
|
+
import { parentSpecSeatOf } from "../parent-spec-seat.js";
|
|
3
4
|
import { createPreToolUseConstraintPolicy } from "../hooks.js";
|
|
4
5
|
import { StubExecutionEnv } from "../stub-env.js";
|
|
5
|
-
import { askApproverIdentity,
|
|
6
|
+
import { askApproverIdentity, durableMandateSourceOf } from "../tool-policy.js";
|
|
6
7
|
import { attachRebuiltDenialTrackers, createDenialLimitStop } from "./denial-limit-arms.js";
|
|
7
8
|
export function prepareInheritedGate(input) {
|
|
8
9
|
const { spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun } = input;
|
|
@@ -93,6 +94,7 @@ export function prepareInheritedGate(input) {
|
|
|
93
94
|
}
|
|
94
95
|
};
|
|
95
96
|
const frozenOnQuestion = spec.onQuestion ?? deps.onQuestion;
|
|
97
|
+
const parentSpecSeat = parentSpecSeatOf(spec, frozenOnQuestion);
|
|
96
98
|
const provenanceForChildrenRef = {};
|
|
97
99
|
const delegationProvenanceForChildren = () => provenanceForChildrenRef.current;
|
|
98
100
|
const delegationSettlementRef = {};
|
|
@@ -106,8 +108,7 @@ export function prepareInheritedGate(input) {
|
|
|
106
108
|
...(ownSessionRulesRef.current !== undefined ? [ownSessionRulesRef.current] : []),
|
|
107
109
|
];
|
|
108
110
|
const ownCallerPolicy = lockedPreflight.toolPolicy;
|
|
109
|
-
const durableMandate = input.runtimeCaps()?.forceDurableGate === true
|
|
110
|
-
(spec.durableApproval !== undefined && !isLiveApproverSeat(frozenOnAsk));
|
|
111
|
+
const durableMandate = durableMandateSourceOf({ forceDurableGate: input.runtimeCaps()?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined, onAsk: frozenOnAsk }) !== undefined;
|
|
111
112
|
const contentMandate = input.runtimeCaps()?.forceDurableGate === true ||
|
|
112
113
|
(spec.durableApproval !== undefined && !isLiveQuestionFace(frozenOnQuestion));
|
|
113
114
|
const ownPreToolUse = input.preToolUseObservational() ? undefined : input.hooks()?.preToolUse;
|
|
@@ -186,15 +187,13 @@ export function prepareInheritedGate(input) {
|
|
|
186
187
|
...(readDenyAdditionsNormalized.length > 0 ? { readDenyPatterns: Object.freeze(readDenyAdditionsNormalized.map((e) => ({ ...e }))) } : {}),
|
|
187
188
|
...(spec.interactiveTools === false ? { interactiveTools: false } : {}),
|
|
188
189
|
oneShot: spec.oneShot,
|
|
189
|
-
|
|
190
|
+
parentSpecSeat,
|
|
191
|
+
...(internals?.questionFaceStripped === true ? { questionFaceStripped: true } : {}),
|
|
190
192
|
excludeTools: toolFaceSnapshot.exclude,
|
|
191
193
|
deferTools: toolFaceSnapshot.defer,
|
|
192
194
|
alwaysLoadTools: toolFaceSnapshot.alwaysLoad,
|
|
193
195
|
...(toolFaceSnapshot.restoreGated !== undefined ? { restoreGatedTools: toolFaceSnapshot.restoreGated } : {}),
|
|
194
196
|
promptProfile,
|
|
195
|
-
...(spec.additionalDirectories !== undefined ? { additionalDirectories: Object.freeze([...spec.additionalDirectories]) } : {}),
|
|
196
|
-
...(spec.additionalReadDirectories !== undefined ? { additionalReadDirectories: Object.freeze([...spec.additionalReadDirectories]) } : {}),
|
|
197
|
-
...(spec.envFacts !== undefined ? { envFacts: { ...spec.envFacts } } : {}),
|
|
198
197
|
...(spec.memoryPersistenceCapable !== undefined ? { memoryPersistenceCapable: spec.memoryPersistenceCapable } : {}),
|
|
199
198
|
get memoryCaptureOptedOut() {
|
|
200
199
|
return input.memoryEngineSession()?.captureOptOut?.optedOut() ?? false;
|
|
@@ -263,5 +262,5 @@ export function prepareInheritedGate(input) {
|
|
|
263
262
|
...(spec.enablePlanMode === true ? { enterPlanMode } : {}),
|
|
264
263
|
};
|
|
265
264
|
};
|
|
266
|
-
return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
|
|
265
|
+
return { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx };
|
|
267
266
|
}
|
|
@@ -18,12 +18,6 @@ export interface PrepareMemoryInput {
|
|
|
18
18
|
/** borrowed-readonly — the resolved task root: the containment boundary every derived memory dir
|
|
19
19
|
* is checked against, and the repo-root fallback when `deps.rootPath` is unset. */
|
|
20
20
|
taskRootPath: string;
|
|
21
|
-
/** borrowed-mutable — the caller's write-gate cell, and THIS phase is its writer: it installs the
|
|
22
|
-
* memory write gate into `.current` (the module header's one out-param effect). Identity is the
|
|
23
|
-
* contract — the caller's hands/read-face seat reads this exact cell. */
|
|
24
|
-
memoryWriteGateRef: {
|
|
25
|
-
current?: BeforeWriteHook;
|
|
26
|
-
};
|
|
27
21
|
/**
|
|
28
22
|
* borrowed-readonly — #181-F5: whether a tool NAMED `Write` (the tool the CC `# Memory` instruction names) is on the
|
|
29
23
|
* ASSEMBLED roster this run, not excluded, AND can actually REACH the host-side memory root:
|
|
@@ -199,6 +193,10 @@ export interface MemoryInjectionComposition {
|
|
|
199
193
|
export interface PrepareMemoryResult {
|
|
200
194
|
memoryEngineSession: Prepared["memoryEngineSession"];
|
|
201
195
|
memoryTools?: ToolSpec[];
|
|
196
|
+
/** owned — the memory WRITE gate (Write/Edit/NotebookEdit run their FINAL text through MemoryEngine.gateWrite when
|
|
197
|
+
* the target lands inside the memory writable root; the read-only plane refuses its own domain). Present iff a memory
|
|
198
|
+
* engine mounted; the hands phase composes it into the band's beforeWrite (a memory-less run: every write passes). */
|
|
199
|
+
memoryWriteGate?: BeforeWriteHook;
|
|
202
200
|
/**
|
|
203
201
|
* owned — #691: the injection's COMPOSITION step, run by the driver AFTER the hands phase (the mount above runs
|
|
204
202
|
* BEFORE it). It performs the one destructive read this phase has — `inject()` drains the announcement queue —
|
|
@@ -13,7 +13,8 @@ import { FileMemoryEngineBackend } from "../memory-engine/file-backend.js";
|
|
|
13
13
|
import { writableRootOf } from "../memory-engine/types.js";
|
|
14
14
|
let undeclaredCapturePostureAnnounced = false;
|
|
15
15
|
export async function prepareMemory(input) {
|
|
16
|
-
const { spec, deps, sessionId, taskRootPath,
|
|
16
|
+
const { spec, deps, sessionId, taskRootPath, admissionCtx } = input;
|
|
17
|
+
let memoryWriteGate;
|
|
17
18
|
const memorySpec = normalizeMemorySpec(spec.memory);
|
|
18
19
|
let admittedOrgScopes = [];
|
|
19
20
|
let ownOrgVerdict;
|
|
@@ -473,7 +474,7 @@ export async function prepareMemory(input) {
|
|
|
473
474
|
writeHandle.writeScope !== null &&
|
|
474
475
|
foreignUnderRoot.length === 0 &&
|
|
475
476
|
(input.advertisedWritableDirs === undefined || (await input.advertisedWritableDirs.admit({ path: writableRootOf(writeHandle), advertiser: "memory", expectCanonical: writableRootOf(writeHandle) })));
|
|
476
|
-
|
|
477
|
+
memoryWriteGate = async (w) => {
|
|
477
478
|
if (readOnlyEngine !== undefined && readOnlyHandle !== undefined) {
|
|
478
479
|
const ro = readOnlyEngine.gateWrite(readOnlyHandle, w.key, w.content);
|
|
479
480
|
if (!ro.ok)
|
|
@@ -776,6 +777,7 @@ export async function prepareMemory(input) {
|
|
|
776
777
|
ownOrgVerdict,
|
|
777
778
|
effectiveMemoryScopes,
|
|
778
779
|
...(memoryTools !== undefined ? { memoryTools } : {}),
|
|
780
|
+
...(memoryWriteGate !== undefined ? { memoryWriteGate } : {}),
|
|
779
781
|
composeInjection,
|
|
780
782
|
};
|
|
781
783
|
}
|
|
@@ -75,9 +75,9 @@ export interface PreparePolicyChainInput {
|
|
|
75
75
|
irreversible?: false;
|
|
76
76
|
egress?: false;
|
|
77
77
|
}>;
|
|
78
|
-
/** borrowed-readonly — the
|
|
79
|
-
*
|
|
80
|
-
|
|
78
|
+
/** borrowed-readonly — the ENGINE HAND roster: every tool whose effect dispatches through the task's execution env,
|
|
79
|
+
* membership minted at the mount sites (the sandbox boundary predicate's one containment fact). */
|
|
80
|
+
envHandToolNames: ReadonlySet<string>;
|
|
81
81
|
/** borrowed-readonly — the shell-seat provenance set (the offer factory's `shellGated` mandate term, read per call). */
|
|
82
82
|
shellGatedTools: ReadonlySet<string>;
|
|
83
83
|
/** borrowed-readonly — the tracked-cwd seat, read per call by the lanes and the offer factory (never written here). */
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { SEND_MESSAGE_TOOL_NAME } from "../../agents/send-message-tool.js";
|
|
2
1
|
import { policyAskClassOf } from "../ask-class.js";
|
|
3
2
|
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
4
3
|
import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
5
4
|
import { cloneObserverInput, resolveHookTimeoutMs } from "../hooks.js";
|
|
6
5
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "../permission-rules.js";
|
|
7
6
|
import { isIsolated } from "../remote-env.js";
|
|
8
|
-
import { askApproverIdentity, carryEngineAttestations, carryPrecedingSettlement, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, isLiveApproverSeat, resolveAsk, toolPolicyNameSets } from "../tool-policy.js";
|
|
7
|
+
import { askApproverIdentity, carryEngineAttestations, carryPrecedingSettlement, checkToolPolicyProjection, combinePolicies, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, durableParkOptInDeclared, isLiveApproverSeat, resolveAsk, toolPolicyNameSets, attestAskUnresolvableCause } from "../tool-policy.js";
|
|
9
8
|
import { RETIRED_TOOL_NAMES } from "../tool-name-aliases.js";
|
|
10
9
|
import { NAMESPACED_NAME_SHAPES, protocolOf } from "../protocol-table.js";
|
|
11
10
|
import { emitTrace } from "../trace.js";
|
|
@@ -16,7 +15,7 @@ import { askGrantShapeOf } from "./inherited-ask-grants.js";
|
|
|
16
15
|
import { createPermissionRuleLanes, inheritedAskRuleEvidence, createRuleOffersOf } from "./permission-rule-lanes.js";
|
|
17
16
|
import { createSessionRulePolicy } from "./session-rule-policy.js";
|
|
18
17
|
export async function preparePolicyChain(input) {
|
|
19
|
-
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives,
|
|
18
|
+
const { spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef } = input;
|
|
20
19
|
const policy = lockedPreflight.toolPolicy;
|
|
21
20
|
const auditPolicyNames = (auditee) => {
|
|
22
21
|
const nameGroups = toolPolicyNameSets(auditee);
|
|
@@ -144,6 +143,12 @@ export async function preparePolicyChain(input) {
|
|
|
144
143
|
inheritedUnavailableAsks.add(toolCallId);
|
|
145
144
|
return true;
|
|
146
145
|
};
|
|
146
|
+
const mandatedCallFloats = (toolCallId) => resolveCheckpointStore(spec, deps) !== undefined && durableParkOptInDeclared({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined }) && markInheritedUnavailable(toolCallId);
|
|
147
|
+
const mandateUnreconstructibleDeny = (creq) => attestAskUnresolvableCause({
|
|
148
|
+
action: "deny",
|
|
149
|
+
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
150
|
+
}, "mandate_unreconstructible", creq);
|
|
151
|
+
const markerChannelFullDeny = (creq) => attestAskUnresolvableCause({ action: "deny", message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed` }, "approver_unavailable", creq);
|
|
147
152
|
const inheritedAskGrants = new Map();
|
|
148
153
|
const recordInheritedAskGrant = (toolCallId, approver, presented, waitMs) => {
|
|
149
154
|
if (typeof approver !== "function")
|
|
@@ -190,7 +195,7 @@ export async function preparePolicyChain(input) {
|
|
|
190
195
|
list.push({ cls, layer });
|
|
191
196
|
foldAskClasses.set(toolCallId, list);
|
|
192
197
|
};
|
|
193
|
-
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) ||
|
|
198
|
+
const sandboxBoundaryCapable = (toolName) => egressTools.has(toolName) || !envHandToolNames.has(toolName);
|
|
194
199
|
const emitSandboxAdmitted = (info) => {
|
|
195
200
|
emitTrace(deps.tracer, () => ({
|
|
196
201
|
kind: "permission.sandbox_admitted",
|
|
@@ -358,16 +363,9 @@ export async function preparePolicyChain(input) {
|
|
|
358
363
|
};
|
|
359
364
|
}
|
|
360
365
|
if (pc.durableMandate === true) {
|
|
361
|
-
if (
|
|
362
|
-
(spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
|
|
363
|
-
markInheritedUnavailable(creq.toolCallId)) {
|
|
366
|
+
if (mandatedCallFloats(creq.toolCallId))
|
|
364
367
|
return first;
|
|
365
|
-
|
|
366
|
-
return {
|
|
367
|
-
action: "deny",
|
|
368
|
-
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
369
|
-
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
370
|
-
};
|
|
368
|
+
return mandateUnreconstructibleDeny(creq);
|
|
371
369
|
}
|
|
372
370
|
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: first, req: creq, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
373
371
|
if (judged.kind === "allow")
|
|
@@ -398,10 +396,7 @@ export async function preparePolicyChain(input) {
|
|
|
398
396
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
399
397
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
400
398
|
return inheritedAsk;
|
|
401
|
-
return
|
|
402
|
-
action: "deny",
|
|
403
|
-
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
404
|
-
};
|
|
399
|
+
return markerChannelFullDeny(creq);
|
|
405
400
|
}
|
|
406
401
|
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
407
402
|
if (resolved.action !== "allow")
|
|
@@ -437,16 +432,9 @@ export async function preparePolicyChain(input) {
|
|
|
437
432
|
};
|
|
438
433
|
}
|
|
439
434
|
if (pc.durableMandate === true) {
|
|
440
|
-
if (
|
|
441
|
-
(spec.durableApproval !== undefined || runtimeCaps?.forceDurableGate === true) &&
|
|
442
|
-
markInheritedUnavailable(creq.toolCallId)) {
|
|
435
|
+
if (mandatedCallFloats(creq.toolCallId))
|
|
443
436
|
return decision;
|
|
444
|
-
|
|
445
|
-
return {
|
|
446
|
-
action: "deny",
|
|
447
|
-
message: `inherited parent policy requires durable approval for "${creq.toolName}" — the parent's durable ` +
|
|
448
|
-
`ask cannot be reconstructed in a delegated child; denied fail-closed (tighten-only)`,
|
|
449
|
-
};
|
|
437
|
+
return mandateUnreconstructibleDeny(creq);
|
|
450
438
|
}
|
|
451
439
|
const presentedArgs = decision.updatedInput !== undefined ? decision.updatedInput : creq.args;
|
|
452
440
|
const judged = await judgeInheritedClassifier({ autoMode: pc.autoMode, ask: decision, req: { ...creq, args: presentedArgs }, signal: csignal ?? abortController.signal, subject: "this call" });
|
|
@@ -477,10 +465,7 @@ export async function preparePolicyChain(input) {
|
|
|
477
465
|
if (resolved.action === "deny" && resolved.approverUnavailable === true) {
|
|
478
466
|
if (markInheritedUnavailable(creq.toolCallId))
|
|
479
467
|
return inheritedAsk;
|
|
480
|
-
return
|
|
481
|
-
action: "deny",
|
|
482
|
-
message: `no approver is reachable for the inherited approval of "${creq.toolName}" and the marker channel is at capacity — denied fail-closed`,
|
|
483
|
-
};
|
|
468
|
+
return markerChannelFullDeny(creq);
|
|
484
469
|
}
|
|
485
470
|
settleDenialLimitFallback({ fallback, mintedHere, tracker: pc.autoMode?.denialTracking, resolved, headless: headlessDenyAtFold, stop: stopForDenialLimit, toolName: creq.toolName, toolCallId: creq.toolCallId });
|
|
486
471
|
if (resolved.action !== "allow")
|
|
@@ -95,7 +95,7 @@ export async function preparePromptAssembly(input) {
|
|
|
95
95
|
}
|
|
96
96
|
: undefined;
|
|
97
97
|
const promptConstitution = assembled.constitution;
|
|
98
|
-
const promptBlocks = assembled.
|
|
98
|
+
const promptBlocks = assembled.blocks;
|
|
99
99
|
const collisionAudit = auditToolCollisions(tools);
|
|
100
100
|
for (const y of collisionAudit.yields) {
|
|
101
101
|
onceLedger.onError(new Error(`tool mount: caller tool "${y.name}" shadows another tool with the same canonical name (deliberate last-write-wins yield — the later mount serves)`), { phase: "config", sessionId });
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createAskUserQuestionTool, isLiveQuestionFace } from "../ask-question.js";
|
|
2
2
|
import { boundInputHashOf } from "../canonical-json.js";
|
|
3
|
+
import { durableParkOptInDeclared } from "../tool-policy.js";
|
|
3
4
|
import { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
|
|
4
5
|
import { RosterBuilder } from "../tool-roster.js";
|
|
5
6
|
export { CONTENT_ASK_BINDING_CAP } from "./content-ask-bindings.js";
|
|
@@ -41,7 +42,7 @@ export function prepareQuestionFace(input) {
|
|
|
41
42
|
byDelivery.set(r.deliveryId, r);
|
|
42
43
|
return [...byDelivery.values()];
|
|
43
44
|
};
|
|
44
|
-
const durableQuestionFace = questionParkStoreWired && (
|
|
45
|
+
const durableQuestionFace = questionParkStoreWired && durableParkOptInDeclared({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined });
|
|
45
46
|
const mountedQuestionFace = liveQuestionFace !== undefined
|
|
46
47
|
? async (req, signal) => {
|
|
47
48
|
const bound = contentAskBindings.get(req.toolCallId);
|
|
@@ -12,7 +12,7 @@ export interface PrepareSafetyScanInput {
|
|
|
12
12
|
* The scan's outputs. Ownership annotations (four-class form):
|
|
13
13
|
*
|
|
14
14
|
* `ownToolNames` is **borrowed-readonly** — a first-await snapshot with no mutation anywhere after
|
|
15
|
-
* the scan
|
|
15
|
+
* the scan (sandbox containment reads the env-hand roster, not this set).
|
|
16
16
|
*
|
|
17
17
|
* The six collections are **borrowed-mutable**: the driver and later phases fold into them IN
|
|
18
18
|
* PLACE (identity is part of the contract — closures alias these exact objects). Mutation owners
|
|
@@ -106,7 +106,6 @@ export function prepareSuspendSaga(input) {
|
|
|
106
106
|
activeTools: [...activeTools],
|
|
107
107
|
outputRef: { value: outputRef.value, set: outputRef.set },
|
|
108
108
|
nestedStats: { ...nestedStats },
|
|
109
|
-
consolidationNotes: undefined,
|
|
110
109
|
readFileState: readFileStateForCheckpoint ? [...readFileStateForCheckpoint.entries()] : undefined,
|
|
111
110
|
readFace: faceCheckpointSection(),
|
|
112
111
|
reminderMark,
|
|
@@ -121,7 +120,6 @@ export function prepareSuspendSaga(input) {
|
|
|
121
120
|
.map((t) => ({ id: t.task_id, ...(t.description !== undefined ? { description: t.description } : {}) }));
|
|
122
121
|
return live.length > 0 ? live : undefined;
|
|
123
122
|
})(),
|
|
124
|
-
pendingSteer: undefined,
|
|
125
123
|
pendingSteerQueue: undefined,
|
|
126
124
|
inheritedGate: (() => {
|
|
127
125
|
const requiresParentConstraint = (inheritedParentConstraints?.length ?? 0) > 0 || seedInheritedGate?.requiresParentConstraint === true;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { realpathSync } from "node:fs";
|
|
2
1
|
import { resolve as resolveFsPath } from "node:path";
|
|
3
2
|
import { AgentHarness, DEFAULT_CLAMP_TOLERANCE, DEFAULT_COMPACTION_SETTINGS, summaryOutputBudgetTokens } from "../../internal/harness.js";
|
|
4
3
|
import { sanitizeCompactionSettings } from "../auto-compaction.js";
|
|
4
|
+
import { physicalPathOf } from "../physical-path.js";
|
|
5
5
|
import { projectStaleToolResults, resolveStaleToolResultOffload } from "./compaction-call-options.js";
|
|
6
6
|
import { uuidv7 } from "../../engine/session/uuid.js";
|
|
7
7
|
import { brainToRuntime } from "../runtime.js";
|
|
@@ -58,6 +58,7 @@ import { derivedRouteFallsBack } from "./derived-route-fallback.js";
|
|
|
58
58
|
import { prepareProtocolTools } from "./prepare-protocol-tools.js";
|
|
59
59
|
import { prepareQuestionFace } from "./prepare-question-face.js";
|
|
60
60
|
import { prepareLsp } from "./prepare-lsp.js";
|
|
61
|
+
import { prepareArtifact } from "./prepare-artifact.js";
|
|
61
62
|
import { createRollbackStack } from "./rollback-stack.js";
|
|
62
63
|
export { __resetMaterializeEnvAnnouncements } from "./prepare-tool-disclosure-mount.js";
|
|
63
64
|
export { fileHistoryFilesystemIdentity, resolveFileHistoryScope } from "./prepare-file-history.js";
|
|
@@ -70,6 +71,7 @@ import { createSchedulerTools } from "../../tools/scheduler-tools.js";
|
|
|
70
71
|
import { selfOrchestrationFailClosedReason } from "../../orchestration/workflow-script-runner.js";
|
|
71
72
|
import { remainingBudgetMicroUsd, resolveCheckpointStore } from "../checkpoint-store.js";
|
|
72
73
|
import { checkpointSeatOf } from "../checkpoint-seat.js";
|
|
74
|
+
import { handsWriteHalfMounts } from "../../tools/fs/index.js";
|
|
73
75
|
import { durableParkGapFor } from "../park-selfcheck.js";
|
|
74
76
|
import { deliverEngineNotice } from "../types.js";
|
|
75
77
|
import { ToolRosterDeltaSeat } from "../tool-roster.js";
|
|
@@ -264,7 +266,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
264
266
|
const { toolFaceSnapshot, promptProfile, lockedPreflight, resolvedInteractionPosture, microCompactKnob, resolvedRole, model, thinking, compModel, fableMitigations, memoryDelegationEvidence, memoryProvenance, memoryCapturePolicy, usageWindows, brainCallGuardrailRef, brainCallGuardrailMs } = doors;
|
|
265
267
|
announceToolModelGate(deps.onNotice, model.id, doors.modelGate);
|
|
266
268
|
const modelGateManifest = toolModelGateManifest(doors.modelGate);
|
|
267
|
-
const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes
|
|
269
|
+
const { toolEffects, egressTools, irreversibleTools, irreversibilityTier, axisExplicitNegatives, reversibilityProbes } = prepareSafetyScan({ spec, deps });
|
|
268
270
|
let shellGatedTools = new Set();
|
|
269
271
|
refuseRequireExistingWithoutSession(spec);
|
|
270
272
|
const { acquired, session, conflictRef, wakeRecovered, resumeAtBeforeParentId } = await prepareAcquireReconcile({ sessions, spec, resume, toolEffects, ...(internals?.sessionPlacement !== undefined ? { placement: internals.sessionPlacement } : {}), ...(() => { const g = durableParkGapFor(deps, spec); return g !== undefined ? { durableParkGap: g } : {}; })() });
|
|
@@ -344,7 +346,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
344
346
|
else {
|
|
345
347
|
const canonical = (p, what) => {
|
|
346
348
|
try {
|
|
347
|
-
return
|
|
349
|
+
return physicalPathOf(resolveFsPath(p));
|
|
348
350
|
}
|
|
349
351
|
catch (err) {
|
|
350
352
|
return failIsolation(`cannot canonicalize ${what} (${err instanceof Error ? err.message : String(err)}) — an unverifiable path is treated as not isolated`);
|
|
@@ -368,8 +370,8 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
368
370
|
let resolvedReadFace;
|
|
369
371
|
let readDenyAdditionsNormalized = [];
|
|
370
372
|
let handsLessResolvedFace;
|
|
371
|
-
const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDecider, autoModeDenialTracking: () => autoModeDenialTracking, autoModeArming: () => autoModeArming, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
|
|
372
|
-
const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
|
|
373
|
+
const { liveInheritedGate, seedInheritedGate, inheritedAncestorRules, inheritedShellGate, inheritedParentConstraints, autoModeIntent, inheritedAdmittedOrgScopes, priorOwnOrgVerdict, orgGovernedProvenance, effectiveShellGate, ownSessionRulesRef, memoryAdmittedOrgScopesRef, ownOrgVerdictRef, orgAdmissionCheckpointState, faceCheckpointSection, faceCheckpointState, f012CheckpointState, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, frozenOnQuestion, parentSpecSeat, provenanceForChildrenRef, delegationSettlementRef, inheritedGateForChildren, carrierReadFace, fullShellReachable, gateStopRef, stopForDenialLimit, enrichSpecToolCtx } = prepareInheritedGate({ spec, deps, internals, resume, sessions, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, ownedEnv, lockedPreflight, checkpointSeat, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, autoModeSeat, handsEnabled, reportUsage, harnessRef, skillScope, forwardEvent, subagentRetain, worktreeIsolation, requestReview, requestStopAfterTurn, enterPlanMode, reminderMark, reminderDisclosureCounts, fileHistoryEnabled, historyScope, historyRoot, historyFs, abortRun: () => { abortController.abort(); void harness.abort(); }, runtimeCaps: () => runtimeCaps, hooks: () => hooks, preToolUseObservational: () => preToolUseObservational, hookTimeoutMs: () => hookTimeoutMs, hookEnvFace: () => hookEnvFace, autoModeDecider: () => autoModeDecider, autoModeDenialTracking: () => autoModeDenialTracking, autoModeArming: () => autoModeArming, agentForkDenial: () => agentForkDenial, observersActive: () => observersActive, resolvedReadFace: () => resolvedReadFace, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized, handsLessResolvedFace: () => handsLessResolvedFace, centerAdoption: () => centerAdoptionRef.current, memoryEngineSession: () => memoryEngineSession });
|
|
374
|
+
const { roster, blockedRef, runtimeCaps, runtimeCapsFaulted, complianceDenies, complianceDegraded, agentForkDenial, observersActive, autoModeArmReason, autoModeDecider, autoModeDenialTracking, autoModeArming, selfOrchestrationActive, workflowToolsActive, workflowSizeGuideline } = await prepareCapsAndWorkflow({ spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, checkpointSeat, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, parentSpecSeat, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf, memoryEngineSession: () => memoryEngineSession, centerAdoption: () => centerAdoptionRef.current, readDenyAdditionsNormalized: () => readDenyAdditionsNormalized });
|
|
373
375
|
const tools = roster.tools;
|
|
374
376
|
const pausedRef = {};
|
|
375
377
|
const remoteEnvFailures = [];
|
|
@@ -432,11 +434,10 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
432
434
|
const { mcp, a2a, rebuildHarnessToolsRef, contentOriginWrapRef, toolCallGateArmedRef } = await prepareProtocolTools({ lockedPreflight, spec, deps, reminderMark, reminderDisclosureCounts, runId, sessionId, onceLedger, roster, rosterSeat, remoteToolOffload, toolFaceSnapshot, toolEffects, axisExplicitNegatives, irreversibilityTier, irreversibleTools, egressTools, abortController, rollback });
|
|
433
435
|
const callIssuedAtRef = {};
|
|
434
436
|
const workCutRef = { continuation: false, abortedBeforeTurnEnd: false };
|
|
435
|
-
const memoryWriteGateRef = {};
|
|
436
437
|
const advertisedWritableDirs = handsEnabled
|
|
437
438
|
? new AdvertisedWritableDirs(executionEnv, (dir, reason) => deps.onError?.(new Error(`${dir.advertiser} advertised writable directory skipped (cannot canonicalize): ${dir.path} — ${reason}`), { phase: "config", sessionId }))
|
|
438
439
|
: undefined;
|
|
439
|
-
const handsWriteHalfPlanned = handsEnabled && spec.handsReadOnly
|
|
440
|
+
const handsWriteHalfPlanned = handsEnabled && handsWriteHalfMounts({ readOnly: spec.handsReadOnly === true });
|
|
440
441
|
const memoryPairNameDomain = new Set();
|
|
441
442
|
for (const t of tools) {
|
|
442
443
|
memoryPairNameDomain.add(t.name);
|
|
@@ -455,12 +456,11 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
455
456
|
return { fault: true };
|
|
456
457
|
}
|
|
457
458
|
})();
|
|
458
|
-
const { memoryEngineSession, memoryTools, composeInjection: composeMemoryInjection, admittedOrgScopes: memoryAdmittedOrgScopes, ownOrgVerdict: memoryOwnOrgVerdict, effectiveMemoryScopes: memoryEffectiveScopes, } = await prepareMemory({
|
|
459
|
+
const { memoryEngineSession, memoryTools, memoryWriteGate, composeInjection: composeMemoryInjection, admittedOrgScopes: memoryAdmittedOrgScopes, ownOrgVerdict: memoryOwnOrgVerdict, effectiveMemoryScopes: memoryEffectiveScopes, } = await prepareMemory({
|
|
459
460
|
spec,
|
|
460
461
|
deps,
|
|
461
462
|
sessionId,
|
|
462
463
|
taskRootPath: taskRootFinal,
|
|
463
|
-
memoryWriteGateRef,
|
|
464
464
|
reminderMark,
|
|
465
465
|
writeToolsMounted: (handsWriteHalfPlanned || tools.some((t) => t.name === "Write")) &&
|
|
466
466
|
!(toolFaceSnapshot.exclude?.includes("Write") ?? false) &&
|
|
@@ -505,7 +505,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
505
505
|
if (internals?.ownOrgAdmissionRef !== undefined && ownOrgVerdictRef.current !== undefined) {
|
|
506
506
|
internals.ownOrgAdmissionRef.current = ownOrgVerdictRef.current;
|
|
507
507
|
}
|
|
508
|
-
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals,
|
|
508
|
+
const handsReadFaceInput = { handsEnabled, executionEnv, taskRootFinal, rebaseRestoredPath, resume, session, sessionId, hostTaskId, taskScope, fullShellReachable, effectiveShellGate, toolFaceSnapshot, model, spec, deps, internals, memoryWriteGate, ...(advertisedWritableDirs !== undefined ? { advertisedWritableDirs } : {}), firstPartyOffload, roster, egressTools, irreversibilityTier, irreversibleTools, reversibilityProbes, reminderMark, reminderDisclosureCounts, ...(trackFileEdit !== undefined ? { trackFileEdit } : {}), onFileEdited: noteFileEdited, ...(restoredFilePaths.length > 0 ? { restoredFilePaths } : {}) };
|
|
509
509
|
const handsReadFace = handsEnabled ? await prepareHandsMount(handsReadFaceInput) : resolveHandsLessReadFace(handsReadFaceInput);
|
|
510
510
|
const { readFileStateForCheckpoint, seedContextFiles, handsCwdRef, workspaceStateSettle, wsSnapshot, rebaseWsPath, backgroundTaskToolsActive, additionalRootsCanonical, additionalReadRootsCanonical, attachmentRootCanonical, readDenyMatcher, envHandToolNames, sealReadStateSeat } = handsReadFace;
|
|
511
511
|
resolvedReadFace = handsReadFace.resolvedReadFace;
|
|
@@ -532,6 +532,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
532
532
|
`(per-principal entitlement governance, not a misconfiguration — Agent(subagent_type:"fork") will refuse honestly)`), { phase: "config", sessionId });
|
|
533
533
|
}
|
|
534
534
|
const { lspDiagnostics, nudgeLspOnEdit, lspRunIdent } = prepareLsp({ spec, deps, executionEnv, taskRootFinal, handsEnabled, sessionId, handsCwdRef, roster, envHandToolNames });
|
|
535
|
+
prepareArtifact({ deps, runId, taskId: hostTaskId, sessionId, agentName: internals?.explicitAgentName, executionEnv, rootCanonical: attachmentRootCanonical, additionalRootsCanonical: [...additionalRootsCanonical, ...additionalReadRootsCanonical], readDenyMatcher, resolvedReadFace, handsCwdRef, roster, firstPartyOffload, envHandToolNames });
|
|
535
536
|
if (internals?.delegationProvenance !== undefined && resume !== undefined) {
|
|
536
537
|
const live = internals.delegationProvenance.ref.current;
|
|
537
538
|
const seed = resume.seed.delegationProvenance;
|
|
@@ -681,7 +682,7 @@ export async function prepareTask(spec, deps, sessions, resume, internals, runne
|
|
|
681
682
|
releaseSignal = () => sig.removeEventListener("abort", onExternalAbort);
|
|
682
683
|
}
|
|
683
684
|
}
|
|
684
|
-
const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives,
|
|
685
|
+
const { hooks, hookTimeoutMs, preToolUseObservational, ownGatePreToolUse, basePolicyForResumeEdit, denyNarrowingPolicy, policyLayers, effectivePolicy, inheritedUnavailableAsks, inheritedAskGrants, askSourceIdentity, riskAxesOf, ruleOffersOf, permissionRuleLane, permissionRuleOrgLane, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, foldAskClasses, ancestorSandboxAdmissions } = await preparePolicyChain({ spec, deps, internals, sessionId, runId, hostTaskId, taskRootFinal, executionEnv, lockedPreflight, tools, harnessTools, toolEffects, egressTools, irreversibilityTier, axisExplicitNegatives, shellGatedTools, envHandToolNames, handsCwdRef, readDenyMatcher, questionToolMounted, runtimeCaps, inheritedAncestorRules, inheritedParentConstraints, seedInheritedGate, hasSkillManifest, skillScope, frozenOnAsk, hookEnvSource, notifyOwnHookCrash, autoModeDecider, stopForDenialLimit, delegation, abortController, now, ownSessionRulesRef });
|
|
685
686
|
const { onAsk, preToolContexts, blockedToolCalls, gateOutcomes, batchHaltRef, blockedTracked, incompleteSuspendAdapter, durableSuspendInfraReady, resourceSuspendEligible, usageGovernance, durableApproval, wiringManifest, parkLaneArmed, gateMachineryActive, hookIdentity, hookEnvFace } = prepareWiringManifest({ spec, deps, internals, resume, sessionId, runId, hostTaskId, taskScope, hooks, preToolUseObservational, policyLayers, effectivePolicy, handsEnabled, mcp, irreversibleTools, egressTools, toolEffects, ownedEnv, executionEnv, offloadStore, onceLedger, usageWindows, envLifetimeSuspendAt, runtimeCaps, resolvedInteractionPosture, durableQuestionFace, liveQuestionFace, checkpointStore, sessions, modelGateManifest, autoModeArmReason, lockedPreflight, peerLaneRefs, peerLaneActive, harness, pausedRef, frozenOnAsk, liveInheritedGate, delegation, toolRoster });
|
|
686
687
|
if (fileHistoryBoundary !== undefined) {
|
|
687
688
|
harness.on("tool_call", async () => {
|
|
@@ -3,7 +3,7 @@ import { resolveCheckpointStore } from "../checkpoint-store.js";
|
|
|
3
3
|
import { createHookEnvCapabilities, mintHookInvocationIdentity } from "../hooks.js";
|
|
4
4
|
import { isRemoteExecutionEnv, missingRestoreSurface } from "../remote-env.js";
|
|
5
5
|
import { isVolatileOffloadStore } from "../tool-result-store.js";
|
|
6
|
-
import { isLiveApproverSeat } from "../tool-policy.js";
|
|
6
|
+
import { durableMandateSourceOf, isLiveApproverSeat } from "../tool-policy.js";
|
|
7
7
|
import { deliverEngineNotice } from "../types.js";
|
|
8
8
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
9
9
|
import { GLOBAL_USAGE_KEY, usageRetryAfterMs, windowsGovernCost } from "../usage-window-store.js";
|
|
@@ -84,24 +84,26 @@ function buildUsageGovernance(windows, deps, principal, sessionId) {
|
|
|
84
84
|
}
|
|
85
85
|
const ungatedWarnedShapes = new WeakMap();
|
|
86
86
|
function announceDurableGateUnavailable(args) {
|
|
87
|
-
if (
|
|
87
|
+
if (args.mandate === undefined || args.storeWired)
|
|
88
88
|
return;
|
|
89
|
+
const source = args.mandate;
|
|
89
90
|
const cause = args.taskStoreDisabled ? "task_store_disabled" : "no_deployment_store";
|
|
90
91
|
const inheritedContentMandate = (args.parentConstraints ?? []).some((pc) => pc.contentMandate === true);
|
|
91
92
|
const liveQuestionFace = args.liveQuestionFace && !inheritedContentMandate;
|
|
92
93
|
deliverEngineNotice(args.onNotice, {
|
|
93
94
|
code: "config.durable_gate_unavailable",
|
|
94
|
-
message: `Durable approval gate mandated but unavailable: the runtime entitlement forceDurableGate is in force for this ` +
|
|
95
|
-
`
|
|
95
|
+
message: `Durable approval gate mandated but unavailable: ${source === "force_durable_gate" ? "the runtime entitlement forceDurableGate is in force for this principal" : "this task opted into durable approval (durableApproval) with no live approver seat"}, ` +
|
|
96
|
+
`but ${cause === "task_store_disabled" ? 'this task disabled the checkpoint store (checkpointStore: "disabled")' : "this deployment wired no checkpoint store"}, ` +
|
|
96
97
|
`so no interactive ask of this task can be parked for a durable answer. Asks resolve on the live chain instead ` +
|
|
97
|
-
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : "permission asks are denied fail-closed — no live approver is wired"}; ` +
|
|
98
|
+
`(${args.liveApprover ? "a live approver answers permission asks in-stream" : args.blanketAllow ? 'a blanket "allow" posture answers ordinary permission asks without judgment (a mandated ask is refused)' : "permission asks are denied fail-closed — no live approver is wired"}; ` +
|
|
98
99
|
`${liveQuestionFace ? "a live question face answers AskUserQuestion in-stream" : args.liveQuestionFace ? "AskUserQuestion is withheld from the live face by an inherited durable mandate and refused" : "AskUserQuestion has no live face and is refused"}) ` +
|
|
99
|
-
`and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store
|
|
100
|
+
`and NO durable approval record is written. ${cause === "task_store_disabled" ? "Run this task with its store" : "Wire a checkpoint store on this deployment"}, or ${source === "force_durable_gate" ? "withdraw the entitlement for principals served here" : "give the task a live approver seat (or drop durableApproval)"}.`,
|
|
100
101
|
detail: {
|
|
101
102
|
sessionId: args.sessionId,
|
|
102
103
|
runId: args.runId,
|
|
103
104
|
...(args.principal ? { principal: args.principal } : {}),
|
|
104
105
|
cause,
|
|
106
|
+
source,
|
|
105
107
|
liveApprover: args.liveApprover,
|
|
106
108
|
liveQuestionFace,
|
|
107
109
|
},
|
|
@@ -225,7 +227,7 @@ export function prepareWiringManifest(input) {
|
|
|
225
227
|
resourceSuspendEligible ||
|
|
226
228
|
platformSuspendArmed ||
|
|
227
229
|
spec.enablePlanMode === true;
|
|
228
|
-
announceDurableGateUnavailable({ onNotice: deps.onNotice, forceDurableGate: runtimeCaps?.forceDurableGate === true, storeWired: checkpointStore !== undefined, taskStoreDisabled: spec.checkpointStore === "disabled", liveApprover: isLiveApproverSeat(frozenOnAsk), liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
230
|
+
announceDurableGateUnavailable({ onNotice: deps.onNotice, mandate: durableMandateSourceOf({ forceDurableGate: runtimeCaps?.forceDurableGate === true, durableApprovalDeclared: spec.durableApproval !== undefined, onAsk: frozenOnAsk }), storeWired: checkpointStore !== undefined, taskStoreDisabled: spec.checkpointStore === "disabled", liveApprover: isLiveApproverSeat(frozenOnAsk), blanketAllow: frozenOnAsk === "allow", liveQuestionFace: liveQuestionFace !== undefined, parentConstraints: liveInheritedGate?.parentConstraints, sessionId, runId, principal: spec.principal });
|
|
229
231
|
const hookIdentity = mintHookInvocationIdentity({
|
|
230
232
|
sessionId,
|
|
231
233
|
taskId: hostTaskId,
|
|
@@ -36,6 +36,7 @@ export async function resumeAdmission(input) {
|
|
|
36
36
|
const outcomeGate = outcome.gate;
|
|
37
37
|
const resumeSignal = config.signal;
|
|
38
38
|
let suppliedMessage;
|
|
39
|
+
const parkedSteers = readPendingSteerQueue(cp.state);
|
|
39
40
|
if (outcomeGate === "wake") {
|
|
40
41
|
suppliedMessage = outcome.message;
|
|
41
42
|
const gk = cp.gate.kind;
|
|
@@ -74,7 +75,7 @@ export async function resumeAdmission(input) {
|
|
|
74
75
|
if (suppliedMessage !== undefined) {
|
|
75
76
|
wakeMessage = validatePendingSteer(suppliedMessage);
|
|
76
77
|
}
|
|
77
|
-
else if (
|
|
78
|
+
else if (parkedSteers.length === 0) {
|
|
78
79
|
throw new CheckpointError("wake.nothing_to_deliver", "cannot wake: no message was supplied and the checkpoint holds no parked pendingSteer — an empty " +
|
|
79
80
|
"wake would burn the checkpoint on a blank continuation; supply `message` or park a steer first");
|
|
80
81
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { CheckpointError, readPendingSteerQueue } from "../checkpoint-store.js";
|
|
2
2
|
import { GLOBAL_USAGE_KEY, resolveUsageWindows, usageRetryAfterMs } from "../usage-window-store.js";
|
|
3
3
|
import { placementValueOrAbsent } from "./checkpoint-scope.js";
|
|
4
|
+
import { assertNoRetiredRunnerDeps } from "./retired-runner-deps.js";
|
|
5
|
+
import { resolveMicroCompactKnob } from "./prepare-config-doors.js";
|
|
4
6
|
export function resumeInternalsAndConfig(input) {
|
|
5
7
|
const { cp, config, internals, outcomeGate, runner } = input;
|
|
6
8
|
let windowEntrance;
|
|
9
|
+
assertNoRetiredRunnerDeps(runner.deps);
|
|
10
|
+
resolveMicroCompactKnob(runner.deps.microCompact);
|
|
7
11
|
if (runner.deps.lockedConfig?.keys?.includes("toolPolicy") === true && config.basePolicyForResumeEdit !== undefined) {
|
|
8
12
|
throw new CheckpointError("checkpoint.invalid_outcome", "TaskSpec.basePolicyForResumeEdit is administratively locked by this deployment (locked key \"toolPolicy\") — a task-supplied " +
|
|
9
13
|
"resume-edit policy is refused pre-CAS (the checkpoint stays pending); remove the field or change the deployment's lock configuration");
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { assertNoRetiredKeys } from "../retired-keys.js";
|
|
2
|
+
const RETIRED_RUNNER_DEPS_KEYS = {
|
|
3
|
+
legacyRewindBoundaryProbe: "the rewind refusal always names both possibilities (never existed / retired whole-tree era); a deployment that holds that era's table answers the question on its own surface",
|
|
4
|
+
};
|
|
5
|
+
export function assertNoRetiredRunnerDeps(deps) {
|
|
6
|
+
assertNoRetiredKeys(deps, RETIRED_RUNNER_DEPS_KEYS, "RunnerDeps");
|
|
7
|
+
}
|
|
@@ -286,9 +286,11 @@ export function createHarnessHandlers(input) {
|
|
|
286
286
|
if (prepared.abortController.signal.aborted)
|
|
287
287
|
prepared.workCutRef.abortedBeforeTurnEnd = true;
|
|
288
288
|
const stopExtra = rs.turn.turnStopReason !== undefined ? { stopReason: rs.turn.turnStopReason } : {};
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
const usage = rs.turn.turnUsage ?? { inputTokens: 0, totalInputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0, costMicroUsd: 0 };
|
|
290
|
+
const turnUsageUnknown = rs.turn.turnUsage === undefined || rs.turn.turnUsageMissing;
|
|
291
|
+
if (turnUsageUnknown)
|
|
292
|
+
stats.usageMissing = true;
|
|
293
|
+
queue.push({ type: "turn_end", usage, ...(turnUsageUnknown ? { usageMissing: true } : {}), ...stopExtra, ...ident() });
|
|
292
294
|
rs.turn.turnUsageMissing = false;
|
|
293
295
|
rs.turn.turnStopReason = undefined;
|
|
294
296
|
if (parentToolCallId !== undefined) {
|
|
@@ -51,7 +51,7 @@ export interface RunSettleAndTeardownInput {
|
|
|
51
51
|
parentToolCallId: string | undefined;
|
|
52
52
|
/** borrowed-readonly — the sub-agent display name for the terminal tick. */
|
|
53
53
|
subagentName: string | undefined;
|
|
54
|
-
/** borrowed-readonly — the loop-liveness latch: `userHalted`
|
|
54
|
+
/** borrowed-readonly — the loop-liveness latch: `userHalted` = the halt verb was ACCEPTED (the unconsumed-halt notice's input; it does not sign the seat). */
|
|
55
55
|
loopLatch: {
|
|
56
56
|
readonly userHalted: boolean;
|
|
57
57
|
};
|
|
@@ -11,6 +11,7 @@ import { defaultTaskRegistry } from "../task-registry.js";
|
|
|
11
11
|
import { emitTrace } from "../trace.js";
|
|
12
12
|
import { deliverEngineNotice } from "../types.js";
|
|
13
13
|
import { assembleResult } from "./assemble-result.js";
|
|
14
|
+
import { discloseUnconsumedHalt } from "./halt-attribution.js";
|
|
14
15
|
import { TIMER_LATENESS_REPORT_MS } from "./clock-and-limits.js";
|
|
15
16
|
import { resumeDecisionWasNegative } from "./decide-continuation.js";
|
|
16
17
|
import { drainForwardedFramesBeforeDone, forwardsSubagentEvents } from "./prepare-run-refs.js";
|
|
@@ -102,7 +103,7 @@ export async function runSettleAndTeardown(input) {
|
|
|
102
103
|
rewindNotes: prepared.rewindNotes,
|
|
103
104
|
editedFiles: prepared.editedFilesSnapshot(),
|
|
104
105
|
haltedOnUserRejection: prepared.batchHaltRef.current !== undefined,
|
|
105
|
-
|
|
106
|
+
haltConsumption: prepared.harness.haltConsumption(),
|
|
106
107
|
strandedHumanAnswers,
|
|
107
108
|
remoteEnvFailures: prepared.remoteEnvFailures,
|
|
108
109
|
effectiveReadFace: prepared.effectiveReadFace,
|
|
@@ -136,6 +137,7 @@ export async function runSettleAndTeardown(input) {
|
|
|
136
137
|
},
|
|
137
138
|
});
|
|
138
139
|
}
|
|
140
|
+
discloseUnconsumedHalt({ accepted: loopLatch.userHalted, consumption: prepared.harness.haltConsumption(), onNotice: runner.deps.onNotice, sessionId: prepared.sessionId, runId: rs.telemetry.runId, taskId: spec.taskId });
|
|
139
141
|
if (resume !== undefined &&
|
|
140
142
|
resume.pendingActionStarted !== true &&
|
|
141
143
|
result.terminal.kind !== "completed" &&
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isAbsoluteForFamily, pathFamilyOf } from "../../tools/fs/safety.js";
|
|
2
2
|
import { applyRecordedEdit } from "../../tools/fs/fs-shared.js";
|
|
3
3
|
import { normalizeFileText } from "../../tools/fs/encoding.js";
|
|
4
4
|
import { isOffloadedDetailReplacement } from "../tool-result-store.js";
|
|
@@ -75,7 +75,7 @@ export function wholeFileRecordsFromTranscript(messages) {
|
|
|
75
75
|
if (typeof changed !== "string")
|
|
76
76
|
continue;
|
|
77
77
|
const replayed = replayedEditContent(rest);
|
|
78
|
-
if (replayed !== undefined &&
|
|
78
|
+
if (replayed !== undefined && isAbsoluteForFamily(pathFamilyOf({ root: changed }), changed)) {
|
|
79
79
|
byPath.set(changed, { path: changed, content: replayed, at: m.timestamp });
|
|
80
80
|
}
|
|
81
81
|
else {
|
|
@@ -97,7 +97,7 @@ export function wholeFileRecordsFromTranscript(messages) {
|
|
|
97
97
|
const nested = rest.file;
|
|
98
98
|
const holder = isRead ? (typeof nested === "object" && nested !== null ? nested : undefined) : rest;
|
|
99
99
|
const filePath = holder?.filePath;
|
|
100
|
-
if (typeof filePath !== "string" || !
|
|
100
|
+
if (typeof filePath !== "string" || !isAbsoluteForFamily(pathFamilyOf({ root: filePath }), filePath))
|
|
101
101
|
continue;
|
|
102
102
|
const content = isRead ? wholeFileFromReadCard(rest) : typeof rest.content === "string" ? rest.content : undefined;
|
|
103
103
|
if (content === undefined)
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { canonicalizeTarget, writeTargetPath } from "../../tools/fs/safety.js";
|
|
2
|
-
import { isWinFormPath } from "../../tools/fs/safety.js";
|
|
1
|
+
import { canonicalizeTarget, isWinFormPath, pathFamilyOf, writeTargetPath } from "../../tools/fs/safety.js";
|
|
3
2
|
import { createCoarseCommandNamePolicy, namespacedCoveringEntries, namespacedCoveringHit } from "../tool-policy.js";
|
|
4
3
|
import { declaredPathTargetOf, isProtectedWrite, pathConfinableWriteToolNames, skillScopeWriteToolNames } from "../tool-registry.js";
|
|
5
4
|
import { pathTargetBaseOf } from "../effective-path-target.js";
|
|
@@ -66,13 +65,13 @@ export function createSessionRulePolicy(rules, opts) {
|
|
|
66
65
|
if (typeof path !== "string" || path.length === 0) {
|
|
67
66
|
return deny(`write tool "${req.toolName}" denied: session rule confines writes to allowDirs but the call has no resolvable path`);
|
|
68
67
|
}
|
|
69
|
-
const canon = await canonicalizeTarget(env, path, signal, pathTargetBaseOf(declared, { root: rootPath, cwd: req.cwd }));
|
|
68
|
+
const canon = await canonicalizeTarget(env, path, signal, pathFamilyOf({ root: rootPath, cwd: req.cwd ?? env.cwd }), pathTargetBaseOf(declared, { root: rootPath, cwd: req.cwd }));
|
|
70
69
|
if (!canon.ok) {
|
|
71
70
|
return deny(`write to "${path}" denied: its real target could not be resolved against the session-rule allowDirs`);
|
|
72
71
|
}
|
|
73
72
|
const roots = [];
|
|
74
73
|
for (const raw of allowDirs) {
|
|
75
|
-
const r = await canonicalizeTarget(env, raw, signal, rootPath);
|
|
74
|
+
const r = await canonicalizeTarget(env, raw, signal, pathFamilyOf({ root: rootPath ?? env.cwd }), rootPath);
|
|
76
75
|
if (r.ok)
|
|
77
76
|
roots.push(r.key);
|
|
78
77
|
}
|