@sema-agent/core 7.6.0 → 7.6.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/agents/agent-transcript-tool.d.ts +2 -2
  3. package/dist/agents/cascade.d.ts +2 -3
  4. package/dist/agents/repair-loop.d.ts +2 -2
  5. package/dist/agents/retain-ledger.d.ts +2 -3
  6. package/dist/agents/send-message-tool.d.ts +2 -2
  7. package/dist/agents/session-util.d.ts +2 -2
  8. package/dist/agents/subagent.d.ts +3 -4
  9. package/dist/agents/teacher.d.ts +2 -2
  10. package/dist/agents/team.d.ts +2 -2
  11. package/dist/agents/verify.d.ts +5 -6
  12. package/dist/core/agent-definition.d.ts +172 -0
  13. package/dist/core/agent-definition.js +1 -0
  14. package/dist/core/delegation-frames.d.ts +298 -0
  15. package/dist/core/delegation-frames.js +21 -0
  16. package/dist/core/engine-notice.d.ts +555 -0
  17. package/dist/core/engine-notice.js +55 -0
  18. package/dist/core/gate-fold.d.ts +12 -0
  19. package/dist/core/gate-fold.js +158 -0
  20. package/dist/core/gate-lanes.d.ts +93 -0
  21. package/dist/core/gate-lanes.js +626 -0
  22. package/dist/core/hands-band.d.ts +134 -0
  23. package/dist/core/hands-band.js +1 -0
  24. package/dist/core/hooks.d.ts +20 -101
  25. package/dist/core/hooks.js +53 -854
  26. package/dist/core/mcp-failure.d.ts +43 -5
  27. package/dist/core/mcp-failure.js +31 -14
  28. package/dist/core/mcp-server-spec.d.ts +217 -0
  29. package/dist/core/mcp-server-spec.js +1 -0
  30. package/dist/core/model-seat.d.ts +99 -0
  31. package/dist/core/model-seat.js +1 -0
  32. package/dist/core/reminder-mint.d.ts +10 -0
  33. package/dist/core/reminder-mint.js +3 -0
  34. package/dist/core/runner/contracts.d.ts +382 -6
  35. package/dist/core/runner/gate-exit.d.ts +177 -9
  36. package/dist/core/runner/gate-exit.js +70 -1
  37. package/dist/core/runner/prepare-caps-and-workflow.d.ts +2 -7
  38. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -7
  39. package/dist/core/runner/prepare-task.d.ts +2 -2
  40. package/dist/core/runner/runtask.d.ts +4 -71
  41. package/dist/core/runner/runtask.js +14 -5
  42. package/dist/core/runner-deps.d.ts +1416 -0
  43. package/dist/core/runner-deps.js +1 -0
  44. package/dist/core/runtime-caps.d.ts +164 -0
  45. package/dist/core/runtime-caps.js +1 -0
  46. package/dist/core/task-event.d.ts +910 -0
  47. package/dist/core/task-event.js +1 -0
  48. package/dist/core/task-limits.d.ts +110 -0
  49. package/dist/core/task-limits.js +1 -0
  50. package/dist/core/task-result.d.ts +809 -0
  51. package/dist/core/task-result.js +1 -0
  52. package/dist/core/task-spec.d.ts +1370 -0
  53. package/dist/core/task-spec.js +1 -0
  54. package/dist/core/task-stream.d.ts +382 -0
  55. package/dist/core/task-stream.js +1 -0
  56. package/dist/core/tool-spec.d.ts +1174 -0
  57. package/dist/core/tool-spec.js +1 -0
  58. package/dist/core/types.d.ts +26 -7691
  59. package/dist/core/types.js +2 -76
  60. package/dist/core/warm-resume.d.ts +2 -2
  61. package/dist/index.d.ts +2 -1
  62. package/dist/index.js +1 -1
  63. package/dist/orchestration/goal.d.ts +2 -2
  64. package/dist/orchestration/run-spec.d.ts +2 -2
  65. package/dist/orchestration/run-workflow-tool.d.ts +3 -3
  66. package/dist/orchestration/workflow.d.ts +4 -4
  67. package/dist/scenarios/scenario-registry.d.ts +3 -3
  68. package/dist/scenarios/teacher-quickstart.d.ts +2 -2
  69. package/dist/server/http.d.ts +2 -2
  70. package/dist/stores/file/fs-atomic.d.ts +88 -12
  71. package/dist/stores/file/fs-atomic.js +184 -55
  72. package/dist/stores/file/index.d.ts +1 -0
  73. package/dist/stores/file/index.js +1 -0
  74. package/package.json +1 -1
  75. package/test/export-surface.snapshot.json +9 -1
