@sema-agent/core 7.13.0 → 7.15.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 +110 -0
- package/dist/agents/subagent.d.ts +4 -9
- package/dist/agents/subagent.js +16 -12
- package/dist/agents/teacher.js +1 -1
- package/dist/brain/reasoning.d.ts +23 -0
- package/dist/brain/reasoning.js +35 -4
- package/dist/brain/stream-engine.js +35 -17
- package/dist/brain/timeout.d.ts +25 -4
- package/dist/brain/timeout.js +1 -1
- package/dist/core/ask-origin.d.ts +30 -11
- package/dist/core/ask-origin.js +10 -5
- package/dist/core/auto-mode.d.ts +3 -3
- package/dist/core/checkpoint-seat.d.ts +18 -0
- package/dist/core/checkpoint-seat.js +6 -0
- package/dist/core/checkpoint-store.d.ts +23 -31
- package/dist/core/checkpoint-store.js +7 -4
- package/dist/core/engine-notice.d.ts +3 -1
- package/dist/core/env-knob-announce.d.ts +16 -0
- package/dist/core/env-knob-announce.js +14 -0
- package/dist/core/gate-fold.js +2 -0
- package/dist/core/gate-lanes.js +21 -12
- package/dist/core/gate-outcome.d.ts +42 -3
- package/dist/core/gate-outcome.js +22 -0
- package/dist/core/governance-codes.js +1 -1
- package/dist/core/hooks.d.ts +9 -19
- package/dist/core/hooks.js +6 -4
- package/dist/core/mcp.d.ts +3 -2
- package/dist/core/mcp.js +5 -11
- package/dist/core/memory-engine/engine.d.ts +2 -2
- package/dist/core/runner/advertised-writable-dirs.d.ts +74 -0
- package/dist/core/runner/advertised-writable-dirs.js +48 -0
- package/dist/core/runner/assemble-result.d.ts +5 -0
- package/dist/core/runner/contracts.d.ts +2 -2
- package/dist/core/runner/denial-limit-arms.d.ts +7 -9
- package/dist/core/runner/denial-limit-arms.js +8 -10
- package/dist/core/runner/gate-exit.d.ts +15 -3
- package/dist/core/runner/gate-exit.js +6 -4
- package/dist/core/runner/permission-rule-lanes.d.ts +3 -1
- package/dist/core/runner/permission-rule-lanes.js +1 -1
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +34 -4
- package/dist/core/runner/prepare-caps-and-workflow.js +47 -12
- package/dist/core/runner/prepare-defer-classify.d.ts +1 -1
- package/dist/core/runner/prepare-defer-classify.js +12 -10
- package/dist/core/runner/prepare-gate-stations.d.ts +4 -5
- package/dist/core/runner/prepare-gate-stations.js +2 -2
- package/dist/core/runner/prepare-hands-readface.d.ts +18 -12
- package/dist/core/runner/prepare-hands-readface.js +32 -43
- package/dist/core/runner/prepare-inherited-gate.d.ts +7 -5
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-memory.d.ts +31 -34
- package/dist/core/runner/prepare-memory.js +73 -51
- package/dist/core/runner/prepare-park-ask.d.ts +5 -6
- package/dist/core/runner/prepare-park-ask.js +3 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +2 -2
- package/dist/core/runner/prepare-policy-chain.js +7 -4
- package/dist/core/runner/prepare-prompt-inputs.d.ts +4 -0
- package/dist/core/runner/prepare-prompt-inputs.js +2 -2
- package/dist/core/runner/prepare-question-face.d.ts +10 -8
- package/dist/core/runner/prepare-question-face.js +1 -3
- package/dist/core/runner/prepare-safety-scan.js +1 -1
- package/dist/core/runner/prepare-task.js +60 -53
- package/dist/core/runner/prepare-wiring-manifest.d.ts +2 -2
- package/dist/core/runner/prepare-wiring-manifest.js +1 -1
- package/dist/core/runner/run-compaction-machinery.js +2 -0
- package/dist/core/runner/run-harness-handlers.js +3 -1
- package/dist/core/runner/stream-settle-backstop.js +1 -1
- package/dist/core/runner/tool-defer-gate.d.ts +86 -0
- package/dist/core/runner/tool-defer-gate.js +57 -0
- package/dist/core/runner/tool-disclosure.d.ts +0 -36
- package/dist/core/runner/tool-disclosure.js +0 -43
- package/dist/core/runner-deps.d.ts +16 -9
- package/dist/core/runtime-caps.d.ts +21 -0
- package/dist/core/runtime-caps.js +5 -1
- package/dist/core/task-event.d.ts +11 -2
- package/dist/core/task-registry-shared.js +8 -6
- package/dist/core/task-result.d.ts +15 -0
- package/dist/core/task-spec.d.ts +8 -2
- package/dist/core/terminal-cause.d.ts +6 -2
- package/dist/core/tool-policy.d.ts +34 -28
- package/dist/core/tool-policy.js +29 -5
- package/dist/core/tool-roster.js +2 -0
- package/dist/core/tool-spec.d.ts +20 -16
- package/dist/core/types.d.ts +3 -2
- package/dist/core/types.js +1 -0
- package/dist/core/wiring-manifest.d.ts +16 -9
- package/dist/core/wiring-manifest.js +8 -3
- package/dist/index.d.ts +7 -6
- package/dist/index.js +5 -4
- package/dist/orchestration/run-workflow-tool.d.ts +8 -8
- package/dist/orchestration/run-workflow-tool.js +1 -1
- package/dist/orchestration/workflow-primitives.d.ts +4 -3
- package/dist/orchestration/workflow-primitives.js +3 -3
- package/dist/orchestration/workflow-types.d.ts +14 -0
- package/dist/orchestration/workflow.d.ts +41 -4
- package/dist/orchestration/workflow.js +23 -5
- package/dist/tools/fs/fs-bash.d.ts +41 -0
- package/dist/tools/fs/fs-bash.js +86 -29
- package/dist/tools/fs/fs-shared.js +9 -3
- package/dist/tools/fs/read-deny.d.ts +24 -8
- package/dist/tools/fs/read-deny.js +20 -1
- package/package.json +2 -1
- package/test/export-surface.snapshot.json +29 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE, classifierUnavailableDenyMessage, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow } from "../auto-mode.js";
|
|
2
2
|
import { sanitizeAutoModeArmingRecipe, tightenDenialLimit } from "../auto-mode-arming.js";
|
|
3
|
+
import { attestClassifierDenyCause } from "../tool-policy.js";
|
|
3
4
|
import { deliverEngineNotice } from "../types.js";
|
|
4
5
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
5
6
|
import { askOriginOf, classifierMayAnswer, probeMandatedAsk } from "../ask-origin.js";
|
|
@@ -62,15 +63,14 @@ function fallbackCarry(fallback, liveApprover, tracker) {
|
|
|
62
63
|
export function gateAskCarry(decision, liveApprover, tracker) {
|
|
63
64
|
return {
|
|
64
65
|
...(decision.origin !== undefined ? { origin: decision.origin } : {}),
|
|
66
|
+
...(decision.ruleStoreUnreadable !== undefined ? { ruleStoreUnreadable: decision.ruleStoreUnreadable } : {}),
|
|
65
67
|
...fallbackCarry(decision.denialLimitFallback, liveApprover, tracker),
|
|
66
|
-
...(decision.classifierUnavailable !== undefined ? { classifierUnavailable: { cause: decision.classifierUnavailable.cause } } : {}),
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
export function inheritedAskCarry(judged, liveApprover, tracker) {
|
|
70
71
|
return {
|
|
71
72
|
origin: judged.origin,
|
|
72
73
|
...fallbackCarry(judged.fallback, liveApprover, tracker),
|
|
73
|
-
...(judged.ask.classifierUnavailable !== undefined ? { classifierUnavailable: { cause: judged.ask.classifierUnavailable.cause } } : {}),
|
|
74
74
|
};
|
|
75
75
|
}
|
|
76
76
|
export async function judgeInheritedClassifier(opts) {
|
|
@@ -89,21 +89,19 @@ export async function judgeInheritedClassifier(opts) {
|
|
|
89
89
|
if (verdict.kind === "unavailable") {
|
|
90
90
|
return {
|
|
91
91
|
kind: "deny",
|
|
92
|
-
result: { action: "deny", message: classifierUnavailableDenyMessage(req.toolName, verdict.cause), decisionReason: "classifier"
|
|
92
|
+
result: attestClassifierDenyCause({ action: "deny", message: classifierUnavailableDenyMessage(req.toolName, verdict.cause), decisionReason: "classifier" }, "unavailable", req),
|
|
93
93
|
};
|
|
94
94
|
}
|
|
95
95
|
const reason = verdict.kind === "block" ? (verdict.reason ? inlineUntrusted(verdict.reason) : "") : CLASSIFIER_PARSE_FAILURE_DENY_MESSAGE;
|
|
96
96
|
const category = verdict.kind === "block" && verdict.category ? inlineUntrusted(verdict.category) : "";
|
|
97
97
|
const tracked = autoMode.denialTracking?.recordBlock();
|
|
98
98
|
if (tracked?.limitReached !== true) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
message: verdict.kind === "block" ? `auto-mode classifier blocked ${opts.subject} at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : `${reason} (${opts.subject}, at an inherited ancestor layer)`,
|
|
104
|
-
decisionReason: "classifier",
|
|
105
|
-
},
|
|
99
|
+
const denied = {
|
|
100
|
+
action: "deny",
|
|
101
|
+
message: verdict.kind === "block" ? `auto-mode classifier blocked ${opts.subject} at an inherited ancestor layer${reason ? `: ${reason}` : category ? `: [${category}]` : ""}` : `${reason} (${opts.subject}, at an inherited ancestor layer)`,
|
|
102
|
+
decisionReason: "classifier",
|
|
106
103
|
};
|
|
104
|
+
return { kind: "deny", result: verdict.kind === "parse_error" ? attestClassifierDenyCause(denied, "parse_error", req) : denied };
|
|
107
105
|
}
|
|
108
106
|
const fallback = tracked.fallback;
|
|
109
107
|
const minted = { ...ask, message: denialLimitFallbackMessage(fallback, reason || category || req.toolName), decisionReason: "classifier", requiresRealApproval: true, denialLimitFallback: fallback };
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* the reminder envelope and the text helpers. Its `import type` edges up to `hooks.ts` name the gate's public
|
|
22
22
|
* contract (`ToolGateInput`, `ToolGateResult`, the observer payload), which stays declared there.
|
|
23
23
|
*/
|
|
24
|
-
import { type DeniedBy, type GateOutcome, type Settlement } from "../gate-outcome.js";
|
|
24
|
+
import { type ClassifierDenyCause, type DeniedBy, type GateOutcome, type Settlement } from "../gate-outcome.js";
|
|
25
25
|
import type { AskOrigin, AskOriginFacts } from "../ask-origin.js";
|
|
26
26
|
import { type PermissionResult, type ResolvedAsk, type ToolCallRequest } from "../tool-policy.js";
|
|
27
27
|
import type { SafeNotifier } from "../safe-notify.js";
|
|
@@ -32,10 +32,13 @@ export interface SettledAsk {
|
|
|
32
32
|
settlement: Settlement;
|
|
33
33
|
origin: AskOrigin;
|
|
34
34
|
}
|
|
35
|
-
/** The facts a gate pass hands the mint. `deniedBy` is present exactly when the pass refused; `
|
|
36
|
-
*
|
|
35
|
+
/** The facts a gate pass hands the mint. `deniedBy` is present exactly when the pass refused; `cause` only
|
|
36
|
+
* beside it, when the refusing round was a classifier round that did not rule (the station's attestation,
|
|
37
|
+
* read once by the fold or the classifier step); `settled` exactly when the pass consumed an ask's
|
|
38
|
+
* settlement (a person's yes that was later vetoed included). */
|
|
37
39
|
export interface GateExitFacts {
|
|
38
40
|
deniedBy?: DeniedBy;
|
|
41
|
+
cause?: ClassifierDenyCause;
|
|
39
42
|
settled?: SettledAsk;
|
|
40
43
|
}
|
|
41
44
|
/**
|
|
@@ -80,6 +83,10 @@ export interface SettlementLedger {
|
|
|
80
83
|
* for an attested refusal, `policy` otherwise — a veto when a yes rides the settlement); undefined
|
|
81
84
|
* for an allow or an ask. */
|
|
82
85
|
fromDecision(decision: PermissionResult): DeniedBy | undefined;
|
|
86
|
+
/** Read a deny's attested classifier CAUSE for this call (an inherited station's `unavailable` /
|
|
87
|
+
* `parse_error` round travelling through an ancestor wrapper into this fold); undefined for a ruling
|
|
88
|
+
* block, a non-classifier deny, an allow or an ask. */
|
|
89
|
+
causeOf(decision: PermissionResult): ClassifierDenyCause | undefined;
|
|
83
90
|
/** A surviving ask supersedes whatever an earlier decision settled. */
|
|
84
91
|
supersede(): void;
|
|
85
92
|
}
|
|
@@ -208,6 +215,11 @@ export interface GatePass {
|
|
|
208
215
|
* that ended as a refusal). The exit mints the outcome from it beside the ledger's `settled`; a refusal
|
|
209
216
|
* that reaches the exit without it is an engine defect and the mint throws. */
|
|
210
217
|
deniedBy: DeniedBy | undefined;
|
|
218
|
+
/** borrowed-mutable — the FORM of the classifier round behind a deny (`unavailable` / `parse_error`), written
|
|
219
|
+
* beside `deniedBy` by the gate's own classifier step (its attestation, read once) or by the fold / the
|
|
220
|
+
* re-check when an inherited station's attested deny arrives through the chain; undefined for a ruling
|
|
221
|
+
* block and every non-classifier deny. The exit mints `GateDisposition.cause` from it. */
|
|
222
|
+
denyCause: ClassifierDenyCause | undefined;
|
|
211
223
|
/** borrowed-mutable — the standing verdict. The no-policy default until the adjudication station writes the
|
|
212
224
|
* policy's answer; then rewritten by every station that changes the verdict (fold, tightens, org, rule
|
|
213
225
|
* lane, stamp, classifier, sandbox, content lane, resolution, edit chain). */
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { screenGateOutcome, SETTLEMENT_IS_REFUSAL } from "../gate-outcome.js";
|
|
2
|
-
import { decisionText, engineSettlementOf } from "../tool-policy.js";
|
|
2
|
+
import { classifierDenyCauseOf, decisionText, engineSettlementOf } from "../tool-policy.js";
|
|
3
3
|
import { inlineUntrusted } from "../untrusted-text.js";
|
|
4
4
|
import { formatHookFeedback } from "../reminder-mint.js";
|
|
5
5
|
export function mintGateOutcome(facts) {
|
|
6
6
|
const settlement = facts.settled !== undefined ? Object.freeze({ ...facts.settled.settlement, who: Object.freeze({ ...facts.settled.settlement.who }) }) : undefined;
|
|
7
7
|
const outcome = Object.freeze({
|
|
8
|
-
disposition: Object.freeze(facts.deniedBy !== undefined ? { kind: "denied", deniedBy: facts.deniedBy } : { kind: "allowed" }),
|
|
8
|
+
disposition: Object.freeze(facts.deniedBy !== undefined ? { kind: "denied", deniedBy: facts.deniedBy, ...(facts.cause !== undefined ? { cause: facts.cause } : {}) } : { kind: "allowed" }),
|
|
9
9
|
...(facts.settled !== undefined ? { settlement: settlement, origin: facts.settled.origin } : {}),
|
|
10
10
|
});
|
|
11
11
|
const defects = screenGateOutcome(outcome);
|
|
@@ -50,6 +50,9 @@ export function createSettlementLedger(call) {
|
|
|
50
50
|
return undefined;
|
|
51
51
|
return attested !== undefined && SETTLEMENT_IS_REFUSAL[attested.settlement.kind] ? "ask_resolution" : "policy";
|
|
52
52
|
},
|
|
53
|
+
causeOf(decision) {
|
|
54
|
+
return decision.action === "deny" ? classifierDenyCauseOf(decision, call) : undefined;
|
|
55
|
+
},
|
|
53
56
|
supersede() {
|
|
54
57
|
settled = undefined;
|
|
55
58
|
},
|
|
@@ -102,7 +105,7 @@ export async function exitGate(pass) {
|
|
|
102
105
|
}
|
|
103
106
|
if (pass.deniedBy === undefined)
|
|
104
107
|
throw new Error(`the tool gate refused "${toolName}" without a refusing layer — every deny site attributes itself`);
|
|
105
|
-
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}) });
|
|
108
|
+
const gate = mintGateOutcome({ deniedBy: pass.deniedBy, ...(pass.denyCause !== undefined ? { cause: pass.denyCause } : {}), ...(ledger.settled !== undefined ? { settled: ledger.settled } : {}) });
|
|
106
109
|
await notifyPermissionDenied({
|
|
107
110
|
toolName,
|
|
108
111
|
input: cloneObserverInput(pass.currentInput),
|
|
@@ -110,7 +113,6 @@ export async function exitGate(pass) {
|
|
|
110
113
|
reason: denyReason,
|
|
111
114
|
gate,
|
|
112
115
|
...(input.identity !== undefined ? { identity: input.identity } : {}),
|
|
113
|
-
...(pass.decision.action === "deny" && pass.decision.classifierUnavailable !== undefined ? { classifierUnavailable: { cause: pass.decision.classifierUnavailable.cause } } : {}),
|
|
114
116
|
});
|
|
115
117
|
return {
|
|
116
118
|
block: true,
|
|
@@ -245,7 +245,9 @@ export declare function createRuleOffersOf(cfg: {
|
|
|
245
245
|
irreversibilityTier: {
|
|
246
246
|
get(name: string): Parameters<typeof persistedRuleMandateOf>[0]["irreversibility"];
|
|
247
247
|
};
|
|
248
|
-
|
|
248
|
+
shellGatedTools: {
|
|
249
|
+
has(name: string): boolean;
|
|
250
|
+
};
|
|
249
251
|
taskRoot: string | undefined;
|
|
250
252
|
/** The live tracked-cwd ref (read per call — the relative-cd resolution base, adversarial-review P1/r3). */
|
|
251
253
|
cwdRef: {
|
|
@@ -176,7 +176,7 @@ export function createRuleOffersOf(cfg) {
|
|
|
176
176
|
if (persistedRuleMandateOf({
|
|
177
177
|
egress: cfg.egressTools.has(toolName),
|
|
178
178
|
irreversibility: cfg.irreversibilityTier.get(toolName),
|
|
179
|
-
shellGated: cfg.
|
|
179
|
+
shellGated: cfg.shellGatedTools.has(toolName),
|
|
180
180
|
probeMandated: ask?.probeMandated === true,
|
|
181
181
|
}) !== undefined) {
|
|
182
182
|
return { ruleOffersAbsence: "mandated" };
|
|
@@ -25,28 +25,33 @@ import type { PromptEpochArtifact } from "../../prompt-assembly/artifact.js";
|
|
|
25
25
|
import { type WorkflowSizeGuideline } from "../../orchestration/workflow-size-guideline.js";
|
|
26
26
|
import { type AutoModeArmingRecipe } from "../auto-mode-arming.js";
|
|
27
27
|
import { type AutoModeDecider, type AutoModeDenialTracker } from "../auto-mode.js";
|
|
28
|
+
import { type CheckpointSeat } from "../checkpoint-seat.js";
|
|
28
29
|
import { type ComplianceCapability } from "../compliance.js";
|
|
29
30
|
import type { LockedPreflight } from "../locked-config.js";
|
|
30
31
|
import type { StoredSession } from "../session.js";
|
|
31
32
|
import type { OnAsk } from "../tool-policy.js";
|
|
32
33
|
import type { RunnerDeps, RuntimeCaps, TaskEvent, TaskSpec, ToolExecuteContext } from "../types.js";
|
|
33
|
-
import type {
|
|
34
|
+
import type { AutoModeArmFact } from "../wiring-manifest.js";
|
|
35
|
+
import type { AssertAllKeysHandled } from "../ask-origin.js";
|
|
34
36
|
import type { ReadFace } from "../../tools/fs/index.js";
|
|
35
37
|
import type { InheritedGate, Prepared, RunInternals, RunnerSelfSeat, ToolFaceSnapshot } from "./contracts.js";
|
|
36
38
|
import { type BlockedRef } from "./synthetic-tools.js";
|
|
37
39
|
import { RosterBuilder } from "../tool-roster.js";
|
|
38
40
|
export interface PrepareCapsAndWorkflowInput {
|
|
39
41
|
/** borrowed-readonly — the REBOUND spec, whole: the roster map reads `tools`; the mounts read `enableBlockedReport`,
|
|
40
|
-
* `enablePlanMode`, `interactiveTools
|
|
42
|
+
* `enablePlanMode`, `interactiveTools`; the caps/compliance stations read `principal`, `selfOrchestration`,
|
|
41
43
|
* `enableFork`, `getApiKeyAndHeaders`; the Workflow mount forwards `oneShot`, `handsReadOnly`, `interactiveTools`. The
|
|
42
44
|
* self-orchestration predicate takes the whole spec. Never mutated. */
|
|
43
45
|
spec: TaskSpec;
|
|
44
46
|
/** borrowed-readonly — the deployment seats, whole: `runtimeCapsResolver`, `compliancePostureResolver`, `onError`, `onNotice`,
|
|
45
|
-
* `autoMode`, `brain`, `models`,
|
|
47
|
+
* `autoMode`, `brain`, `models`, and the Workflow mount's dozen deps (`workflowScriptRunner`,
|
|
46
48
|
* `workflowGovernanceBaseline`, `workflowRunStore`, `workflowJournalStore`, `workflowScriptStore`, `builtinWorkflows`,
|
|
47
49
|
* `onWorkflowAgentSpawn`, `workflowCompletionNotifier`, `workflowLimits`, `agents`, `builtinAgents`, `onBackgroundChildEvent`).
|
|
48
50
|
* The self-orchestration predicate takes the whole record. */
|
|
49
51
|
deps: RunnerDeps;
|
|
52
|
+
/** borrowed-readonly — the seat this run hands its children (`checkpointSeatOf`, minted once by the driver right after the
|
|
53
|
+
* config doors): the plan-pair face reads the store it names, the Workflow mount hands the seat itself to its children. */
|
|
54
|
+
checkpointSeat: CheckpointSeat | undefined;
|
|
50
55
|
/** borrowed-readonly — the trusted spawn-side channel; the Workflow mount forwards `rootSessionId`, `placementRoot`,
|
|
51
56
|
* `onTaskNotification`, `workflowDepth`, and the capture-floor getter reads `memoryCaptureAncestors`. */
|
|
52
57
|
internals: Pick<RunInternals, "rootSessionId" | "placementRoot" | "onTaskNotification" | "workflowDepth" | "memoryCaptureAncestors" | "workflowParkedResume"> | undefined;
|
|
@@ -145,7 +150,8 @@ export interface PrepareCapsAndWorkflowResult {
|
|
|
145
150
|
/** owned — the observers grant (`allowObservers === true`, explicit opt-in). */
|
|
146
151
|
observersActive: boolean;
|
|
147
152
|
/** owned — the arming outcome as a closed reason (the manifest's auto-mode face). */
|
|
148
|
-
|
|
153
|
+
/** #529 / #692 C-d — the leg's auto-mode arming fact (`armed` ⇔ `reason === "armed"`; `deniedSource` only beside a STATED `denied`). */
|
|
154
|
+
autoModeArmReason: AutoModeArmFact;
|
|
149
155
|
/** owned — the armed classifier, or undefined when any arming arm failed. */
|
|
150
156
|
autoModeDecider: AutoModeDecider | undefined;
|
|
151
157
|
/** owned — the denial tracker built beside the decider (same face, same arming). */
|
|
@@ -162,5 +168,29 @@ export interface PrepareCapsAndWorkflowResult {
|
|
|
162
168
|
current: () => WorkflowSizeGuideline;
|
|
163
169
|
} | undefined;
|
|
164
170
|
}
|
|
171
|
+
/**
|
|
172
|
+
* The resolved-caps value screen (the caps-side twin of `refuseInvalidAutoModeSeat`): the arming arm reads
|
|
173
|
+
* `autoMode !== false`, so a resolver that returns a MARSHALLED value — a non-boolean member (`"false"`,
|
|
174
|
+
* `0`, `null`) or a non-record container (`false`, `"false"`, `[]`; the resolver is an HTTP-backed seam the
|
|
175
|
+
* type system does not validate at runtime) — would pass a value meant as a denial straight into arming.
|
|
176
|
+
* Either shape is treated as a disclosed resolver fault: announced through onError (phase config), and
|
|
177
|
+
* coined fail-closed — a bad MEMBER to `autoMode:false` (the rest of the record kept), a bad CONTAINER to
|
|
178
|
+
* the same degrade object the resolver-throw arm uses (every `!== false`-gated cap denied), with
|
|
179
|
+
* `faulted` raised so the posture-keyed consumers read it as an outage, not as a verdict. `undefined`, or
|
|
180
|
+
* a record whose `autoMode` is `undefined`/`true`/`false`, passes untouched (byte-identical).
|
|
181
|
+
*/
|
|
182
|
+
/** The supported capability keys, fenced total over {@link RuntimeCaps}: a key added to the type without a row here
|
|
183
|
+
* is a red build, so the snapshot below can never silently drop a new restriction. */
|
|
184
|
+
declare const RUNTIME_CAP_KEYS: {
|
|
185
|
+
readonly allowWorkflows: true;
|
|
186
|
+
readonly allowFork: true;
|
|
187
|
+
readonly allowObservers: true;
|
|
188
|
+
readonly forceDurableGate: true;
|
|
189
|
+
readonly autoMode: true;
|
|
190
|
+
readonly autoModeDenySource: true;
|
|
191
|
+
readonly allowMemoryOptOut: true;
|
|
192
|
+
};
|
|
193
|
+
export type RuntimeCapKeysCoverEveryCap = AssertAllKeysHandled<Exclude<keyof RuntimeCaps, keyof typeof RUNTIME_CAP_KEYS>>;
|
|
165
194
|
/** The M4 phase body — prepareTask's caps-and-workflow stretch, verbatim (see the module header). */
|
|
166
195
|
export declare function prepareCapsAndWorkflow(input: PrepareCapsAndWorkflowInput): Promise<PrepareCapsAndWorkflowResult>;
|
|
196
|
+
export {};
|
|
@@ -10,7 +10,7 @@ import { autoModeArmingRecipeOf } from "../auto-mode-arming.js";
|
|
|
10
10
|
import { AUTO_MODE_CLASSIFIER_LOW_REASONING_BUDGET_TOKENS, AUTO_MODE_CLASSIFIER_MAX_TOKENS } from "../auto-mode-defaults.js";
|
|
11
11
|
import { buildAutoModePrompt, renderAutoModeAction, renderAutoModeWindow } from "../auto-mode-prompt.js";
|
|
12
12
|
import { createAutoModeDecider, createAutoModeDenialTracker } from "../auto-mode.js";
|
|
13
|
-
import {
|
|
13
|
+
import { checkpointStoreOfSeat } from "../checkpoint-seat.js";
|
|
14
14
|
import { COMPLIANCE_CAPABILITIES, WEB_FETCH_TOOL_NAME, resolveComplianceDenies } from "../compliance.js";
|
|
15
15
|
import { createPresentPlanTool, createEnterPlanModeTool } from "../present-plan-tool.js";
|
|
16
16
|
import { resolveTaskModel } from "../roles.js";
|
|
@@ -19,6 +19,7 @@ import { defaultTaskRegistry } from "../task-registry.js";
|
|
|
19
19
|
import { emitTrace } from "../trace.js";
|
|
20
20
|
import { defineTool, isDefineToolProduct, rebindDefineToolCtx } from "../tools.js";
|
|
21
21
|
const MOUNT_REMEDY = "author it as a plain-object ToolSpec (own `name` and `execute`), hand the defineTool product itself, or wrap a product through the supported wrapper form (a fresh object re-stamped with `stampDefineToolBrand` whose rebind re-wraps the rebound product)";
|
|
22
|
+
import { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "../runtime-caps.js";
|
|
22
23
|
import { derivedRouteFallsBack } from "./derived-route-fallback.js";
|
|
23
24
|
import { REPORT_FINDINGS_TOOL_NAME, createReportBlockedTool, createReportFindingsTool } from "./synthetic-tools.js";
|
|
24
25
|
function classifierReplyText(reply) {
|
|
@@ -42,6 +43,24 @@ function assembleParentCaptureState(o, i, ctl, ancestors) {
|
|
|
42
43
|
});
|
|
43
44
|
return o instanceof Promise || i instanceof Promise ? Promise.all([o, i]).then(([ov, iv]) => build(ov, iv)) : build(o, i);
|
|
44
45
|
}
|
|
46
|
+
const RUNTIME_CAP_KEYS = {
|
|
47
|
+
allowWorkflows: true,
|
|
48
|
+
allowFork: true,
|
|
49
|
+
allowObservers: true,
|
|
50
|
+
forceDurableGate: true,
|
|
51
|
+
autoMode: true,
|
|
52
|
+
autoModeDenySource: true,
|
|
53
|
+
allowMemoryOptOut: true,
|
|
54
|
+
};
|
|
55
|
+
function snapshotRuntimeCaps(record) {
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const key of Object.keys(RUNTIME_CAP_KEYS)) {
|
|
58
|
+
const v = record[key];
|
|
59
|
+
if (v !== undefined)
|
|
60
|
+
out[key] = v;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
45
64
|
function screenAutoModeCap(caps, onError, sessionId) {
|
|
46
65
|
if (caps === undefined)
|
|
47
66
|
return { caps, faulted: false };
|
|
@@ -49,7 +68,20 @@ function screenAutoModeCap(caps, onError, sessionId) {
|
|
|
49
68
|
onError?.(new Error(`runtimeCapsResolver returned a non-record value (${JSON.stringify(caps)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain). Return a RuntimeCaps object or undefined.`), { phase: "config", sessionId });
|
|
50
69
|
return { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, faulted: true };
|
|
51
70
|
}
|
|
52
|
-
|
|
71
|
+
let record;
|
|
72
|
+
try {
|
|
73
|
+
record = snapshotRuntimeCaps(caps);
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
onError?.(new Error(`runtimeCapsResolver's record threw while being read (${err instanceof Error ? err.message : String(err)}) — read as a resolver fault: every per-principal capability is DENIED for this run (auto mode is not armed; asks flow the original chain).`), { phase: "config", sessionId });
|
|
77
|
+
return { caps: { allowWorkflows: false, allowFork: false, autoMode: false }, faulted: true };
|
|
78
|
+
}
|
|
79
|
+
const { autoMode, autoModeDenySource } = record;
|
|
80
|
+
if (autoModeDenySource !== undefined && (!isAutoModeDenySource(autoModeDenySource) || autoMode !== false)) {
|
|
81
|
+
onError?.(new Error(`runtimeCapsResolver returned autoModeDenySource=${JSON.stringify(autoModeDenySource)} beside autoMode=${JSON.stringify(autoMode)} — read as a resolver fault: auto mode is DENIED for this run (the classifier is not armed; asks flow the original chain). Name a source only beside autoMode:false, and only one of ${AUTO_MODE_DENY_SOURCES.join("|")}.`), { phase: "config", sessionId });
|
|
82
|
+
const { autoModeDenySource: _refused, ...rest } = record;
|
|
83
|
+
return { caps: { ...rest, autoMode: false }, faulted: true };
|
|
84
|
+
}
|
|
53
85
|
if (record.autoMode === undefined || typeof record.autoMode === "boolean")
|
|
54
86
|
return { caps: record, faulted: false };
|
|
55
87
|
onError?.(new Error(`runtimeCapsResolver returned a non-boolean autoMode (${JSON.stringify(record.autoMode)}) — read as a resolver fault: auto mode is DENIED for this run (the classifier is not armed; asks flow the original chain). Return true, false, or omit the key.`), { phase: "config", sessionId });
|
|
@@ -67,17 +99,20 @@ function mintPersistedArming(am, laneRule, classifierSystemPrompt, onError, sess
|
|
|
67
99
|
}
|
|
68
100
|
return arming;
|
|
69
101
|
}
|
|
70
|
-
function autoModeArmReasonOf(intent, facePresent,
|
|
102
|
+
function autoModeArmReasonOf(intent, facePresent, caps, capsFaulted) {
|
|
71
103
|
if (!intent)
|
|
72
|
-
return "no_intent";
|
|
104
|
+
return { armed: false, reason: "no_intent" };
|
|
73
105
|
if (!facePresent)
|
|
74
|
-
return "no_face";
|
|
75
|
-
if (
|
|
76
|
-
|
|
77
|
-
|
|
106
|
+
return { armed: false, reason: "no_face" };
|
|
107
|
+
if (caps?.autoMode === false) {
|
|
108
|
+
if (capsFaulted)
|
|
109
|
+
return { armed: false, reason: "resolver_fault" };
|
|
110
|
+
return { armed: false, reason: "denied", ...(caps.autoModeDenySource !== undefined ? { deniedSource: caps.autoModeDenySource } : {}) };
|
|
111
|
+
}
|
|
112
|
+
return { armed: true, reason: "armed" };
|
|
78
113
|
}
|
|
79
114
|
export async function prepareCapsAndWorkflow(input) {
|
|
80
|
-
const { spec, deps, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
115
|
+
const { spec, deps, checkpointSeat, internals, session, sessionId, runId, hostTaskId, taskScope, taskRootFinal, model, thinking, lockedPreflight, toolEffects, toolFaceSnapshot, promptProfile, resolvedInteractionPosture, harnessRef, frozenOnAsk, carrierReadFace, forwardEvent, inheritedGateForChildren, enrichSpecToolCtx, maybeOffload, requestReview, enterPlanMode, autoModeIntent, peerLaneActive, peerSendMessageBuiltIn, runnerSelf } = input;
|
|
81
116
|
const roster = new RosterBuilder(toolEffects);
|
|
82
117
|
for (const t of spec.tools ?? []) {
|
|
83
118
|
const mounted = mountCallerTool(t);
|
|
@@ -112,7 +147,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
112
147
|
roster.mount(createReportFindingsTool(), { source: "builtin", mountedBy: "always" });
|
|
113
148
|
}
|
|
114
149
|
if (spec.enablePlanMode === true && spec.interactiveTools !== false) {
|
|
115
|
-
const planReviewFace =
|
|
150
|
+
const planReviewFace = checkpointStoreOfSeat(checkpointSeat) !== undefined;
|
|
116
151
|
if (spec.interactiveTools === true || planReviewFace) {
|
|
117
152
|
roster.mount(defineTool(createPresentPlanTool(requestReview)), { source: "builtin", mountedBy: "optional" });
|
|
118
153
|
if (planReviewFace) {
|
|
@@ -173,7 +208,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
173
208
|
let autoModeDecider;
|
|
174
209
|
let autoModeDenialTracking;
|
|
175
210
|
let autoModeArming;
|
|
176
|
-
const autoModeArmReason = autoModeArmReasonOf(autoModeIntent, deps.autoMode !== undefined, runtimeCaps
|
|
211
|
+
const autoModeArmReason = autoModeArmReasonOf(autoModeIntent, deps.autoMode !== undefined, runtimeCaps, runtimeCapsFaulted);
|
|
177
212
|
if (autoModeIntent && deps.autoMode !== undefined && runtimeCaps?.autoMode !== false) {
|
|
178
213
|
const am = deps.autoMode;
|
|
179
214
|
let classifierModel;
|
|
@@ -297,7 +332,7 @@ export async function prepareCapsAndWorkflow(input) {
|
|
|
297
332
|
},
|
|
298
333
|
...(spec.handsReadOnly === true ? { parentHandsReadOnly: true } : {}), ...(spec.interactiveTools === false ? { parentInteractiveTools: false } : {}),
|
|
299
334
|
onNotice: deps.onNotice,
|
|
300
|
-
|
|
335
|
+
...(checkpointSeat !== undefined ? { parentCheckpointStore: checkpointSeat } : {}),
|
|
301
336
|
parentCenterArtifactDigest: () => input.centerAdoption()?.artifact.artifactDigest,
|
|
302
337
|
parentCenterSourceRevision: () => input.centerAdoption()?.sourceRevision,
|
|
303
338
|
...(forwardEvent ? { forwardEvent } : {}),
|
|
@@ -28,7 +28,7 @@ export interface PrepareDeferClassifyInput {
|
|
|
28
28
|
fullShellReachable: boolean;
|
|
29
29
|
/** borrowed-readonly — the resolved prompt profile (`classic` swaps in `descriptionClassic`). */
|
|
30
30
|
promptProfile: "simple" | "classic";
|
|
31
|
-
/** borrowed-readonly — the resolved model (the
|
|
31
|
+
/** borrowed-readonly — the resolved model (the deferral gate's threshold reads its context window). */
|
|
32
32
|
model: Model;
|
|
33
33
|
/** borrowed-readonly — the materialized MCP roster; only `tools` is read (protocol names for the
|
|
34
34
|
* remote-roster arm; `mcpAlwaysLoad` self-declarations, losing to an explicit operator defer). */
|
|
@@ -3,10 +3,12 @@ import { FULL_SHELL_CONTRACT_ID } from "../../tools/fs/index.js";
|
|
|
3
3
|
import { ASK_USER_QUESTION_TOOL_NAME } from "../ask-question.js";
|
|
4
4
|
import { MEMORY_ENGINE_TOOL_NAMES } from "../memory-engine/tools.js";
|
|
5
5
|
import { SHARED_MEMORY_TOOL_NAMES } from "../shared-memory/types.js";
|
|
6
|
-
import {
|
|
6
|
+
import { protocolOf } from "../protocol-table.js";
|
|
7
|
+
import { classifyDeferred } from "./tool-defer-gate.js";
|
|
8
|
+
import { TOOL_SEARCH_NAME } from "./tool-disclosure.js";
|
|
7
9
|
import { RosterBuilder } from "../tool-roster.js";
|
|
8
|
-
function explicitlyDeferredMemoryTrio(mounted, roster,
|
|
9
|
-
return mounted ? MEMORY_ENGINE_TOOL_NAMES.filter((n) => roster.some((t) => t.name === n) && (
|
|
10
|
+
function explicitlyDeferredMemoryTrio(mounted, roster, callerDeferNames) {
|
|
11
|
+
return mounted ? MEMORY_ENGINE_TOOL_NAMES.filter((n) => roster.some((t) => t.name === n) && (callerDeferNames ?? []).includes(n)) : [];
|
|
10
12
|
}
|
|
11
13
|
function memoryGroupRetractionSet(builtinDeferPairNames, engineTrioInPlay) {
|
|
12
14
|
return new Set([...builtinDeferPairNames, ...(engineTrioInPlay ? MEMORY_ENGINE_TOOL_NAMES : [])]);
|
|
@@ -39,29 +41,29 @@ export function prepareDeferClassify(input) {
|
|
|
39
41
|
roster.replaceAt(i, { ...t, description: t.descriptionClassic });
|
|
40
42
|
}
|
|
41
43
|
}
|
|
42
|
-
const
|
|
43
|
-
const protocolToolNames = [...mcp.tools.map((t) => t.name), ...a2a.tools.map((t) => t.name)];
|
|
44
|
+
const protocolToolNames = [...mcp.tools, ...a2a.tools].filter((t) => protocolOf(t.name) !== undefined).map((t) => t.name);
|
|
44
45
|
const mcpAlwaysLoadNames = mcp.tools
|
|
45
46
|
.filter((t) => t.mcpAlwaysLoad === true && !(toolFaceSnapshot.defer ?? []).includes(t.name))
|
|
46
47
|
.map((t) => t.name);
|
|
47
48
|
const classifyDeferredOverFace = (face, builtinDeferNames) => {
|
|
49
|
+
const mounted = new Set(face.map((t) => t.name));
|
|
48
50
|
const deferredSet = classifyDeferred({
|
|
49
51
|
specs: spec.tools ?? [],
|
|
50
52
|
protocolToolNames,
|
|
51
|
-
fullTools: face
|
|
53
|
+
fullTools: face,
|
|
52
54
|
deferMode: deps.deferMode,
|
|
53
55
|
model,
|
|
54
|
-
|
|
56
|
+
callerDeferNames: (toolFaceSnapshot.defer ?? []).filter((n) => mounted.has(n)),
|
|
57
|
+
builtinDeferNames: builtinDeferNames.filter((n) => mounted.has(n)),
|
|
55
58
|
alwaysLoadNames: [
|
|
56
59
|
ASK_USER_QUESTION_TOOL_NAME,
|
|
57
60
|
...(toolFaceSnapshot.alwaysLoad ?? []),
|
|
58
61
|
...mcpAlwaysLoadNames,
|
|
59
62
|
],
|
|
60
63
|
});
|
|
61
|
-
for (const n of [...deferredSet])
|
|
62
|
-
if (!
|
|
64
|
+
for (const n of [...deferredSet])
|
|
65
|
+
if (!mounted.has(n))
|
|
63
66
|
deferredSet.delete(n);
|
|
64
|
-
}
|
|
65
67
|
return deferredSet;
|
|
66
68
|
};
|
|
67
69
|
const sharedMemoryPair = sharedMemoryPairMounted ? SHARED_MEMORY_TOOL_NAMES.filter((n) => tools.some((t) => t.name === n)) : [];
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* gate-machinery block, kept as the block's one guard here); the `tool_result` station keys off the hook record alone, as
|
|
20
20
|
* it always did.
|
|
21
21
|
*
|
|
22
|
-
* Every station this file holds is a `
|
|
22
|
+
* Every station this file holds is a `deniedBy` / settlement WRITE site the decomposition's next slice maps onto one
|
|
23
23
|
* gate outcome; nothing here changes a word, a source or an order — the stations are moved, not re-adjudicated.
|
|
24
24
|
*/
|
|
25
25
|
import type { AgentHarness, AgentTool } from "../../internal/harness.js";
|
|
@@ -130,10 +130,9 @@ export interface PrepareGateStationsInput {
|
|
|
130
130
|
abortController: {
|
|
131
131
|
readonly signal: AbortSignal;
|
|
132
132
|
};
|
|
133
|
-
/** borrowed-readonly —
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
shellGatedMonitor: boolean;
|
|
133
|
+
/** borrowed-readonly — the shell-seat provenance set: the shell-running tools whose tier is the engine's shell seat's, not a
|
|
134
|
+
* deployment mark (the gate's `shellGated` attribution is the gated tool's membership). */
|
|
135
|
+
shellGatedTools: ReadonlySet<string>;
|
|
137
136
|
/** borrowed-readonly — the auto-mode decider, or undefined (the classifier lane the gate routes a surviving ask through). */
|
|
138
137
|
autoModeDecider: AutoModeDecider | undefined;
|
|
139
138
|
/** borrowed-readonly — the auto-mode denial tracker, or undefined (handed to the gate beside the decider). */
|
|
@@ -42,7 +42,7 @@ function maybeHumanRejectionHalt(input) {
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
export function prepareGateStations(input) {
|
|
45
|
-
const { askLane, parkAsk, tools, toolRosterDeltas, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController,
|
|
45
|
+
const { askLane, parkAsk, tools, toolRosterDeltas, toolEffects, deps, toolCallGateArmedRef, effectivePolicy, hooks, egressTools, irreversibleTools, spec, complianceDenies, harness, blockedToolCalls, inheritedAskGrants, inheritedUnavailableAsks, foldAskClasses, ancestorSandboxAdmissions, preToolContexts, gateOutcomes, batchHaltRef, blockedTracked, hookIdentity, reminderMark, planModeRef, hostTaskId, sessionId, ownGatePreToolUse, hookTimeoutMs, handsCwdRef, hookEnvFace, irreversibilityTier, reversibilityProbes, abortController, shellGatedTools, autoModeDecider, autoModeDenialTracking, stopForDenialLimit, permissionRuleLane, permissionRuleOrgLane, questionToolMounted, sandboxAdmissionArmed, sandboxBoundaryCapable, emitSandboxAdmitted, delegation, notifyOwnHookCrash } = input;
|
|
46
46
|
if (askLane !== undefined && parkAsk !== undefined) {
|
|
47
47
|
const { adjudicate, resolveAskBound, notifyPermissionDenied, notifyHookError } = askLane;
|
|
48
48
|
const { resolveContentAsk, suspendAsk } = parkAsk;
|
|
@@ -119,7 +119,7 @@ export function prepareGateStations(input) {
|
|
|
119
119
|
abortSignal: abortController.signal,
|
|
120
120
|
...(notifyPermissionDenied ? { permissionDenied: notifyPermissionDenied } : {}),
|
|
121
121
|
onHookError: notifyHookError,
|
|
122
|
-
shellGated:
|
|
122
|
+
shellGated: shellGatedTools.has(e.toolName),
|
|
123
123
|
...(autoModeDecider ? { autoMode: { decider: autoModeDecider, ...(autoModeDenialTracking !== undefined ? { denialTracking: autoModeDenialTracking } : {}) } } : {}),
|
|
124
124
|
onHeadlessDenialLimit: stopForDenialLimit,
|
|
125
125
|
onAskUnresolvable: (info) => deliverEngineNotice(deps.onNotice, askUnresolvableNotice({ sessionId, ...info })),
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { type BeforeWriteHook, type CwdRef, type ReadDenyMatcher, type ReadFace } from "../../tools/fs/index.js";
|
|
2
2
|
import { type ReadFileState } from "../../tools/fs/safety.js";
|
|
3
|
-
import type { RunnerDeps, TaskSpec } from "../types.js";
|
|
3
|
+
import type { RunnerDeps, ShellGateDoctrine, TaskSpec } from "../types.js";
|
|
4
4
|
import type { Model } from "../../internal/llm.js";
|
|
5
5
|
import type { AgentTool, ExecutionEnv, WorkspaceState } from "../../internal/harness.js";
|
|
6
|
+
import type { AdvertisedWritableDirs } from "./advertised-writable-dirs.js";
|
|
6
7
|
import type { StoredSession } from "../session.js";
|
|
7
8
|
import type { IrreversibilityTier, PrepareResume, ReversibilityProbes, RunInternals, ToolFaceSnapshot } from "./contracts.js";
|
|
8
9
|
import { RosterBuilder } from "../tool-roster.js";
|
|
@@ -135,7 +136,7 @@ export interface PrepareHandsReadFaceInput {
|
|
|
135
136
|
fullShellReachable: boolean;
|
|
136
137
|
/** borrowed-readonly — the MAX-RANK fold of spec.shellGate with the inherited chain's doctrine
|
|
137
138
|
* (computed in the driver's inherited-gate block); the shellGate fold's doctrine value. */
|
|
138
|
-
effectiveShellGate:
|
|
139
|
+
effectiveShellGate: ShellGateDoctrine;
|
|
139
140
|
/** borrowed-readonly — B-1's frozen task-start face snapshot; only `.exclude` is read here (the
|
|
140
141
|
* Monitor-mount honesty bit for the gh rate-limit hint, #181-F6). */
|
|
141
142
|
toolFaceSnapshot: ToolFaceSnapshot;
|
|
@@ -161,13 +162,18 @@ export interface PrepareHandsReadFaceInput {
|
|
|
161
162
|
* when no file restore ran. Fail-closed by construction — dropping a read record only ever
|
|
162
163
|
* produces refusals. */
|
|
163
164
|
restoredFilePaths?: readonly string[];
|
|
164
|
-
/** borrowed-readonly — (ref cell; the REF itself is never replaced) design/138 S2-C
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* prepareMemory. */
|
|
165
|
+
/** borrowed-readonly — (ref cell; the REF itself is never replaced) design/138 S2-C memory write gate:
|
|
166
|
+
* the band's beforeWrite closure reads `.current` call-time; prepareMemory (driver, BEFORE this phase
|
|
167
|
+
* since #691 — the memory root must be known before the toolkit compiles) installs the gate — the one
|
|
168
|
+
* writer; this phase only reads. Declared in the driver because the SAME ref feeds prepareMemory. */
|
|
168
169
|
memoryWriteGateRef: {
|
|
169
170
|
current?: BeforeWriteHook;
|
|
170
171
|
};
|
|
172
|
+
/** borrowed-mutable — #691: the advertised-writable-directory seat (see its module header for the one
|
|
173
|
+
* rule). Present on the hands leg only (a fence exists). The memory phase, which runs BEFORE this one,
|
|
174
|
+
* has already admitted its write root through it; this phase admits the deployment's scratchpad and
|
|
175
|
+
* folds `roots` into the write-capable containment allowlist before the toolkit compiles. */
|
|
176
|
+
advertisedWritableDirs?: AdvertisedWritableDirs;
|
|
171
177
|
/** borrowed-readonly — the driver's per-tool offload wrapper (design/158 posture + policy); the
|
|
172
178
|
* band rides through it exactly as caller/MCP tools do. */
|
|
173
179
|
firstPartyOffload: (tool: AgentTool) => AgentTool;
|
|
@@ -276,12 +282,12 @@ export interface PrepareHandsReadFaceResult {
|
|
|
276
282
|
/** owned — design/199 件B: the ONE compiled deny judge per prepare (built-ins ∪ deployment ∪
|
|
277
283
|
* task additions). Undefined ⇔ hands-less (its consumers only exist with hands). */
|
|
278
284
|
readDenyMatcher: ReadDenyMatcher | undefined;
|
|
279
|
-
/**
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
+
/** owned — the shell-seat PROVENANCE set: the shell-running tools whose tier the engine's shell seat (read
|
|
286
|
+
* boundary + shellGate doctrine) is the SOLE POSITIVE source of — no explicit deployment mark on that name.
|
|
287
|
+
* The one seat every consumer reads (risk grading, the gate's tighten attribution, the persisted-rule mandate
|
|
288
|
+
* boundary): `shellGatedTools.has(toolName)`. Minted here, never grown afterwards; empty when the seat fold
|
|
289
|
+
* did not run (no real writable shell). */
|
|
290
|
+
shellGatedTools: ReadonlySet<string>;
|
|
285
291
|
/** owned (design/380 rescan C4) — the ENV-HAND tool names, minted AT THE MOUNT: every tool this
|
|
286
292
|
* phase mounted over the ExecutionEnv (the fs/bash band), later grown by the driver's own env
|
|
287
293
|
* mounts (Monitor, the worktree pair — the SAME Set identity, mutated at those mount sites).
|