@sema-agent/core 5.18.0 → 5.19.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 +97 -0
- package/dist/core/checkpoint-store.d.ts +3 -2
- package/dist/core/fs-write-gate-policy.js +1 -1
- package/dist/core/hooks.d.ts +3 -1
- package/dist/core/hooks.js +36 -0
- package/dist/core/permission-rule-consent.d.ts +8 -1
- package/dist/core/permission-rule-consent.js +21 -10
- package/dist/core/runner/active-skill-scope.js +1 -1
- package/dist/core/runner/prepare-task.d.ts +4 -0
- package/dist/core/runner/prepare-task.js +171 -121
- package/dist/core/runner/runtask.d.ts +3 -1
- package/dist/core/runner/runtask.js +35 -7
- package/dist/core/runner/session-rule-policy.js +1 -1
- package/dist/core/sensitive-path-policy.js +1 -1
- package/dist/core/tool-policy.d.ts +6 -0
- package/dist/core/tool-policy.js +75 -24
- package/dist/core/types.d.ts +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/orchestration/run-spec.js +1 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +5 -2
- package/dist/tools/fs/bash-readonly-classifier.js +129 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,102 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 5.19.0 — 2026-08-10
|
|
4
|
+
|
|
5
|
+
> Three bundles, each pre-verified two-way by the evaluation line against the 5.18.1 artifact
|
|
6
|
+
> before this release (criteria [3134], green-lit [3146]).
|
|
7
|
+
|
|
8
|
+
### BREAKING
|
|
9
|
+
|
|
10
|
+
- **A task's PreToolUse screening face now screens its DELEGATED CHILDREN** (issue #33). The
|
|
11
|
+
face used to run only in the gate of the task that installed it, so a call it denied executed
|
|
12
|
+
unrefused one level down — sync, background and workflow legs alike, at any depth. It now
|
|
13
|
+
folds into a ToolPolicy on the existing ancestor-constraint chain (full-installation identity,
|
|
14
|
+
four-axis dedup so a deps-level hook is consulted once per call at any depth). A screening
|
|
15
|
+
`ask` resolves at the installing task's frozen approver; a hook-wired parent with no approver
|
|
16
|
+
denies its children's screened calls fail-closed.
|
|
17
|
+
**Operational**: `parentConstraintCount` gains a screening entry for hook-wired trees — a
|
|
18
|
+
pending approval checkpoint minted before this change and resumed after (or the reverse)
|
|
19
|
+
fails pre-CAS with `resume.parent_constraint_mismatch`. **Drain pending checkpoints across
|
|
20
|
+
the upgrade.** A delegated child of a hook-wired parent also sets
|
|
21
|
+
`requiresParentConstraint`, so its durable resume must re-supply the chain via
|
|
22
|
+
`resumeStream(..., internals)`.
|
|
23
|
+
- **Write guards judge the call's live cwd** (P1, host-lane proven bypass). A resident shell's
|
|
24
|
+
`cd` moved what a relative Write/Edit/NotebookEdit target meant, while the guards kept
|
|
25
|
+
judging the wiring-time root — `cd .git/hooks` + `Write("pre-commit")` landed unrefused.
|
|
26
|
+
Every path-resolving guard (sensitive-path, fs-write-gate, session-rule allowDirs,
|
|
27
|
+
active-skill allowPaths, transcript-integrity, run-spec frozen deny) now resolves the target
|
|
28
|
+
against `ToolCallRequest.cwd`, stamped per call from the same tracked cwd the tools resolve
|
|
29
|
+
with. **The asymmetry is deliberate**: the target follows the live cwd; each guard's own
|
|
30
|
+
configured directories stay anchored to the static root, so a `cd` cannot relocate the fence
|
|
31
|
+
itself. Absent the stamp (direct invocation), every guard falls back to its configured root —
|
|
32
|
+
byte-identical prior behavior. Also newly asked: a non-read-only Bash whose cwd sits inside
|
|
33
|
+
the transcript directory, and a POSIX filename containing a backslash (fail-closed).
|
|
34
|
+
Registered, not fixed: bash builtin writes, hook `touchedPaths`, the shell-operand axis
|
|
35
|
+
(backlog #108 notes).
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- **Read-only shell classification (`shellGate:"classify"`) prompts less and is more accurate
|
|
40
|
+
in both directions.** The compound splitter carries quote state, so a quoted connector —
|
|
41
|
+
`grep -E "a|b"`, the ordinary spelling of a read-only monitoring pipeline — is argument text
|
|
42
|
+
rather than a phantom command boundary; `2>/dev/null` and output-descriptor fd duplication
|
|
43
|
+
are recognized as moving no data into any file. No widening: every other redirection form
|
|
44
|
+
still rejects, unbalanced quoting falls back to the stricter blind scan, and phantom segments
|
|
45
|
+
could only ever add a rejection. Also tightened in the demoting direction: operand counts now
|
|
46
|
+
match what bash passes, so stdin-reading forms that would hang (`grep "a | b"`,
|
|
47
|
+
`cut -d , -f1`, `grep -if-`, `grep -f/dev/zero`) no longer auto-allow.
|
|
48
|
+
|
|
49
|
+
### Guards / tooling (no behavior surface)
|
|
50
|
+
|
|
51
|
+
- `scripts/ship-post-lint.mjs`: release-post commit references are ancestry-verified against
|
|
52
|
+
the release, and negative claims get the real two-version dist delta to be written against.
|
|
53
|
+
- A brain silent-recovery-arm ratchet freezes the 26 existing tell-nobody arms so a new one has
|
|
54
|
+
to be argued for; the delegation carriage surfaces (live chain, constraint entry, checkpoint
|
|
55
|
+
projection) are exhaustively registered so a new field stops compiling until its travel is
|
|
56
|
+
recorded.
|
|
57
|
+
|
|
58
|
+
## 5.18.1 — 2026-08-10
|
|
59
|
+
|
|
60
|
+
> The 5.18.0 post-release verification round, folded back in. Every surface below was
|
|
61
|
+
> two-way-verified against the 5.18.0 artifact by the evaluation line before this release
|
|
62
|
+
> (pre-release criteria [3095], green-lit [3103]).
|
|
63
|
+
|
|
64
|
+
### BREAKING (vs 5.18.0; both APIs are new in 5.18.0 and cli has not consumed them yet)
|
|
65
|
+
|
|
66
|
+
- **`confirmRuleApproval` returns `{ ok: true } | { ok: false, reason }`** instead of a bare
|
|
67
|
+
boolean — seven-member closed reason set (`record_not_found` deliberately covers the
|
|
68
|
+
foreign-principal arm so record existence does not leak, `selection_missing`,
|
|
69
|
+
`selection_invalid`, `selection_mismatch`, `batch_takes_no_selection`, `not_pending`,
|
|
70
|
+
`conflict`). `selectedCandidate` is an integer index.
|
|
71
|
+
- **`prepareCardApproval` refuses caller-supplied `candidates` loudly**
|
|
72
|
+
(`config.invalid_argument`) instead of silently ignoring them — card options are
|
|
73
|
+
engine-minted, and a dropped supply attempt is the same silent-narrowing shape this
|
|
74
|
+
release family removes elsewhere.
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- **`settledBy` on approval settlements** (`"human" | "timeout" | "aborted"`): an optional
|
|
79
|
+
field on the durable resume outcome's `policy_ask` arm, carried onto the settled call's
|
|
80
|
+
`tool_end` (top-level key). Out-of-vocabulary values are refused pre-CAS
|
|
81
|
+
(`checkpoint.invalid_outcome`, `detail.field: "settledBy"` — the row stays pending);
|
|
82
|
+
`decision: "allow"` accepts only `"human"` or omission (a contradictory record must not
|
|
83
|
+
become an execution). Core's own arms fill it (elapsed window = `timeout`; abort /
|
|
84
|
+
unclonable / out-of-contract = `aborted`; human answers = `"human"`); posture arms
|
|
85
|
+
(headless auto-deny, blanket modes) leave it absent. Absence = an older caller — consumers
|
|
86
|
+
must not infer semantics from a missing key. New exports: `ApprovalSettledBy`,
|
|
87
|
+
`APPROVAL_SETTLED_BY_VALUES`, `isApprovalSettledBy`.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
|
|
91
|
+
- **An elapsed approval window says nobody answered** — the live-deadline refusal no longer
|
|
92
|
+
borrows the sentence a person's refusal uses; human-refusal and no-provenance wordings are
|
|
93
|
+
byte-for-byte unchanged (269 existing approval strings verified untouched).
|
|
94
|
+
- **`createAllowDenyPolicy` screens malformed `mcp__` names** (empty segment: `mcp__`,
|
|
95
|
+
`mcp__a__`) alongside the content form; `mcp__server` / `mcp__server__tool` and the
|
|
96
|
+
conditionally-retired `Task` spelling stay accepted. The constructor-level retired-name
|
|
97
|
+
screen added briefly after 5.18.0 was withdrawn — the roster-aware prepare-time audit
|
|
98
|
+
(`config.legacy_tool_name`, all three kinds) already owns that refusal.
|
|
99
|
+
|
|
3
100
|
## 5.18.0 — 2026-08-10
|
|
4
101
|
|
|
5
102
|
> Two mainline features land together: design/178 personal-assistant memory v1 (the retrieval pair
|
|
@@ -95,6 +95,7 @@ export type ResumeOutcome = {
|
|
|
95
95
|
updatedInput?: unknown;
|
|
96
96
|
reason?: string;
|
|
97
97
|
answer?: QuestionAnswer;
|
|
98
|
+
settledBy?: import("./tool-policy.js").ApprovalSettledBy;
|
|
98
99
|
} | {
|
|
99
100
|
gate: "resource_limit";
|
|
100
101
|
decision: "continue";
|
|
@@ -277,10 +278,10 @@ export declare function summarizeCheckpoint(cp: Checkpoint): CheckpointSummary;
|
|
|
277
278
|
export declare class CheckpointError extends Error {
|
|
278
279
|
readonly code: "checkpoint.already_exists" | "checkpoint.already_resolved" | "checkpoint.not_found" | "checkpoint.gate_mismatch" | "checkpoint.resume_aborted" | "checkpoint.invalid_outcome" | "checkpoint.unsupported_version" | "checkpoint.walltime_axis_retired" | "checkpoint.reopen_revote" | "checkpoint.reopened_concurrently" | "checkpoint.reopen_failed" | "steering.invalid_content" | "steering.queue_full" | "steering.duplicate_input_id" | "wake.gate_pending" | "wake.nothing_to_deliver" | "resume.parent_constraint_missing" | "resume.parent_constraint_mismatch";
|
|
279
280
|
readonly detail?: {
|
|
280
|
-
field?: "boundCallId" | "boundInputHash" | "answer";
|
|
281
|
+
field?: "boundCallId" | "boundInputHash" | "answer" | "settledBy";
|
|
281
282
|
} | undefined;
|
|
282
283
|
constructor(code: "checkpoint.already_exists" | "checkpoint.already_resolved" | "checkpoint.not_found" | "checkpoint.gate_mismatch" | "checkpoint.resume_aborted" | "checkpoint.invalid_outcome" | "checkpoint.unsupported_version" | "checkpoint.walltime_axis_retired" | "checkpoint.reopen_revote" | "checkpoint.reopened_concurrently" | "checkpoint.reopen_failed" | "steering.invalid_content" | "steering.queue_full" | "steering.duplicate_input_id" | "wake.gate_pending" | "wake.nothing_to_deliver" | "resume.parent_constraint_missing" | "resume.parent_constraint_mismatch", message: string, detail?: {
|
|
283
|
-
field?: "boundCallId" | "boundInputHash" | "answer";
|
|
284
|
+
field?: "boundCallId" | "boundInputHash" | "answer" | "settledBy";
|
|
284
285
|
} | undefined);
|
|
285
286
|
}
|
|
286
287
|
export type StoreDurability = "durable" | "process-local";
|
|
@@ -15,7 +15,7 @@ export function createFsWriteGatePolicy(opts) {
|
|
|
15
15
|
if (path === undefined) {
|
|
16
16
|
return ask(`write tool "${req.toolName}" requires approval: the call has no resolvable path target to confine`);
|
|
17
17
|
}
|
|
18
|
-
const canon = await canonicalizeTarget(env, path, signal, rootPath);
|
|
18
|
+
const canon = await canonicalizeTarget(env, path, signal, req.cwd ?? rootPath);
|
|
19
19
|
if (!canon.ok) {
|
|
20
20
|
return ask(`write to "${path}" requires approval: its real target could not be resolved (${canon.message})`);
|
|
21
21
|
}
|
package/dist/core/hooks.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DocumentContent, ImageContent, TextContent } from "../internal/llm.js";
|
|
2
2
|
import type { ExecutionEnv, FileError, Result, SessionTreeEntry } from "../internal/harness-types.js";
|
|
3
|
-
import type { PermissionResult, ResolvedAsk, ToolCallRequest } from "./tool-policy.js";
|
|
3
|
+
import type { PermissionResult, ResolvedAsk, ToolCallRequest, ToolPolicy } from "./tool-policy.js";
|
|
4
4
|
export interface Hooks {
|
|
5
5
|
preToolUse?(toolName: string, input: unknown, ctx: HookToolContext): PreToolUseResult | undefined | Promise<PreToolUseResult | undefined>;
|
|
6
6
|
postToolUse?(toolName: string, input: unknown, output: HookToolOutput, ctx: HookToolContext): PostToolUseResult | undefined | Promise<PostToolUseResult | undefined>;
|
|
@@ -104,6 +104,7 @@ export declare function formatHookFeedback(text: string): string;
|
|
|
104
104
|
export interface ToolGateResult {
|
|
105
105
|
block?: boolean;
|
|
106
106
|
reason?: string;
|
|
107
|
+
settledBy?: import("./tool-policy.js").ApprovalSettledBy;
|
|
107
108
|
updatedInput?: unknown;
|
|
108
109
|
suspend?: {
|
|
109
110
|
token: import("./checkpoint-store.js").CheckpointToken;
|
|
@@ -164,4 +165,5 @@ export interface ToolGateInput {
|
|
|
164
165
|
}) => void;
|
|
165
166
|
};
|
|
166
167
|
}
|
|
168
|
+
export declare function createPreToolUseConstraintPolicy(preToolUse: NonNullable<Hooks["preToolUse"]>, env?: HookEnvCapabilities, onCrash?: (err: unknown) => void): ToolPolicy;
|
|
167
169
|
export declare function runToolGate(input: ToolGateInput): Promise<ToolGateResult>;
|
package/dist/core/hooks.js
CHANGED
|
@@ -98,6 +98,38 @@ function screenPreToolUseResult(r) {
|
|
|
98
98
|
return undefined;
|
|
99
99
|
return refuseOutOfContractDecision(r);
|
|
100
100
|
}
|
|
101
|
+
export function createPreToolUseConstraintPolicy(preToolUse, env, onCrash) {
|
|
102
|
+
return {
|
|
103
|
+
check: async (req) => {
|
|
104
|
+
let r;
|
|
105
|
+
try {
|
|
106
|
+
r = screenPreToolUseResult(await preToolUse(req.toolName, req.args, { toolCallId: req.toolCallId, toolName: req.toolName, ...(env !== undefined ? { env } : {}) }));
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
try {
|
|
110
|
+
onCrash?.(err);
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
}
|
|
114
|
+
return { action: "deny", message: preToolUseCrashReason(`this call to "${req.toolName}"`, err), decisionReason: "hook" };
|
|
115
|
+
}
|
|
116
|
+
if (r === undefined)
|
|
117
|
+
return { action: "allow" };
|
|
118
|
+
if (r.action === "deny") {
|
|
119
|
+
return { action: "deny", message: decisionText(r) ?? `tool "${req.toolName}" blocked by a PreToolUse hook`, decisionReason: "hook" };
|
|
120
|
+
}
|
|
121
|
+
if (r.action === "ask") {
|
|
122
|
+
return {
|
|
123
|
+
action: "ask",
|
|
124
|
+
message: decisionText(r) ?? `approval required for "${req.toolName}" (inherited PreToolUse hook)`,
|
|
125
|
+
decisionReason: "hook",
|
|
126
|
+
...(r.updatedInput !== undefined ? { updatedInput: r.updatedInput } : {}),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
return r.updatedInput !== undefined ? { action: "allow", updatedInput: r.updatedInput } : { action: "allow" };
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
}
|
|
101
133
|
function traceHookCrash(input, err, notifier) {
|
|
102
134
|
notifier.notify(() => input.onHookError?.(err), "toolGate.onHookError");
|
|
103
135
|
}
|
|
@@ -411,9 +443,11 @@ export async function runToolGate(input) {
|
|
|
411
443
|
if (input.permissionDenied) {
|
|
412
444
|
await notifier.notifyAsync(() => input.permissionDenied?.({ toolName, input: cloneObserverInput(currentInput), toolCallId, reason: denyReason, source: denySource }), "toolGate.permissionDenied");
|
|
413
445
|
}
|
|
446
|
+
const denySettledBy = decision.settledBy;
|
|
414
447
|
return {
|
|
415
448
|
block: true,
|
|
416
449
|
reason: formatHookFeedback(denyReason),
|
|
450
|
+
...(denySettledBy !== undefined ? { settledBy: denySettledBy } : {}),
|
|
417
451
|
preToolContext,
|
|
418
452
|
};
|
|
419
453
|
}
|
|
@@ -422,8 +456,10 @@ export async function runToolGate(input) {
|
|
|
422
456
|
if (rw !== undefined)
|
|
423
457
|
currentInput = rw;
|
|
424
458
|
}
|
|
459
|
+
const allowSettledBy = decision.action === "allow" ? decision.settledBy : undefined;
|
|
425
460
|
return {
|
|
426
461
|
updatedInput: currentInput === event.input ? undefined : currentInput,
|
|
462
|
+
...(allowSettledBy !== undefined ? { settledBy: allowSettledBy } : {}),
|
|
427
463
|
preToolContext,
|
|
428
464
|
};
|
|
429
465
|
}
|
|
@@ -56,7 +56,14 @@ export declare function confirmRuleApproval(opts: {
|
|
|
56
56
|
principal: string;
|
|
57
57
|
selectedCandidate?: number;
|
|
58
58
|
deps: RuleConsentDeps;
|
|
59
|
-
}): Promise<
|
|
59
|
+
}): Promise<ConfirmResult>;
|
|
60
|
+
export type ConfirmRefusalReason = "record_not_found" | "selection_missing" | "selection_invalid" | "selection_mismatch" | "batch_takes_no_selection" | "not_pending" | "conflict";
|
|
61
|
+
export type ConfirmResult = {
|
|
62
|
+
ok: true;
|
|
63
|
+
} | {
|
|
64
|
+
ok: false;
|
|
65
|
+
reason: ConfirmRefusalReason;
|
|
66
|
+
};
|
|
60
67
|
export type RedeemResult = {
|
|
61
68
|
status: "redeemed";
|
|
62
69
|
rule: string;
|
|
@@ -47,6 +47,11 @@ function parseRuleTicket(ticket) {
|
|
|
47
47
|
}
|
|
48
48
|
export async function prepareCardApproval(opts) {
|
|
49
49
|
const principal = requirePrincipal(opts.principal, "prepareCardApproval");
|
|
50
|
+
if ("candidates" in opts) {
|
|
51
|
+
const e = new Error("prepareCardApproval does not accept caller candidates — card options are minted by the engine from the adjudicated command");
|
|
52
|
+
e.code = "config.invalid_argument";
|
|
53
|
+
throw e;
|
|
54
|
+
}
|
|
50
55
|
if (opts.toolName !== CARD_RULE_TOOL)
|
|
51
56
|
return undefined;
|
|
52
57
|
const scope = opts.scope ?? { kind: "global" };
|
|
@@ -70,24 +75,30 @@ export async function prepareCardApproval(opts) {
|
|
|
70
75
|
const CARD_RULE_TOOL = "Bash";
|
|
71
76
|
export async function confirmRuleApproval(opts) {
|
|
72
77
|
const principal = requirePrincipal(opts.principal, "confirmRuleApproval");
|
|
78
|
+
const no = (reason) => ({ ok: false, reason });
|
|
73
79
|
const rec = await opts.deps.approvals.get(opts.approvalId);
|
|
74
80
|
if (rec === undefined || rec.principal !== principal)
|
|
75
|
-
return
|
|
81
|
+
return no("record_not_found");
|
|
76
82
|
if (rec.kind === "card") {
|
|
77
83
|
const chosen = opts.selectedCandidate;
|
|
78
|
-
if (chosen === undefined
|
|
79
|
-
return
|
|
80
|
-
if (
|
|
81
|
-
return
|
|
82
|
-
|
|
84
|
+
if (chosen === undefined)
|
|
85
|
+
return no("selection_missing");
|
|
86
|
+
if (!Number.isInteger(chosen) || rec.candidates[chosen] === undefined)
|
|
87
|
+
return no("selection_invalid");
|
|
88
|
+
if (rec.state === "approved" || rec.state === "redeemed") {
|
|
89
|
+
return rec.selectedCandidate === chosen ? { ok: true } : no("selection_mismatch");
|
|
90
|
+
}
|
|
91
|
+
const won = await opts.deps.approvals.cas(rec.id, rec.rev, { ...rec, rev: rec.rev + 1, state: "approved", selectedCandidate: chosen });
|
|
92
|
+
return won ? { ok: true } : no("conflict");
|
|
83
93
|
}
|
|
84
94
|
if (opts.selectedCandidate !== undefined)
|
|
85
|
-
return
|
|
95
|
+
return no("batch_takes_no_selection");
|
|
86
96
|
if (rec.state === "approved")
|
|
87
|
-
return true;
|
|
97
|
+
return { ok: true };
|
|
88
98
|
if (rec.state !== "pending")
|
|
89
|
-
return
|
|
90
|
-
|
|
99
|
+
return no("not_pending");
|
|
100
|
+
const won = await opts.deps.approvals.cas(rec.id, rec.rev, { ...rec, rev: rec.rev + 1, state: "approved" });
|
|
101
|
+
return won ? { ok: true } : no("conflict");
|
|
91
102
|
}
|
|
92
103
|
export async function redeemRuleTicket(opts) {
|
|
93
104
|
const principal = requirePrincipal(opts.principal, "redeemRuleTicket");
|
|
@@ -96,7 +96,7 @@ export function createActiveSkillScopePolicy(opts) {
|
|
|
96
96
|
decisionReason: "safety",
|
|
97
97
|
};
|
|
98
98
|
}
|
|
99
|
-
const canon = await canonicalizeTarget(env, path, signal, rootPath);
|
|
99
|
+
const canon = await canonicalizeTarget(env, path, signal, req.cwd ?? rootPath);
|
|
100
100
|
if (!canon.ok) {
|
|
101
101
|
return {
|
|
102
102
|
action: "deny",
|
|
@@ -10,6 +10,7 @@ import { SubagentRetainLedger } from "../../agents/retain-ledger.js";
|
|
|
10
10
|
import type { OnAsk, ToolPolicy } from "../tool-policy.js";
|
|
11
11
|
import { type ActiveSkillFrame } from "./active-skill-scope.js";
|
|
12
12
|
import type { SessionPermissionRules } from "../session-policy-store.js";
|
|
13
|
+
import { type Hooks } from "../hooks.js";
|
|
13
14
|
import { type RecoveredOrphan } from "../session-reconcile.js";
|
|
14
15
|
import { CacheBreakDetector, type ToolFingerprintInput } from "../cache-break-detector.js";
|
|
15
16
|
import { type BrainCallGuardrailRef } from "../../brain/timeout.js";
|
|
@@ -64,6 +65,7 @@ export interface Prepared {
|
|
|
64
65
|
hit: boolean;
|
|
65
66
|
};
|
|
66
67
|
blockedToolCalls: Set<string>;
|
|
68
|
+
approvalSettledBy: Map<string, import("../tool-policy.js").ApprovalSettledBy>;
|
|
67
69
|
nestedStats: NestedUsageAccum;
|
|
68
70
|
rewindNotes?: NonNullable<TaskResult["rewindNotes"]>;
|
|
69
71
|
cwdRef?: CwdRef;
|
|
@@ -329,6 +331,8 @@ export interface InheritedGate {
|
|
|
329
331
|
policy: ToolPolicy;
|
|
330
332
|
onAsk?: OnAsk;
|
|
331
333
|
durableMandate?: boolean;
|
|
334
|
+
preToolUse?: Hooks["preToolUse"];
|
|
335
|
+
hookEnv?: unknown;
|
|
332
336
|
}>;
|
|
333
337
|
}
|
|
334
338
|
export declare function isFableFamilyModelId(id: string): boolean;
|