@@ -0,0 +1,134 @@
1
+ /**
2
+ * design/138 S2-C — the hands band's write-time CONTENT hook (single source; `src/tools/fs` re-exports
3
+ * these so its import surface is unchanged — moved here by design/141 件2 because `RunnerDeps.hands`
4
+ * carries the deployment-composable half of the hook). Called before EVERY `env.writeFile` in
5
+ * Write/Edit/NotebookEdit with the resolved containment key and the exact final text; `{ ok:false }`
6
+ * fails the tool with a structured error and NOTHING is written. A THROWING hook fails CLOSED.
7
+ */
8
+ export interface BeforeWriteRequest {
9
+ tool: "Write" | "Edit" | "NotebookEdit";
10
+ /** The model-supplied path argument (for the error-message coordinate the model knows). */
11
+ path: string;
12
+ /** The resolved canonical containment key — what the hook should judge. */
13
+ key: string;
14
+ /** The FINAL full text about to be written (Edit/NotebookEdit: after application). */
15
+ content: string;
16
+ }
17
+ export type BeforeWriteResult = {
18
+ ok: true;
19
+ } | {
20
+ ok: false;
21
+ code: string;
22
+ reason: string;
23
+ };
24
+ export type BeforeWriteHook = (req: BeforeWriteRequest) => BeforeWriteResult | undefined | Promise<BeforeWriteResult | undefined>;
25
+ /**
26
+ * design/381 — the hands band's FIRST-TOUCH HISTORY hook, called before EVERY file mutation in
27
+ * Write/Edit/NotebookEdit (after the `beforeWrite` content gate passed, immediately before the
28
+ * final env write) with the resolved canonical containment key. The Runner wires it to
29
+ * `FileHistoryStore.trackEdit` (backup-before-first-edit, the CC FileHistory trigger-point set
30
+ * minus the bash simulation arm sema does not have — DV-7); later calls for an already-tracked
31
+ * path are cheap store no-ops. `{ok:false}` carries the REFUSAL TEXT the tool must answer instead
32
+ * of writing (DV-14 default: no durable first-touch state ⇒ the edit is refused, typed and loud —
33
+ * any proceed-unprotected policy is resolved INSIDE the hook by the Runner, never by the band).
34
+ * A THROWING hook fails CLOSED (same posture as the write gate). Absent hook ⇒ byte-identical
35
+ * behavior (no history store wired).
36
+ */
37
+ export interface TrackEditRequest {
38
+ tool: "Write" | "Edit" | "NotebookEdit";
39
+ /** The model-supplied path argument (for the error-message coordinate the model knows). */
40
+ path: string;
41
+ /** The resolved canonical containment key — the identity the history record is keyed on. */
42
+ key: string;
43
+ /** The tool call's abort signal, threaded into the store's env read. */
44
+ signal?: AbortSignal;
45
+ }
46
+ export type TrackEditResult = {
47
+ ok: true;
48
+ /**
49
+ * #491 — the compensating handle for the ordering the topology cannot avoid: the pre-image
50
+ * capture runs BEFORE the write, so a write that then FAILS (lost create race, ENOSPC,
51
+ * EACCES, read-only mount) would leave a first-touch record for an edit that never happened —
52
+ * and an `existed-not` record makes an untouched path a rewind DELETE target, removing bytes
53
+ * whoever writes them next (the user, a peer process) owns. Present ONLY when THIS call minted
54
+ * the record (an already-tracked path belongs to the edit that first touched it and must never
55
+ * be discarded); the band calls it on the write-failure arm of every mutation lane. `proof`
56
+ * says which retraction rule applies: `"proven"` = the write's own error code guarantees
57
+ * nothing was written, `"verify"` = ambiguous, so the history seat must re-read the path and
58
+ * retract only if it still matches what the first touch recorded. It never throws and never
59
+ * blocks the failure it accompanies — the original write error is the answer.
60
+ */
61
+ annul?: (proof: "proven" | "verify") => Promise<void>;
62
+ } | {
63
+ ok: false;
64
+ refusal: string;
65
+ };
66
+ export type TrackFileEditHook = (req: TrackEditRequest) => Promise<TrackEditResult>;
67
+ /**
68
+ * The hands band's MUTATION-EDITED observation seat — the counterpart of {@link TrackEditRequest},
69
+ * fired at the other end of the same lane. Called once per Write/Edit/NotebookEdit call whose FINAL
70
+ * env write did not PROVABLY write nothing, at the single point every mutation lane funnels through,
71
+ * under the same three-valued law as the first-touch record's own retraction:
72
+ * - a call the argument checks, the read-before-edit gate, the write gate or the first-touch
73
+ * history seat refused never fires it (nothing was written);
74
+ * - a call whose write FAILED with a code whose contract says nothing was written never fires it;
75
+ * - a call whose write failed AMBIGUOUSLY (a non-atomic env that truncated and then errored) or
76
+ * THREW fires it — exactly the arm where the retraction KEEPS the first-touch record because the
77
+ * file may really have changed. The two seats agree on purpose: a file whose baseline was kept
78
+ * for a possible modification must also be listed as possibly modified;
79
+ * - a `Bash` command that changed a file never fires it: bash does not run through this band's
80
+ * write lanes at all, which is the whole reason this seat is not a tool-name table.
81
+ * PURE OBSERVATION: it returns nothing and it cannot refuse. A FAULT in it is contained in both
82
+ * shapes an observer can fail in — a synchronous throw, and (the return type is `void`, but an
83
+ * `async` function still type-checks there) a rejected promise, which is sunk rather than left
84
+ * unhandled. Neither is awaited: an observer must never turn a landed write into a failed tool
85
+ * answer, nor delay one.
86
+ */
87
+ export interface FileEditedNotice {
88
+ tool: "Write" | "Edit" | "NotebookEdit";
89
+ /** The model-supplied path argument — the SAME coordinate the delegated-child projection's
90
+ * `SubagentEditedFile.path` carries, so the two seats can be read side by side. */
91
+ path: string;
92
+ /** The resolved canonical containment key the bytes actually landed on. */
93
+ key: string;
94
+ }
95
+ export type FileEditedHook = (notice: FileEditedNotice) => void;
96
+ /**
97
+ * design/141 件2 — the SAFE deployment-configurable subset of the hands toolkit ({@link RunnerDeps.hands}).
98
+ * Only fields whose injection is purely additive for a deployment are here; Runner-internal orchestration
99
+ * state (taskRegistry/detachHub/execClamp/cwdRef/mount coordination) is deliberately NOT configurable.
100
+ */
101
+ export interface HandsBandOptions {
102
+ /** Override the `bash_readonly` command allowlist (read-only band). Default: the built-in read-only set. */
103
+ bashReadonlyAllow?: readonly string[];
104
+ /** Co-Authored-By trailer for the bash git protocol. Default NONE ([c209] BREAKING: attribution is a
105
+ * deployment identity asset — the branded scenario sets `"Name <email>"`); `false` ≡ unset. */
106
+ commitCoAuthor?: string | false;
107
+ /** Read-tool image downsampler: inject your own, or `false` to force-disable (deterministic no-sharp).
108
+ * Omitted ⇒ auto-detect sharp. Same contract as the MCP-side {@link import("./mcp.js").ImageDownsampler}. */
109
+ readImageDownsampler?: ((input: Buffer, mimeType: string) => Promise<import("./mcp.js").DownsampledImage | undefined>) | false;
110
+ /** Deployment write gate — COMPOSED with (never replacing) the engine's MemoryEngine write-scan gate:
111
+ * this hook judges first (a rejection short-circuits), the engine gate then still runs in full. */
112
+ beforeWrite?: BeforeWriteHook;
113
+ /** RB-198 F1 (CC 220 `Zry`/`WZi.#m` parity): on a foreground Bash command's OWN timeout, an eligible
114
+ * command (see `canAutoBackground` — no `git` anywhere in the command, not a `sleep`-first-word wait) is
115
+ * adopted as a background task instead of being killed — CC's own posture ("received no response for
116
+ * Nms" would otherwise force a wasteful blind re-run of a non-idempotent long command). Default `false`
117
+ * (byte-compat): this is a deployment-level opt-in, deliberately NOT inferred from background-task
118
+ * plumbing (`detachHub`/`taskRegistry`) merely being present, since the Runner wires those unconditionally
119
+ * for every task — tying eligibility to their mere presence would silently flip the timeout outcome for
120
+ * every existing caller with no explicit signal at all. */
121
+ autoBackgroundOnTimeout?: boolean;
122
+ /** Append the per-read content-safety reminder after a successful text read (the ~50-token
123
+ * `<system-reminder>` the Read tool adds to a text body — the plain-text and notebook read paths;
124
+ * PDF text extraction has its own result builder and has never carried the reminder, so this switch
125
+ * does not govern it). Default TRUE, and an omitted field keeps
126
+ * that default: a BYOM engine cannot assume its serving model carries that mitigation internally, and
127
+ * the reminder only works because it sits next to the bytes it is about — not in a system prompt
128
+ * hundreds of turns back.
129
+ *
130
+ * Pass `false` to state that THIS deployment's serving model does carry it, and stop paying the
131
+ * reminder's tokens on every text read for advice the model already applies. Absent and `false` are
132
+ * deliberately different decisions: absent means "unknown, so assume not". */
133
+ readCyberReminder?: boolean;
134
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -2,8 +2,11 @@ import type { ActorAssertion, DocumentContent, ImageContent, TextContent } from
2
2
  import type { ExecutionEnv, FileError, Result, SessionTreeEntry } from "../internal/harness-types.js";
3
3
  import type { DecisionReason, PermissionResult, ResolvedAsk, ToolCallRequest, ToolPolicy } from "./tool-policy.js";
4
4
  import type { GateOutcome } from "./gate-outcome.js";
5
+ export { normalizeOrgGateVerdict, normalizePersistedRuleHit, persistedRuleMandateOf } from "./gate-lanes.js";
6
+ export { cloneObserverInput } from "./runner/gate-exit.js";
5
7
  import { type AskClass } from "./ask-class.js";
6
- import { type AutoModeDenialTracker } from "./auto-mode.js";
8
+ import type { AutoModeDenialTracker } from "./auto-mode.js";
9
+ export { formatHookFeedback } from "./reminder-mint.js";
7
10
  import type { WiringLegKind } from "./wiring-manifest.js";
8
11
  /**
9
12
  * In-process hook seam (design/37) — a provider-agnostic interception layer modeled on CC's hooks,
@@ -413,15 +416,6 @@ export interface PermissionDeniedPayload {
413
416
  * thing: stop reading, nobody is waiting for your answer any more. */
414
417
  signal?: AbortSignal;
415
418
  }
416
- /**
417
- * 1.256 复审 MED-1 — observe-only payload isolation for {@link Hooks.permissionDenied}: clone the tool
418
- * args before they ride the observer payload, so a hook mutating `payload.input` can never pollute the
419
- * LIVE args object (later events / audit records share it). Same posture as the postToolUseFailure
420
- * details clone (prepare-task): `structuredClone` first; a non-structured-cloneable graph
421
- * (functions/handles) falls back to a SHALLOW plain object/array copy (top-level mutation isolated);
422
- * a non-object primitive passes through as-is (immutable anyway).
423
- */
424
- export declare function cloneObserverInput(input: unknown): unknown;
425
419
  /** Context for {@link Hooks.stopFailure} — aligned with the TaskResult error face (observe-only). */
426
420
  export interface StopFailureContext {
427
421
  /** #281 件A — the run/leg identity envelope (always present on the engine's emission; the seat is
@@ -901,15 +895,6 @@ export interface UserPromptSubmitResult {
901
895
  /** Injected ahead of the user's prompt (wrapped as a `<system-reminder>`). */
902
896
  additionalContext?: string;
903
897
  }
904
- /** Wrap model-facing hook/gate feedback in a `<system-reminder>` so it reads as guidance, not data.
905
- * NOTE (council design/74 #6): this does NOT escape a literal `</system-reminder>` in `text` — callers MUST
906
- * pass trusted, first-party strings (every current caller does: fixed gate/limit messages). If a future
907
- * caller needs to relay UNTRUSTED content (tool output, user data), it must sanitize the close tag first
908
- * (or use the `delimitUntrusted` fence), or a crafted payload could break out of the reminder framing.
909
- * design/319 (A ticket): `mark` is the session's reminder provenance mark — run-scoped callers thread it
910
- * so the open tag carries the value the system-prompt declaration names (rendered by the mint home; the
911
- * body is byte-untouched). Absent ⇒ the historic bare open tag (a caller outside a run). */
912
- export declare function formatHookFeedback(text: string, mark?: string): string;
913
898
  /** The outcome of the two-phase tool gate, mapped onto the harness `tool_call` hook return shape. */
914
899
  export interface ToolGateResult {
915
900
  /** Block execution (the loop emits an error tool result with `reason`). */
@@ -1082,53 +1067,6 @@ export interface PersistedRuleCoverage {
1082
1067
  }
1083
1068
  /** Every shape a lane may answer with. A bare string stays valid and unchanged. */
1084
1069
  export type PersistedRuleAnswer = string | PersistedRuleHit | PersistedRuleCoverage | PersistedRuleUnreadable | undefined;
1085
- /**
1086
- * design/252 review r3 — read a foreign {@link OrgGateVerdict} the way the personal-rule answer is read:
1087
- * OWN DATA properties only, never the prototype chain, never an accessor.
1088
- *
1089
- * Unlike the personal-rule normalizer below, this one accepts ANY non-array object as the carrier —
1090
- * not only a plain record. The two seams tighten in opposite directions when a shape is refused: the
1091
- * personal lane is a LOOSENING seam, so refusing a class instance degrades toward asking; this answer
1092
- * carries the org's DENY, and folding a structurally valid `{status:"available", verdict:{behavior:
1093
- * "deny"}}` class instance into `unavailable` would LOOSEN it — from a deny nobody can approve into a
1094
- * real-approval ask a person can clear. A class instance's fields are its own data properties, so the
1095
- * own-data read below already gives the full pollution guarantee (inherited members never authorize);
1096
- * the prototype test added nothing here but the downgrade.
1097
- *
1098
- * The two seams are the same class of trust boundary and were not being read the same way. What that
1099
- * cost here is worse than on the personal lane, because this answer is GOVERNANCE:
1100
- * · an inherited `revision` (a polluted `Object.prototype`) stamped a fabricated snapshot version onto
1101
- * a human's approval request — a WRONG record, which is worse than an absent one;
1102
- * · an inherited `verdict` invented an org rule, and with it an org ask or deny the lane never gave;
1103
- * · an answer that is not a record at all read as "available, nothing to say", i.e. the governance
1104
- * fail-open the availability contract exists to prevent.
1105
- * Anything this function cannot read as a well-formed answer becomes `unavailable` — the fail-CLOSED
1106
- * word, never the empty one.
1107
- */
1108
- export declare function normalizeOrgGateVerdict(answer: unknown, unreadable: string): OrgGateVerdict;
1109
- /**
1110
- * Normalize the accepted {@link ToolGateInput.persistedRules} answers into one reading.
1111
- *
1112
- * `{}` = a clean negative (no rule admits this call). `{ unreadable: true }` = the lane could not read
1113
- * its source. `{ hit }` = a match, whose `rules` is the non-empty coverage set (design/375). An answer
1114
- * outside every accepted shape — a number, `null`, an object with neither `rules` nor `unreadable`, an
1115
- * EMPTY `rules` array, the retired pre-375 `{ rule, dots? }` single-rule object — is read as a clean
1116
- * negative rather than a match: this is a LOOSENING seam, so an answer nobody can name degrades toward
1117
- * asking, never toward an allow built on it. All-or-nothing across the set's TEXTS for the same
1118
- * reason: a set with one unreadable member is a different (smaller) claim than the lane made, and a
1119
- * decision must not stand on a claim nobody made — one bad member drops the whole answer to the clean
1120
- * negative. Per-member DOTS stay individually optional (identity lost ⇒ `"not_reported"`, exactly the
1121
- * single-rule contract).
1122
- *
1123
- * The hit's dots are COPIED, not aliased. The array travels onto an ask that may sit in front of a
1124
- * person for a long time; a lane that retains and mutates its own array would otherwise change what the
1125
- * approver is looking at, and what an audit later reads, after the evidence was stamped.
1126
- */
1127
- export declare function normalizePersistedRuleHit(hit: PersistedRuleAnswer): {
1128
- hit?: PersistedRuleHit;
1129
- unreadable?: true;
1130
- coverage?: readonly import("./permission-rule-model.js").SegmentCoverage[];
1131
- };
1132
1070
  /** Inputs to the two-phase tool gate. `adjudicate`/`resolveAsk` are pre-bound to the task abort
1133
1071
  * signal; when the caller also supplies {@link ToolGateInput.callSignal}, the Runner's closures
1134
1072
  * additionally bind their waits to that per-call signal (`AbortSignal.any` of the two), so a turn
@@ -1645,41 +1583,6 @@ export declare function createPreToolUseConstraintPolicy(preToolUse: NonNullable
1645
1583
  * walltime and no cancel, the race never fires. So the same seat bound rides here too, and the two
1646
1584
  * installations of one callback are now bounded the same way for the same reason. */
1647
1585
  timeoutMs?: number): ToolPolicy;
1648
- /**
1649
- * The mandate provenance of one call, judged from the SAME mark inputs the gate is driven with —
1650
- * the single source for "could a persisted allow rule clear this ask?". Allow rules silence the
1651
- * classifier's questions, never a mandated one, and this predicate is the mandated-family half of
1652
- * that boundary (the real-approval/governance half rides the decision's own `requiresRealApproval`
1653
- * bit, which the org layer stamps):
1654
- * · `probeMandated` — this CALL's own reversibility probe declared its demotion STRUCTURAL
1655
- * (`"probe_mandate"`), judged FIRST because it is the only per-call member here: the three below
1656
- * are properties of the TOOL and are true of every call on the seat, so a mandate that is true of
1657
- * this one call must not be shadowed by the tier that happens to carry it (#502: the built-in
1658
- * shell probe raises it for a listed reader naming a path outside the session's roots — a boundary
1659
- * the deployment declared, which is exactly what the classify tier alone cannot say);
1660
- * · `egress` — the tool's own external-write mark, judged next: it is the tool's declaration even
1661
- * when the coarse doctrine also installed a shell tier on the same seat;
1662
- * · `shellGated` + tier `"always"` — the operator's per-call confirmation doctrine
1663
- * (`"operator_always"`); the classify doctrine installs `"maybe"`, and THOSE asks stay the rule
1664
- * lane's home turf (`undefined`) — that is the don't-ask-again main case, and the per-call member
1665
- * above is deliberately the ONLY thing that carves a mandate out of it;
1666
- * · a tool's OWN `"always"`/`"maybe"` irreversibility tier without the doctrine (`"tool_marks"`).
1667
- *
1668
- * Two consumers, one derivation: the gate's silencing arm (a matching rule is disclosed as shadowed
1669
- * instead of clearing the ask) and the runner's suggestion factory (a mandated ask offers no
1670
- * "stop asking me this" option — a rule minted from it would never clear it). A drift between the
1671
- * two would let a card offer a rule the lane then refuses to honor. The per-call member reaches both
1672
- * the same way every other per-call fact does: the gate stamps it on the surviving ask, the
1673
- * synchronous sites read it off the decision they spread, and the park leg threads its own parameter.
1674
- */
1675
- export declare function persistedRuleMandateOf(marks: {
1676
- egress?: boolean;
1677
- shellGated?: boolean;
1678
- irreversibility?: "never" | "maybe" | "always";
1679
- /** #502: the surviving ask's engine-stamped `probeMandated` — see
1680
- * {@link import("./types.js").ReversibilityVerdict.mandated}. */
1681
- probeMandated?: boolean;
1682
- }): "operator_always" | "tool_marks" | "probe_mandate" | undefined;
1683
1586
  /**
1684
1587
  * The park closure's ONE structural seat — what the gate hands the durable park beyond the twelve
1685
1588
  * positional seats. Every member is optional and read by name, so a new thing the park must know
@@ -1709,4 +1612,20 @@ export declare function askCarryRowMembers(carry: AskCarry | undefined): {
1709
1612
  denialLimitFallback?: import("./auto-mode.js").DenialLimitFallback;
1710
1613
  origin?: import("./ask-origin.js").AskOrigin;
1711
1614
  };
1615
+ /**
1616
+ * The design/37 **two-phase tool gate** — the single chokepoint that makes the load-bearing invariant
1617
+ * structural ("a hook's `allow` cannot bypass the policy's `deny`/`ask`"):
1618
+ *
1619
+ * 1. **collect** — run the PreToolUse hook, threading any `updatedInput` rewrite into `currentInput`
1620
+ * and collecting `additionalContext`. A hook `deny` short-circuits to a block immediately; a hook
1621
+ * `ask` is remembered (it does not short-circuit — a later policy `deny` outranks it).
1622
+ * 2. **adjudicate** — run the tool policy on the FINAL `currentInput` (never the model's stale args),
1623
+ * fold it with any remembered hook-ask via `deny > ask > allow`, and resolve a surviving `ask`
1624
+ * through `onAsk`. The policy ALWAYS runs regardless of the hook's verdict. A policy `allow` may
1625
+ * itself carry an `updatedInput` rewrite (redact/clamp), applied last over any hook rewrite.
1626
+ *
1627
+ * Because both phases run in this one linear function, the ordering — and the "policy is final"
1628
+ * invariant — is enforced by the call stack, not by registration convention. Returns the gate result
1629
+ * for the harness `tool_call` hook plus the PreToolUse context to attach to the tool result.
1630
+ */
1712
1631
  export declare function runToolGate(input: ToolGateInput): Promise<ToolGateResult>;