@sema-agent/core 7.43.0 → 7.45.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.
Files changed (98) hide show
  1. package/CHANGELOG.md +245 -0
  2. package/dist/agents/subagent.d.ts +2 -1
  3. package/dist/agents/subagent.js +33 -14
  4. package/dist/agents/tool-filter.d.ts +65 -4
  5. package/dist/agents/tool-filter.js +127 -4
  6. package/dist/brain/errors.d.ts +23 -2
  7. package/dist/brain/errors.js +26 -2
  8. package/dist/brain/stream-engine.d.ts +2 -1
  9. package/dist/brain/stream-engine.js +10 -9
  10. package/dist/core/agent-definition.d.ts +2 -2
  11. package/dist/core/allow-entry.d.ts +25 -1
  12. package/dist/core/allow-entry.js +29 -4
  13. package/dist/core/ask-origin.d.ts +23 -4
  14. package/dist/core/ask-origin.js +10 -4
  15. package/dist/core/checkpoint-store.d.ts +28 -15
  16. package/dist/core/checkpoint-store.js +4 -13
  17. package/dist/core/decision-receipt.js +1 -1
  18. package/dist/core/effective-path-target.d.ts +7 -6
  19. package/dist/core/effective-path-target.js +3 -7
  20. package/dist/core/engine-notice.d.ts +33 -14
  21. package/dist/core/engine-notice.js +14 -7
  22. package/dist/core/gate-lanes.js +2 -0
  23. package/dist/core/gate-outcome.d.ts +5 -0
  24. package/dist/core/gate-outcome.js +2 -0
  25. package/dist/core/governance-codes.d.ts +4 -3
  26. package/dist/core/governance-codes.js +1 -0
  27. package/dist/core/hooks.d.ts +2 -0
  28. package/dist/core/memory-engine/content-origin.d.ts +0 -34
  29. package/dist/core/memory-engine/content-origin.js +9 -4
  30. package/dist/core/memory-engine/engine.d.ts +2 -2
  31. package/dist/core/memory-engine/engine.js +7 -14
  32. package/dist/core/memory-engine/file-backend.d.ts +2 -2
  33. package/dist/core/memory-engine/file-backend.js +5 -7
  34. package/dist/core/memory-engine/layout.d.ts +41 -4
  35. package/dist/core/memory-engine/layout.js +35 -5
  36. package/dist/core/permission-rules.d.ts +4 -0
  37. package/dist/core/permission-rules.js +5 -2
  38. package/dist/core/real-approval.d.ts +9 -6
  39. package/dist/core/real-approval.js +5 -5
  40. package/dist/core/runner/child-tree.d.ts +13 -0
  41. package/dist/core/runner/child-tree.js +3 -0
  42. package/dist/core/runner/contracts.d.ts +9 -18
  43. package/dist/core/runner/prepare-ask-lane.d.ts +2 -0
  44. package/dist/core/runner/prepare-ask-lane.js +2 -2
  45. package/dist/core/runner/prepare-config-doors.js +3 -1
  46. package/dist/core/runner/prepare-execution-env.js +2 -1
  47. package/dist/core/runner/prepare-gate-stations.d.ts +3 -0
  48. package/dist/core/runner/prepare-gate-stations.js +2 -1
  49. package/dist/core/runner/prepare-listings.d.ts +4 -4
  50. package/dist/core/runner/prepare-listings.js +2 -22
  51. package/dist/core/runner/prepare-park-ask.d.ts +2 -0
  52. package/dist/core/runner/prepare-park-ask.js +2 -2
  53. package/dist/core/runner/prepare-policy-chain.d.ts +2 -0
  54. package/dist/core/runner/prepare-policy-chain.js +4 -2
  55. package/dist/core/runner/prepare-task.js +10 -6
  56. package/dist/core/runner/resume-policy-outcome.js +2 -1
  57. package/dist/core/runner/run-leg.js +1 -1
  58. package/dist/core/runner/run-notification-lane.js +2 -2
  59. package/dist/core/runner/runtask.d.ts +2 -0
  60. package/dist/core/runner/runtask.js +3 -5
  61. package/dist/core/runner/steer-admission.d.ts +10 -11
  62. package/dist/core/runner/steer-admission.js +6 -8
  63. package/dist/core/runner/stream-steer-verb.d.ts +5 -4
  64. package/dist/core/runner/stream-steer-verb.js +8 -10
  65. package/dist/core/runner/sub-agent-deny-lists.d.ts +32 -0
  66. package/dist/core/runner/sub-agent-deny-lists.js +121 -0
  67. package/dist/core/runner/synthetic-tools.d.ts +1 -1
  68. package/dist/core/runner/synthetic-tools.js +3 -2
  69. package/dist/core/session-policy-store.d.ts +6 -2
  70. package/dist/core/session-policy-store.js +2 -1
  71. package/dist/core/skill-grant.d.ts +10 -2
  72. package/dist/core/skill-grant.js +20 -4
  73. package/dist/core/steer-replay.d.ts +46 -0
  74. package/dist/core/steer-replay.js +22 -0
  75. package/dist/core/task-event.d.ts +3 -2
  76. package/dist/core/task-notification.d.ts +12 -1
  77. package/dist/core/task-notification.js +13 -1
  78. package/dist/core/task-spec.d.ts +5 -3
  79. package/dist/core/task-stream.d.ts +12 -6
  80. package/dist/core/tool-errors.d.ts +2 -2
  81. package/dist/core/tool-policy.d.ts +15 -4
  82. package/dist/core/tool-policy.js +9 -13
  83. package/dist/core/tool-spec.d.ts +20 -2
  84. package/dist/core/types.d.ts +2 -2
  85. package/dist/core/types.js +1 -1
  86. package/dist/index.d.ts +7 -4
  87. package/dist/index.js +7 -4
  88. package/dist/orchestration/workflow-types.d.ts +5 -0
  89. package/dist/orchestration/workflow.d.ts +3 -2
  90. package/dist/orchestration/workflow.js +16 -7
  91. package/dist/tools/fs/removal-targets.d.ts +82 -0
  92. package/dist/tools/fs/removal-targets.js +236 -0
  93. package/dist/tools/fs/shell-read-write-targets.d.ts +27 -0
  94. package/dist/tools/fs/shell-read-write-targets.js +1 -1
  95. package/package.json +1 -1
  96. package/test/export-surface.snapshot.json +43 -5
  97. package/wire-changes/core@7.44.0.json +469 -0
  98. package/wire-changes/core@7.45.0.json +1084 -0
@@ -3,7 +3,8 @@ import { parsePermissionRule } from "./permission-rules.js";
3
3
  import { mountedToolPermissionSeat } from "./mode-policy.js";
4
4
  import { inlineUntrusted } from "./untrusted-text.js";
5
5
  import { boundInputHashOf } from "./canonical-json.js";
6
- import { allowingRows, autoStripped, compileAllowEntry, compileAllowList, inertEntryPhrase, judgeAllowEntries } from "./allow-entry.js";
6
+ import { readToolNameList } from "../agents/tool-filter.js";
7
+ import { allowingRows, autoStripped, compileAllowEntry, compileAllowList, inertEntryPhrase, judgeAllowEntries, nonListValueLabel, nonStringMemberLabel, renderListEntry } from "./allow-entry.js";
7
8
  export const SKILL_GRANT_ORIGINS = Object.freeze(["model", "user", "inherited"]);
8
9
  const FROZEN_SKILL_GRANT_ORIGINS = new Set(["model", "inherited"]);
9
10
  export function skillNamedBy(args, skills) {
@@ -12,6 +13,8 @@ export function skillNamedBy(args, skills) {
12
13
  }
13
14
  function skillGrantBinding(skill) {
14
15
  const canonical = (entries) => [...new Set((entries ?? []).map((e) => {
16
+ if (typeof e !== "string")
17
+ return nonStringMemberLabel(e);
15
18
  const p = parsePermissionRule(e);
16
19
  return p.ruleContent === undefined ? p.toolName : `${p.toolName}(${p.ruleContent})`;
17
20
  }))].sort();
@@ -44,8 +47,21 @@ export function parkedSkillApprovalRefusal(row, args, skills, skillToolName, sit
44
47
  ? `${why} — refusing pre-CAS (nothing ran; the checkpoint stays pending). Decide this checkpoint as deny and re-activate it: the new card shows the current lists.`
45
48
  : `The approved Skill call was not executed: ${why}. This approval is spent — to use "${chosen}", have the model activate it again: the new card shows its lists.`;
46
49
  }
50
+ export function readSkillTable(value) {
51
+ if (value === undefined || value === null)
52
+ return undefined;
53
+ const read = readToolNameList(value);
54
+ return read.kind === "entries" ? read.entries : [nonListValueLabel(read)];
55
+ }
47
56
  export function detachSkillLists(skills) {
48
- return skills.map((s) => (typeof s === "object" && s !== null ? { ...s, ...(Array.isArray(s.allowedTools) ? { allowedTools: [...s.allowedTools] } : {}), ...(Array.isArray(s.disallowedTools) ? { disallowedTools: [...s.disallowedTools] } : {}) } : s));
57
+ return skills.map((s) => {
58
+ if (typeof s !== "object" || s === null)
59
+ return s;
60
+ const { allowedTools: rawAllowed, disallowedTools: rawDenied, ...rest } = s;
61
+ const allowedTools = readSkillTable(rawAllowed);
62
+ const disallowedTools = readSkillTable(rawDenied);
63
+ return { ...rest, ...(allowedTools !== undefined ? { allowedTools } : {}), ...(disallowedTools !== undefined ? { disallowedTools } : {}) };
64
+ });
49
65
  }
50
66
  export function declaresSkillLists(skill) {
51
67
  return (skill.allowedTools?.length ?? 0) > 0 || (skill.disallowedTools?.length ?? 0) > 0;
@@ -74,7 +90,7 @@ export function skillDenyDecision(hit) {
74
90
  action: "deny",
75
91
  message: hit.readsAsNothing !== undefined
76
92
  ? skillDenyUnreadable(hit.skill, hit.readsAsNothing, "activation").message
77
- : `the active skill "${inlineUntrusted(hit.skill, 120)}" lists this tool in disallowed-tools (${hit.entries.map((e) => inlineUntrusted(e, 200)).join(", ")}) — refused for the rest of this run`,
93
+ : `the active skill "${inlineUntrusted(hit.skill, 120)}" lists this tool in disallowed-tools (${hit.entries.map(renderListEntry).join(", ")}) — refused for the rest of this run`,
78
94
  decisionReason: "skill",
79
95
  };
80
96
  }
@@ -88,7 +104,7 @@ export function skillRowRefusal(lane, req) {
88
104
  export function skillAllowDecision(hit, updatedInput) {
89
105
  return {
90
106
  action: "allow",
91
- message: `the active skill "${inlineUntrusted(hit.skill, 120)}" lists this tool in allowed-tools (${hit.entries.map((e) => inlineUntrusted(e, 200)).join(", ")})`,
107
+ message: `the active skill "${inlineUntrusted(hit.skill, 120)}" lists this tool in allowed-tools (${hit.entries.map(renderListEntry).join(", ")})`,
92
108
  decisionReason: "skill",
93
109
  ...(updatedInput !== undefined ? { updatedInput } : {}),
94
110
  };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Is a repeat under an already-used steer `inputId` the same instruction? ONE answer for both seats that hold a
3
+ * steer under its key — the parked queue (`appendPendingSteer`) and the live verb's accepted-input domain — and that
4
+ * one answer feeds the replay decision, the refusal's machine-readable `detail.differs` and its sentence.
5
+ *
6
+ * Both seats compare the record the CALLER sent (text, trusted, tier, actor) — never the delivered bytes: the live
7
+ * delivery folds `trusted` (the framing) and the actor (the speaker label) into its payload, so comparing payloads
8
+ * would report one changed facet as two.
9
+ */
10
+ import type { ActorAssertion } from "../internal/llm.js";
11
+ import { type SystemInjectionPriority } from "./task-notification.js";
12
+ /** The facets a steer's replay identity is made of, in the order a refusal lists them. Closed. */
13
+ export declare const STEER_REPLAY_FACETS: readonly ["text", "trusted", "priority", "actor"];
14
+ export type SteerReplayFacet = (typeof STEER_REPLAY_FACETS)[number];
15
+ /** What a seat remembers a steer by: the caller's own statement, as validated. The parked entry and the live park
16
+ * record both are this shape. An absent `priority` reads as `"next"` ({@link steerPriorityOf}). */
17
+ export interface SteerReplayRecord {
18
+ readonly text: string;
19
+ readonly trusted: boolean;
20
+ readonly priority?: SystemInjectionPriority;
21
+ readonly actor?: ActorAssertion;
22
+ }
23
+ /** The facets `repeat` differs from `held` in, in {@link STEER_REPLAY_FACETS} order. Empty = the idempotent replay. */
24
+ export declare function steerReplayDiffers(held: SteerReplayRecord, repeat: SteerReplayRecord): SteerReplayFacet[];
25
+ /** `steering.duplicate_input_id`'s machine-readable half: the facets, by name only (never the values). Always
26
+ * present on that code, never empty. */
27
+ export interface SteerReplayRefusalDetail {
28
+ readonly differs: readonly SteerReplayFacet[];
29
+ }
30
+ /** Which seat refuses: the parked queue names the key it holds; the live verb answers about the caller's own key. */
31
+ export type SteerReplaySeat = {
32
+ readonly seat: "parked";
33
+ readonly inputId: string;
34
+ } | {
35
+ readonly seat: "accepted";
36
+ };
37
+ /**
38
+ * The refusal for a repeat that is not a replay, or `undefined` for one that is. When `text` differs the repeat is
39
+ * another instruction and the caller is told to take a fresh key. When only the tier / trust / attribution differ it
40
+ * is the SAME instruction, already accepted, whose standing receipt those facets do not change — a fresh key would
41
+ * queue it a second time, so the sentence says so instead of advising one.
42
+ */
43
+ export declare function steerReplayRefusal(held: SteerReplayRecord, repeat: SteerReplayRecord, where: SteerReplaySeat): {
44
+ message: string;
45
+ detail: SteerReplayRefusalDetail;
46
+ } | undefined;
@@ -0,0 +1,22 @@
1
+ import { steerPriorityOf } from "./task-notification.js";
2
+ export const STEER_REPLAY_FACETS = Object.freeze(["text", "trusted", "priority", "actor"]);
3
+ const FACET_IS_SAME = {
4
+ text: (a, b) => a.text === b.text,
5
+ trusted: (a, b) => a.trusted === b.trusted,
6
+ priority: (a, b) => steerPriorityOf(a) === steerPriorityOf(b),
7
+ actor: (a, b) => a.actor?.id === b.actor?.id && a.actor?.hostAsserted === b.actor?.hostAsserted && a.actor?.issuer === b.actor?.issuer,
8
+ };
9
+ export function steerReplayDiffers(held, repeat) {
10
+ return STEER_REPLAY_FACETS.filter((facet) => !FACET_IS_SAME[facet](held, repeat));
11
+ }
12
+ export function steerReplayRefusal(held, repeat, where) {
13
+ const differs = steerReplayDiffers(held, repeat);
14
+ if (differs.length === 0)
15
+ return undefined;
16
+ const seat = where.seat === "parked" ? `parked under inputId "${where.inputId}"` : "accepted under this inputId";
17
+ const listed = differs.join(", ");
18
+ const message = differs.includes("text")
19
+ ? `a different steering instruction is already ${seat} (this repeat differs in: ${listed}) — re-issue this one with a fresh inputId (an identical payload would have been an idempotent retry)`
20
+ : `the same steering instruction is already ${seat}; this repeat differs only in: ${listed}, which cannot change after acceptance — sending it again under another inputId would queue it a second time; to confirm the standing receipt, replay it with its original values`;
21
+ return { message, detail: { differs } };
22
+ }
@@ -94,8 +94,9 @@ export type BrainStatusPhase = "rate_limited" | "retrying" | "reconnecting" | "c
94
94
  * {@link BrainStatus.errorStatus}; this bucket is the reason a consumer RENDERS and the only carrier for the
95
95
  * transport classes, which have no status at all.) Values are about the SHAPE of the failure, never its
96
96
  * provider taxonomy:
97
- * - `connect_refused` — the attempt got a definite negative about the target itself (nothing accepts
98
- * at that address, or the name has no address). This is the class the SHORT retry lane serves.
97
+ * - `connect_refused` — the attempt got a definite negative about the way to the target (nothing accepts
98
+ * at that address, the name has no address, or the proxy on the way refused the tunnel). This is the class
99
+ * the SHORT retry lane serves.
99
100
  * - `transport` — any other transport-level failure: a connect timeout, a reset, a mid-stream
100
101
  * tear. No verdict about the target; the full ladder applies.
101
102
  * - `stall` — no failure was observed on the link at all: THIS process cancelled its own
@@ -32,10 +32,21 @@ export declare const SYSTEM_INJECTION_PRIORITIES: readonly SystemInjectionPriori
32
32
  export declare function isSystemInjectionPriority(value: unknown): value is SystemInjectionPriority;
33
33
  /** The ONE reading of a steer's priority: a parked row or an accepted input that carries none means `"next"`
34
34
  * (the default the live admission has always applied) — so a retry that spells the default and a row parked
35
- * without it are the same instruction, whichever side normalized. */
35
+ * without it are the same instruction, whichever side normalized. A tier outside the closed set throws
36
+ * (`steering.invalid_content`, the sentence names the set); `null` is such a tier, not an absent one. */
36
37
  export declare function steerPriorityOf(x: {
37
38
  readonly priority?: SystemInjectionPriority;
38
39
  }): SystemInjectionPriority;
40
+ /** The two queues a person's input rides on a live run: the `steer` lane (the running turn's next boundary) and the
41
+ * `followUp` lane (the run's would-otherwise-stop seat). They are also the two families of the stranded-input account — an
42
+ * input's account is the one of the lane it was queued on (`USER_INPUT_UNDRAINED_FAMILIES`). */
43
+ export type UserInputLane = "steer" | "followUp";
44
+ /** The ONE reading of "which lane carries this tier": `"later"` rides the follow-up lane (never folded into work in
45
+ * progress), `"next"` and `"now"` ride the steer lane (`"now"` additionally cuts the running turn). Both injection
46
+ * seats — the steer verb and the notification lane — branch on it. A parked row that carries no tier reads through
47
+ * {@link steerPriorityOf} first: `injectionLaneOf(steerPriorityOf(row))`. A tier outside the closed set throws
48
+ * (`steering.invalid_content`, the same check and sentence as {@link steerPriorityOf}). */
49
+ export declare function injectionLaneOf(priority: SystemInjectionPriority): UserInputLane;
39
50
  export interface TaskNotificationPayload {
40
51
  task_id: string;
41
52
  /** design/144 §2: `"external"` is CORE-MINTED ONLY — `TaskStream.notify()` casts it onto every
@@ -10,8 +10,20 @@ export const SYSTEM_INJECTION_PRIORITIES = ["now", "next", "later"];
10
10
  export function isSystemInjectionPriority(value) {
11
11
  return typeof value === "string" && SYSTEM_INJECTION_PRIORITIES.includes(value);
12
12
  }
13
+ function requireSystemInjectionPriority(value) {
14
+ if (isSystemInjectionPriority(value))
15
+ return value;
16
+ const shown = typeof value === "string" ? JSON.stringify(value.length > 24 ? `${value.slice(0, 24)}…` : value) : value === null ? "null" : typeof value;
17
+ const refusal = new Error(`a steer priority must be one of ${SYSTEM_INJECTION_PRIORITIES.join("/")}, got ${shown}`);
18
+ refusal.code = "steering.invalid_content";
19
+ throw refusal;
20
+ }
13
21
  export function steerPriorityOf(x) {
14
- return x.priority ?? "next";
22
+ return x.priority === undefined ? "next" : requireSystemInjectionPriority(x.priority);
23
+ }
24
+ const LANE_OF_PRIORITY = { now: "steer", next: "steer", later: "followUp" };
25
+ export function injectionLaneOf(priority) {
26
+ return LANE_OF_PRIORITY[requireSystemInjectionPriority(priority)];
15
27
  }
16
28
  const TASK_NOTIFICATION_TAGS = [
17
29
  "task-notification",
@@ -551,9 +551,11 @@ export interface TaskSpec {
551
551
  * upstream): an `allowTools` entry naming a tool that does not exist is ITEM-FILTERED at spawn (the
552
552
  * agent stays listed and delegable; the only host disclosure is a prepare-time HEURISTIC advisory
553
553
  * via `RunnerDeps.onError` phase `"config"` for entries unknown to the parent's assembled roster —
554
- * zero model-facing warning, the verified upstream shape); a `denyTools` entry naming an
555
- * unknown tool is REJECTED at task start (`config.agent.unknown_tool` — a deny-typo silently WIDENS,
556
- * the opposite failure direction, sema extension with no upstream deny-list to defer to); and
554
+ * zero model-facing warning, the verified upstream shape); a `denyTools` entry is read as the
555
+ * reference reads it (`Tool(content)` hides the whole `Tool`, with a host notice) and judged once, here and for the
556
+ * delegation tool's own lists alike: a spelling that names no tool, or a stale one (another case of a mounted tool, a
557
+ * retired name), is REJECTED at task start (`config.agent.unknown_tool`), any other name no tool carries is told to the
558
+ * host and hides nothing; and
557
559
  * providing this field with NO delegation tool mounted is rejected too
558
560
  * (`config.agents.no_delegation_tool`) — never a silent no-op. POLICY-NEUTRAL: a
559
561
  * roster listing only; the 1.294 tighten-only parent-policy inheritance is applied at spawn time,
@@ -43,15 +43,20 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
43
43
  * that arrives while the task is LIVE was the only one that injected twice.
44
44
  * - **Absent ⇒ nothing changes**: a uuidv7 is minted for the event, nothing is recorded for the call,
45
45
  * and the delivered bytes are what they always were. Every pre-existing caller is on this arm.
46
- * - **Replay ⇒ idempotent no-op**: re-steering an id this stream already ACCEPTED, with an identical
47
- * payload (same text, same `trusted`, same `actor`), injects nothing and emits no second
46
+ * - **Replay ⇒ idempotent no-op**: re-steering an id this stream already ACCEPTED, with the same
47
+ * steer (same text, `trusted`, tier — absent reads `next` — and `actor`), injects nothing and emits no second
48
48
  * `human_input` frame. What is remembered is exactly what QUEUED: a delivery that was refused
49
49
  * (not running) can be retried under its own id, and a call whose DELIVERED payload is
50
50
  * whitespace-only — which the harness discards without minting a frame; note a `trusted` steer is
51
51
  * wrapped first, so it queues even for blank text — reserves nothing, leaving that id usable.
52
- * - **Same id, DIFFERENT instruction ⇒ typed throw** `steering.duplicate_input_id`: a key is not
52
+ * - **Same id, not the same steer ⇒ typed throw** `steering.duplicate_input_id`: a key is not
53
53
  * evidence of a replay, and two callers colliding on one id must not silently lose the second
54
- * (the parked leg's `appendPendingSteer` refuses it identically). Re-issue under a fresh id.
54
+ * (the parked leg's `appendPendingSteer` judges and refuses it identically). The error carries
55
+ * `detail.differs` — the facets that differ (closed `STEER_REPLAY_FACETS`: `text`, `trusted`,
56
+ * `priority`, `actor`), compared on what the caller SENT, never on the framed bytes. With `text`
57
+ * among them it is another instruction: re-issue it under a fresh id. Without, it is the accepted one
58
+ * re-sent at another tier / trust / attribution, which acceptance does not change: a fresh id would
59
+ * queue it twice, so replay it with its original values to confirm the receipt.
55
60
  * - **Bad value ⇒ typed throw** `steering.invalid_content`, never a silent fallback to "no id": the
56
61
  * value domain is the parked leg's (a non-empty string of at most `MAX_STEER_INPUT_ID_CHARS`
57
62
  * characters), so one key is accepted or
@@ -107,8 +112,9 @@ export interface TaskStream extends AsyncIterable<TaskEvent> {
107
112
  * relaying steer must gate this option at its own face — relay IS authorization.
108
113
  * An unknown value throws typed `steering.invalid_content` (bad-value loudness). The replay
109
114
  * identity (`inputId` idempotency) includes the NORMALIZED tier: the same text replayed under
110
- * the same id at a different tier refuses `steering.duplicate_input_id` — an "idempotent
111
- * success" that silently skipped the interrupt would be a disposition lie.
115
+ * the same id at a different tier refuses `steering.duplicate_input_id` (`detail.differs:
116
+ * ["priority"]`) — an "idempotent success" that silently skipped the interrupt would be a
117
+ * disposition lie.
112
118
  *
113
119
  * design/373 §4.3 (D2, ruling of 2026-08-24) — a deployment `userPromptSubmit` hook SCREENS this verb:
114
120
  * the steer face is a SERVICE entrance (third-party callers reach a running run through it), so
@@ -123,8 +123,8 @@ export type WorkerErrorClass = "budget" | "limit" | "output" | "suspend" | "revi
123
123
  * The `limits.` namespace splits into the `budget` and `limit` classes by exact code — see
124
124
  * {@link EXACT_CODE_CLASS}. Operation-level dotted codes that are surfaced to a *caller* and never become a
125
125
  * task outcome are deliberately OUT of scope: `steering.*` (`steering.not_running`/`steering.invalid_content`/
126
- * `steering.duplicate_input_id`/`steering.blocked_by_hook`, rejected to the `steer()` caller — the fourth also
127
- * rides the resume face as a `CheckpointError` code) and `mcp.*` (`mcp.server_unavailable`, an `onWarn` warning code) — neither
126
+ * `steering.duplicate_input_id`/`steering.blocked_by_hook`, rejected to the `steer()` caller — the third also
127
+ * rides the parked queue's `setPendingSteer` face and the fourth the resume face, as `CheckpointError` codes) and `mcp.*` (`mcp.server_unavailable`, an `onWarn` warning code) — neither
128
128
  * reaches `TaskResult.errorCode`, so a caller will never pass them here. A genuinely unmapped code → `"unknown"` (which therefore means
129
129
  * "known-but-foreign or no code", e.g. a leaked fs/Node code, NOT "an OUR terminal class we forgot to add").
130
130
  */
@@ -4,6 +4,7 @@ import { type Settlement } from "./gate-outcome.js";
4
4
  export { policyCannotAnswer, rowDemandsAPerson } from "./real-approval.js";
5
5
  import { type DecisionReason } from "./decision-receipt.js";
6
6
  export { isEngineRefusal } from "./decision-receipt.js";
7
+ import { type RemovalGuardSeat } from "../tools/fs/removal-targets.js";
7
8
  /** A tool call presented to a policy before it executes. */
8
9
  /** design/388 B6 — the per-call face (see {@link ToolCallRequest.face}). */
9
10
  export interface ToolCallFace {
@@ -69,6 +70,15 @@ export interface ToolCallRequest {
69
70
  * window — at that declaration, not here.
70
71
  */
71
72
  cwd?: string;
73
+ /**
74
+ * The root this leg's tools resolve a ROOT-relative spelling against (a search tool's relative `path`, a
75
+ * pattern with no `path`), stamped beside {@link cwd} at every Runner adjudication seat — the same
76
+ * canonical spelling as `cwd` (the hands' own root, the value `cwd` starts at). Present whenever the leg
77
+ * mounts file hands, read-only hands included; absent on a hands-less leg and on a bare request. A path
78
+ * guard whose deployment supplied no base of its own resolves the call's target against `root` / `cwd`.
79
+ * Read-only, like `cwd`.
80
+ */
81
+ root?: string;
72
82
  /**
73
83
  * The CANONICAL directories THIS RUN'S PROMPT ADVERTISES AS WRITABLE — the admitted list of the root
74
84
  * fence's advertised-writable-directory seat (the memory engine's write home, the deployment's
@@ -397,12 +407,12 @@ export type PermissionResult = {
397
407
  /** The ask's whole class set, in {@link import("./ask-origin.js").ASK_CLASSES} order (see
398
408
  * {@link AskRequest.classes}). Stamped beside {@link askClass}, under the same rule. */
399
409
  classes?: readonly import("./ask-origin.js").AskClass[];
400
- /** WHICH integrity guard minted this ask — the unverifiable recursive delete or the session-transcript
401
- * write. ENGINE-STAMPED by the two guard policies; a fold-internal fact the class derivation reads
402
- * ({@link import("./ask-origin.js").classifyAsk}) so the two guards, which mint the same
410
+ /** WHICH integrity guard minted this ask — a removal of a protected location, an unverifiable recursive delete
411
+ * or the session-transcript write. ENGINE-STAMPED by the guard policies; a fold-internal fact the class
412
+ * derivation reads ({@link import("./ask-origin.js").classifyAsk}) so the guards, which mint the same
403
413
  * `requiresRealApproval` ask, are told apart by a fact and not by their prose. Never copied onto the
404
414
  * approval request or the park row. */
405
- guard?: "unverifiable_delete" | "transcript_write" | "artifact_shared_read";
415
+ guard?: "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "artifact_shared_read";
406
416
  /** The call could not be READ against a rule that may reach it — a content-form deny row, a content-form
407
417
  * ask row, or a persisted-rule row (the lexer's word). ENGINE-STAMPED at the three unreadable mint sites;
408
418
  * the class derivation reads it as `rule_unreadable` (a mode may release it, a person may clear it, no
@@ -1082,6 +1092,7 @@ export declare function createUnverifiableDeletePolicy(opts?: {
1082
1092
  safeVars?: readonly string[];
1083
1093
  /** Override the shell tool names this gate parses (default `Bash`). */
1084
1094
  tools?: string[];
1095
+ removalSeat?: RemovalGuardSeat;
1085
1096
  }): ToolPolicy;
1086
1097
  export declare function createTranscriptIntegrityPolicy(opts?: {
1087
1098
  /** Transcript directories to protect. Default: `($AGENT_DATA_DIR ?? ~/.ai-agent)/sessions`. */
@@ -21,6 +21,7 @@ import { isNamespacedCoveringRuleName, namespacedRuleNameCovers, parsePermission
21
21
  import { protocolOf } from "./protocol-table.js";
22
22
  import { isAbsoluteForFamily, isAbsolutePathForm, joinForFamily, normalizeAbsPathLexically, pathFamilyOf, writeTargetPath } from "../tools/fs/safety.js";
23
23
  import { ASSIGNMENT_PREFIX, writtenAssignmentPrefix } from "../tools/fs/bash-program-position.js";
24
+ import { removalReadingOf } from "../tools/fs/removal-targets.js";
24
25
  const nameListHolds = (set, req) => heldBy("policy.nameLists", set, req);
25
26
  const shellToolsListHolds = (set, req) => heldBy("policy.shellToolsList", set, req);
26
27
  export function advertisedWritableRootsSeat(seat) {
@@ -920,28 +921,23 @@ function hasRecursiveForce(argvTail) {
920
921
  export function createUnverifiableDeletePolicy(opts) {
921
922
  const safeVars = new Set([...UNVERIFIABLE_DELETE_SAFE_VARS, ...(opts?.safeVars ?? [])]);
922
923
  const shellTools = canonicalToolNameSet(opts?.tools);
924
+ const unverifiable = (command, finding = findUnverifiableRecursiveDelete(command, safeVars)) => (finding === undefined ? ALLOW : removalAsk("unverifiable_delete", finding));
923
925
  return brandPolicyAskClass({
924
- check(req) {
926
+ check(req, signal) {
925
927
  if (!shellToolsListHolds(shellTools, req))
926
928
  return ALLOW;
927
929
  const command = req.args?.command;
928
930
  if (typeof command !== "string")
929
931
  return ALLOW;
930
- const finding = findUnverifiableRecursiveDelete(command, safeVars);
931
- if (finding === undefined)
932
- return ALLOW;
933
- return {
934
- action: "ask",
935
- decisionReason: "safety",
936
- requiresRealApproval: true,
937
- guard: "unverifiable_delete",
938
- message: `Unverifiable recursive delete (fail-closed unless cleared): ${finding}. ` +
939
- `Re-run the delete with the resolved literal path written into the command itself ` +
940
- `(or assign the variable in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`,
941
- };
932
+ const removal = removalReadingOf(command, req, opts?.removalSeat);
933
+ return removal === undefined ? unverifiable(command) : removal.judge(signal).then((found) => (found === undefined ? unverifiable(command) : removalAsk(found.guard, found.text)));
942
934
  },
943
935
  }, "external_authority");
944
936
  }
937
+ function removalAsk(guard, text) {
938
+ const message = guard === "dangerous_delete" ? `Dangerous removal: ${text}. No permission mode, allow rule or classifier clears this — only a person confirming this call does.` : `Unverifiable recursive delete (fail-closed unless cleared): ${text}. Re-run the delete with the resolved literal path written into the command itself (or assign the variable a literal path in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`;
939
+ return { action: "ask", decisionReason: "safety", requiresRealApproval: true, guard, message };
940
+ }
945
941
  function pathSegments(p) {
946
942
  return p.split(/[\\/]/).filter(Boolean);
947
943
  }
@@ -175,18 +175,36 @@ export interface ToolSpec<TParams extends TSchema = TSchema> {
175
175
  * offered pool a child of that type actually mounts. Filled by `createSubagentTool` beside
176
176
  * `agentListing`; a type with neither list gets the whole offered pool.
177
177
  *
178
- * Read by ONE consumer: the memory content-origin face, which classifies a delegation RESULT by the
178
+ * Read by the memory content-origin face, which classifies a delegation RESULT by the
179
179
  * child's tool face. A child that can reach a network or protocol tool returns content from outside
180
180
  * the trust boundary just as surely as calling that tool here would, and the parent's transcript is
181
181
  * where it lands. Static by construction — the child's face is known from its definition, so no
182
- * runtime tracking of what the child actually did is involved (that is the v2 ticket).
182
+ * runtime tracking of what the child actually did is involved (that is the v2 ticket). `authored`
183
+ * marks the entries minted from a definition a caller wrote on a tool a deployment mounted (not the
184
+ * engine's built-ins, the general-purpose alias, fork, or the engine's nested copy of the tool for a
185
+ * delegated child); prepare's deny-name check judges only those.
183
186
  */
184
187
  agentToolFaces?: ReadonlyArray<{
185
188
  name: string;
186
189
  allowTools?: readonly string[];
187
190
  denyTools?: readonly string[];
188
191
  canRedelegate?: boolean;
192
+ authored?: true;
189
193
  }>;
194
+ /**
195
+ * The tool-level `denyTools` list of the delegation tool (`SubagentToolOptions.denyTools`, applied when no agent definition is
196
+ * selected), exactly as written, filled by `createSubagentTool` beside {@link agentToolFaces}; absent when none was written
197
+ * and on the engine's nested copy for a delegated child. Read by prepare's deny-name check, which judges it with
198
+ * the `authored` entries of the faces.
199
+ */
200
+ agentToolLevelDenyTools?: readonly string[];
201
+ /**
202
+ * The tool-level `allowTools` list of the delegation tool (`SubagentToolOptions.allowTools`, applied when no agent definition is
203
+ * selected), as the tool copied it, filled by `createSubagentTool` beside {@link agentToolLevelDenyTools}; absent when none was
204
+ * written and on the engine's nested copy for a delegated child. Read by prepare's allowed-list judgment: a value that is not a
205
+ * list of strings is refused before the run.
206
+ */
207
+ agentToolLevelAllowTools?: readonly string[];
190
208
  /**
191
209
  * design/178 §3 (ruled 2026-08-08) — the POOL a delegated child draws from, as the delegation tool
192
210
  * captured it. Read together with {@link agentToolFaces} by the memory content-origin face: the face
@@ -29,6 +29,6 @@ export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js"
29
29
  export type { BackgroundChildEvent, DelegationLifecycleEvent } from "./delegation-frames.js";
30
30
  export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
31
31
  export type { ProjectMemoryLoad, ResumePreflightInfo, ResumePreflightVerdict, RunnerDeps } from "./runner-deps.js";
32
- export type { EngineNotice, OwedUserInputAccount, UserSteerUndrainedCause } from "./engine-notice.js";
33
- export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_STEER_UNDRAINED_CAUSES } from "./engine-notice.js";
32
+ export type { EngineNotice, OwedUserInputAccount, UserInputUndrainedCause } from "./engine-notice.js";
33
+ export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
34
34
  export type { AgentTool, Model, StreamFn, ThinkingLevel, ToolInputValidationContext, ToolInputVerdict };
@@ -1,4 +1,4 @@
1
1
  export { MODEL_ROLES } from "./model-seat.js";
2
2
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./runtime-caps.js";
3
3
  export { __resetMalformedDelegationSeatAnnouncement, deliverDelegationLifecycle } from "./delegation-frames.js";
4
- export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_STEER_UNDRAINED_CAUSES } from "./engine-notice.js";
4
+ export { __resetMalformedNoticeSeatAnnouncement, deliverEngineNotice, owedUserInputCounts, parentLegIds, settleOwedUserInput, undrainedUserInputNotices, USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./engine-notice.js";
package/dist/index.d.ts CHANGED
@@ -42,7 +42,7 @@ export { StdioLspTransport, type LspChildProcess } from "./engine/lsp/stdio-lsp-
42
42
  export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
43
43
  export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, type ModelRole, type RoleSpec, type ModelRoles, type ResolvedRole, type ModelMention, } from "./core/roles.js";
44
44
  export { selectModel, selectModelOrThrow, type ModelCriteria, type ModelTier } from "./core/select-model.js";
45
- export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, type BrainErrorCode } from "./brain/errors.js";
45
+ export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, PROXY_TUNNEL_REFUSED, type BrainErrorCode } from "./brain/errors.js";
46
46
  export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
47
47
  export type { RepetitionEvent, RepetitionInspection } from "./brain/repetition.js";
48
48
  export { computeCostMicroUsd, isModelPriced, modelCostToPricing, type ModelPricing, type TokenCounts, } from "./core/pricing.js";
@@ -63,7 +63,8 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
63
63
  export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice, type McpInjectionDropReason, type McpInjectionDropFacts } from "./core/mcp-injection-drop.js";
64
64
  export { askUnresolvableNotice, type AskUnresolvableFacts } from "./core/ask-unresolvable-notice.js";
65
65
  export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
66
- export { USER_STEER_UNDRAINED_CAUSES, type UserSteerUndrainedCause } from "./core/engine-notice.js";
66
+ export { USER_INPUT_UNDRAINED_CAUSES, type UserInputUndrainedCause, USER_INPUT_UNDRAINED_FAMILIES } from "./core/engine-notice.js";
67
+ export { STEER_REPLAY_FACETS, type SteerReplayFacet } from "./core/steer-replay.js";
67
68
  export { TOOL_TURN_INCOMPLETE_CAUSES, type ToolTurnIncompleteCause } from "./internal/llm.js";
68
69
  export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
69
70
  export { TERMINAL_CAUSE_IS_REPLAYABLE, type TerminalFailureDetail, type TerminalBlockedDetail, PROMPT_BLOCK_CAUSES, type PromptBlockCause, isPromptBlockCause } from "./core/terminal-cause.js";
@@ -145,7 +146,7 @@ export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS, type RuleToolNameVerdict }
145
146
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
146
147
  export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, type TaskNotificationPayload, type TaskNotificationStatus, type ExternalNotificationInput, type SystemInjection, type SystemInjectionPriority, type NotificationInjectionOutcome, // the injector's outcome words (`parked_durably` = the session's durable box took the frame)
147
148
  NOTIFICATION_INJECTION_OUTCOMES, // …and their value half + guard, so a host wiring its own uplink validates a reported outcome without duplicating the vocabulary
148
- isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
149
+ isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, injectionLaneOf, type UserInputLane, AGENT_MESSAGE_TAG, renderAgentMessageFrame, type SemaProvenance, HANDBACK_STATES, type HandbackState, COMPACTION_KINDS, type CompactionKind, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
149
150
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, type ToolFamily, type ToolMountTag, type ToolApprovalCard, type ToolPathAccess, type ToolPathBase, type ToolPathAbsence, type ToolPathTarget, type ToolCallPathTarget, type ToolRosterPathTarget, pathTargetSlotOnly, type ToolRuleFace, type ToolRenderHints, type ToolFaceDeclaration, type ToolCatalogEntry, } from "./core/tool-face.js";
150
151
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, type ToolCallLike, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
151
152
  export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, type RosterSource, type ToolIdentity, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, type RosterBoundMembers, type RosterBoundCode, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
@@ -206,7 +207,8 @@ export { ALLOW_RULE_MEMBERS, type AllowRuleMember, type AllowRuleShadow } from "
206
207
  export { mintNamespacePrefix } from "./core/protocol-naming.js";
207
208
  export { readDenyClassifierRules, renderClassifierDenyRules, type DerivedDenyRule } from "./core/auto-mode-prompt.js";
208
209
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource, type AutoModeDenySource } from "./core/runtime-caps.js";
209
- export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_PARTIES, type SettlementParty, isSettlementParty, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, type ModeRelease, type ModeRefusal, screenGateOutcome } from "./core/gate-outcome.js";
210
+ export { SETTLEMENT_KINDS, type SettlementKind, isSettlementKind, type Settlement, SETTLEMENT_PARTIES, type SettlementParty, isSettlementParty, HOST_DECIDERS, type HostDecider, isHostDecider, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, type DeniedBy, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, type ClassifierDenyCause, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, type GateDisposition, type GateOutcome, type ModeRelease, type ModeRefusal, screenGateOutcome } from "./core/gate-outcome.js";
211
+ export { policyCannotAnswer, type HeldQuestion } from "./core/real-approval.js";
210
212
  export { type AskCarry } from "./core/hooks.js";
211
213
  export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps, type SwappableDepSeat, type SwappableDeps } from "./core/swappable-deps.js";
212
214
  export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, classifierParseFailureDenyMessage, AUTO_MODE_PARSE_FAILURES, isAutoModeParseFailure, type AutoModeParseFailure, type AutoModeUnavailableCause, AUTO_MODE_CLASSIFIER_FALLBACKS, isAutoModeClassifierFallback, AUTO_MODE_FALLBACK_CAUSES, isAutoModeFallbackCause, type AutoModeClassifierFallback, type AutoModeFallbackCause, type AutoModeClassifierRound, type AutoModeLadderRung, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassified, type AutoModeClassifyFn, type AutoModeClassifyInput, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, type AutoModeDenialTracker, type AutoModeDenialLimitOptions, type DenialLimitCounts, type DenialLimitFallbackFace, type UnarmedDenialLimitFallback, type DenialLimitFallback, type DenialLimitVerdict, } from "./core/auto-mode.js";
@@ -252,6 +254,7 @@ export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreTo
252
254
  export { HOOK_FAMILIES, HOOKS_INVALID_CODE, type HookFamily, type WiringManifestHookEntry } from "./core/hook-seats.js";
253
255
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, MEMORY_PROJECT_KEY_ABSENT_REASONS, type MemoryProjectKeyAbsentReason, type MemoryProjectKey, } from "./core/memory.js";
254
256
  export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, type OriginClearanceRow, type OriginClearanceEvent, type OriginClearanceShadow, committedDistilledOf, distilledEquals, type MemoryEntryDistilled, type MemoryEntryDistilledInput, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, type ConsolidationGateRead, type ConsolidationGateRow, type ConsolidationIntent, type ConsolidationIntentCredentialRow, type ConsolidationLeaseSeat, type ConsolidationProductProposal, type ConsolidationProposal, type MemoryConsolidationOptions, type ConsolidationCommitReceipt, type ConsolidationReconcileReport, type ConsolidationResolveReceipt, type ConsolidationPlanSummary, type ConsolidationPlanFoldEvidence, type SessionMemoryStatus, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, type CleanArmLeakFinding, type CleanArmLeakVerdict, type MemoryDistillerPurityContract, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, type ConsolidationDistillFn, type ConsolidationDriveCycleRow, type ConsolidationDriveEngine, type ConsolidationDriveResult, type ConsolidationFoldState, type DistillerCandidate, type DistillerChatAnswer, type DistillerChatFn, type DistillerChatRequest, type FuseSchedule, type LlmConsolidationPlan, type LlmConsolidationPlanArm, type LlmConsolidationPlanProduct, type LlmDistillerContract, type MintLlmConsolidationPlanResult, type PlanParseRepairs, type SanitizedLlmGroups, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, type ConsolidationDriverEngine, type ConsolidationDriverRunRow, type ConsolidationRunReceipt, type ConsolidationRunStopReason, type RunMemoryConsolidationOptions, isInstructionEntry, type MemoryEntryOrigin, type MemoryOriginCause, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, type SessionCaptureOptOutRecord, type SessionCaptureOptOutMarkOutcome, type SessionCaptureRecordStore, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, type ControlPlaneRebuildReceipt, type StrictControlPlaneLedger, type ChallengeAssignment, type ChallengeEvent, type ChallengedHistoryRow, type LineagePendingTxn, type LineagePromotion, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type CleanMemorySearchHit, type ExposedMemorySearchHit, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, type MemoryGetDetails, type MemoryIndexDetails, type MemoryIndexRow, type CleanMemoryIndexRow, type ExposedMemoryIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, type MemoryAnnouncement, type ScanFinding, type MemoryEngineOptions, type MemoryInjection, type EntryProvenanceAccount, type TransferEvidence, type CommittedBinding, type CommittedEntrySnapshot, type CommittedScopeSnapshots, type EntryCustodyReport, erasureSelectHash, type EraseMemoryEntriesInput, type ErasureSelect, type ErasedBinding, type MemoryErasureAttestation, computeMemoryBundleHash, type MemoryExportBundle, type MemoryImportReport, type MemoryExportSnapshot, type MemoryBundleImportPlan, type BundleChallengeRow, type BundleLineageRow, type BundlePollutedSession, type MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, type MemoryScopeEnumeration, type ScoredMemoryEntry, type NotePatch, type PatchReport, type MaterializedFile, type MemorySessionHandle, type HarvestReport, type HarvestRejection, type HarvestRejectionCode, type ParsedEntryFile, type ScannedEntryFile, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, type ParsedScopeKey, migrateScope, type MigrateScopeReport, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, type RemoteMemoryFile, type RemoteMemoryBaseline, type RemoteMaterialization, type RemoteHarvestResult, type InboundEntryFinding, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, type MemorySyncCursor, type MemorySyncConflict, type MemorySyncPlan, type RecallSource, syncMemoryScope, type MemorySyncTransport, type MemorySyncRequestBody, type MemorySyncResponseBody, type MemorySyncClientConflict, type SyncMemoryScopeOptions, type MemorySyncClientResult, } from "./core/memory-engine/index.js";
257
+ export { STORE_FORM_REFUSAL_CODES, TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY, SCOPE_HOME_FORMS, type StoreFormRefusalCode, type StoreFormRefusalDetail, type StoreFormRefusal, type ScopeHomeForm } from "./core/memory-engine/layout.js";
255
258
  export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, type SharedMemoryStoreProvider, type SharedMemoryStoreReader, type SharedMemoryPagedList, type SharedMemoryStoreInfo, type SharedMemoryDocumentEntry, type SharedMemorySnapshot, type SharedMemoryRequestContext, type MemoryListDetails, type MemoryReadDetails, } from "./core/shared-memory/types.js";
256
259
  export { sharedMemoryStoreContract, type SharedMemoryFixture, type SharedMemoryStoreContractHooks, } from "./core/shared-memory/contract.js";
257
260
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ export { StdioLspTransport } from "./engine/lsp/stdio-lsp-transport.js";
29
29
  export { encodeFrame, createFrameDecoder } from "./engine/lsp/frame-decoder.js";
30
30
  export { resolveModel, resolveTaskModel, parseModelMention, expandTiers, DEFAULT_TIER_ORDER, CC_MODEL_TIER_ALIASES, ROLE_TIER_DEFAULTS, MODEL_ROLES, } from "./core/roles.js";
31
31
  export { selectModel, selectModelOrThrow } from "./core/select-model.js";
32
- export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE } from "./brain/errors.js";
32
+ export { BrainError, classifyHttp, isProviderEchoShape, PROVIDER_ECHO_SHAPE, PROXY_TUNNEL_REFUSED } from "./brain/errors.js";
33
33
  export { looksDegenerate, inspectDegenerate, trimDegenerateTail } from "./brain/repetition.js";
34
34
  export { computeCostMicroUsd, isModelPriced, modelCostToPricing, } from "./core/pricing.js";
35
35
  export { cacheFamilyOf, promptTokensOf, uncachedInputTokensOf } from "./core/runner/usage-accounting.js";
@@ -49,7 +49,8 @@ export { MCP_FAILURE_KINDS, MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, classify
49
49
  export { MCP_INJECTION_DROP_REASONS, MCP_INJECTION_DROP_TEXT, mcpInjectionDroppedNotice } from "./core/mcp-injection-drop.js";
50
50
  export { askUnresolvableNotice } from "./core/ask-unresolvable-notice.js";
51
51
  export { ASK_UNRESOLVABLE_CAUSES } from "./core/ask-unresolvable-notice.js";
52
- export { USER_STEER_UNDRAINED_CAUSES } from "./core/engine-notice.js";
52
+ export { USER_INPUT_UNDRAINED_CAUSES, USER_INPUT_UNDRAINED_FAMILIES } from "./core/engine-notice.js";
53
+ export { STEER_REPLAY_FACETS } from "./core/steer-replay.js";
53
54
  export { TOOL_TURN_INCOMPLETE_CAUSES } from "./internal/llm.js";
54
55
  export { DURABLE_MANDATE_SOURCES } from "./core/tool-policy.js";
55
56
  export { TERMINAL_CAUSE_IS_REPLAYABLE, PROMPT_BLOCK_CAUSES, isPromptBlockCause } from "./core/terminal-cause.js";
@@ -117,7 +118,7 @@ export { createFsWriteGatePolicy, WRITE_EXEMPT_DIR_COVERS_ROOT_CODE } from "./co
117
118
  export { RETIRED_TOOL_NAMES } from "./core/tool-name-aliases.js";
118
119
  export { judgeRuleToolName, RULE_TOOL_NAME_VERDICTS } from "./core/tool-name-aliases.js";
119
120
  export { DEFAULT_SUBAGENT_TOOL_NAME } from "./agents/subagent.js";
120
- export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
121
+ export { renderTaskNotificationXml, RESUPPLIED_FRAME_PREAMBLE, taskNotificationDedupKey, isDelegatedAgentTerminal, isTerminalTaskNotification, SystemInjectionQueue, NOTIFICATION_INJECTION_OUTCOMES, isNotificationInjectionOutcome, SYSTEM_INJECTION_PRIORITIES, isSystemInjectionPriority, steerPriorityOf, injectionLaneOf, AGENT_MESSAGE_TAG, renderAgentMessageFrame, HANDBACK_STATES, COMPACTION_KINDS, handbackStateOf, terminalFrameFacets, } from "./core/task-notification.js";
121
122
  export { TOOL_FAMILIES, TOOL_MOUNT_TAGS, TOOL_APPROVAL_CARDS, TOOL_PATH_ACCESSES, TOOL_PATH_BASES, TOOL_PATH_ABSENCES, TOOL_WIRE_NAME_MAX_CHARS, TOOL_CONTRACT_MAX_CHARS, TOOL_CARD_ID_MAX_CHARS, TOOL_KEY_MAX_CHARS, TOOL_KEYS_MAX, RENDER_HINT_MAX_CHARS, RENDER_HINT_ACTIVITY_MAX_CHARS, RENDER_HINT_MAX_LIST, pathTargetSlotOnly, } from "./core/tool-face.js";
122
123
  export { describeToolCatalog, catalogEntriesNamed, catalogToolNames, catalogRuleFaceOf, pathTargetOf, pathTargetValue, protectivePathTargetOf, declaredPathTargetOf, BARE_REQUEST_CODE, isProtectedWrite, isDeclaredWrite, fileOpAccessOf, pathConfinableWriteToolNames, pathTargetingToolNames, compactableToolNames, budgetExemptToolNames, handBandEffects, engineCardTypes, predictMountedToolNames, HANDS_BAND_TAGS, MOUNT_TAG_IN_HANDS_BAND, } from "./core/tool-registry.js";
123
124
  export { ToolRosterEntry, ToolRoster, ToolRosterDelta, ToolRosterRenderHints, ROSTER_SOURCES, toolIdentityOf, mintCapabilityId, diffToolRoster, judgeParkedToolIdentity, ruleFacesFromRoster, toolCallFaceOf, rosterToolName, ruleNamesOf, inputKeysOf, ruleFaceOfInstance, rosterMemberBoundProblem, ToolRosterDeltaSeat, } from "./core/tool-roster.js";
@@ -168,7 +169,8 @@ export { ALLOW_RULE_MEMBERS } from "./core/allow-rule-shadow.js";
168
169
  export { mintNamespacePrefix } from "./core/protocol-naming.js";
169
170
  export { readDenyClassifierRules, renderClassifierDenyRules } from "./core/auto-mode-prompt.js";
170
171
  export { AUTO_MODE_DENY_SOURCES, isAutoModeDenySource } from "./core/runtime-caps.js";
171
- export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_PARTIES, isSettlementParty, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
172
+ export { SETTLEMENT_KINDS, isSettlementKind, SETTLEMENT_PARTIES, isSettlementParty, HOST_DECIDERS, isHostDecider, SETTLEMENT_IS_REFUSAL, DENIED_BY_VALUES, isDeniedBy, DENIED_BY_MAY_VETO, CLASSIFIER_DENY_CAUSES, isClassifierDenyCause, DENIED_BY_MAY_CARRY_CAUSE, screenGateOutcome } from "./core/gate-outcome.js";
173
+ export { policyCannotAnswer } from "./core/real-approval.js";
172
174
  export {} from "./core/hooks.js";
173
175
  export { SWAPPABLE_DEP_SEATS, SWAP_SEAT_NOTICE, isSwappableDepSeat, screenSwappableDeps } from "./core/swappable-deps.js";
174
176
  export { parseAutoModeResponse, createAutoModeDecider, AUTO_MODE_UNAVAILABLE_CAUSES, isAutoModeUnavailableCause, classifierUnavailableDenyMessage, classifierParseFailureDenyMessage, AUTO_MODE_PARSE_FAILURES, isAutoModeParseFailure, AUTO_MODE_CLASSIFIER_FALLBACKS, isAutoModeClassifierFallback, AUTO_MODE_FALLBACK_CAUSES, isAutoModeFallbackCause, createAutoModeDenialTracker, denialLimitFallbackMessage, denialLimitSentence, unarmedWindow, } from "./core/auto-mode.js";
@@ -198,6 +200,7 @@ export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreTo
198
200
  export { HOOK_FAMILIES, HOOKS_INVALID_CODE } from "./core/hook-seats.js";
199
201
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, MemoryProjectionError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, MEMORY_PROJECT_KEY_ABSENT_REASONS, } from "./core/memory.js";
200
202
  export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, writableRootOf, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_ORIGIN_CAUSES, committedOriginOf, originEquals, consolidationExposedFrontmatter, ambiguousOriginRepresentation, committedDistilledOf, distilledEquals, CONSOLIDATION_DEFAULTS, ConsolidationRefusedError, MEMORY_SEARCH_SUPERSEDED_TAG, consolidationTypeEligible, deriveSupersededSet, memorySupersededNote, readIntentCredentials, supersessionFuseCeiling, deriveShadowedSet, memoryConsolidationRecommendedNotice, memoryConsolidationCommittedNotice, memoryConsolidationConflictNotice, memoryConsolidationIncompleteNotice, memoryConsolidationRefusedNotice, memoryConsolidationWithheldNotice, DISTILLER_DEFAULT_MAX_INPUTS_PER_PRODUCT, LLM_DISTILLER_CONTRACT, LLM_DISTILLER_CONTRACT_DL2, LLM_DISTILLER_CONTRACT_DL3, LLM_DISTILLER_CONTRACTS, MEMORY_DISTILLER_CONTRACT_V1, contractGroupingDiff, driveConsolidationToFixpoint, isAliasModelId, llmPlanDistiller, mintExposurePartitionedPlan, mintLlmConsolidationPlan, MEMORY_DISTILLER_PURITY_CONTRACT_V1, detectCleanArmVerbatimLeak, openAiCompatChatSeat, parseJsonAnswer, planParseRepairs, sanitizeLlmGroups, scheduleUnderFuse, CONSOLIDATION_DRIVER_PLANS_DIR, CONSOLIDATION_DRIVER_RUNS_FILE, CONSOLIDATION_RUN_STOP_REASONS, archiveDistillerPlan, readConsolidationDriverRun, runMemoryConsolidationDriver, isInstructionEntry, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, MEMORY_READONLY_NOTICE, MEMORY_CAPTURE_OPTOUT_NOTICE, memoryCaptureOptedOutNotice, memoryCaptureOptOutUnpersistedNotice, SESSION_CAPTURE_OPTOUT_DIR, markSessionCaptureOptOut, readSessionCaptureOptOut, listSessionCaptureOptOut, fileSessionCaptureRecordStore, readV2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, CHALLENGE_LEDGER_MAX_EVENTS, rebuildStrictControlPlaneLedger, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_INDEX_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, MEMORY_EXPOSURE_BANNER, MEMORY_EXPOSURE_HANDLE_TAG, memoryExposureIndexRow, STUB_ARCHIVED_LINE, DEFAULT_MAX_MEMORY_FILES, DEFAULT_MAX_ENTRY_DEPTH, DEFAULT_HARVEST_DEADLINE_MS, DEFAULT_HARVEST_FILE_BUDGET, MASS_DELETION_FUSE_RATIO, scanMemoryWrite, scanMemoryFileName, scanRemediation, MEMORY_FILENAME_SEGMENT_RE, renderAnnouncements, enqueueMemoryAnnouncement, drainMemoryAnnouncements, peekMemoryAnnouncements, bumpScanFuse, scanFuseCount, clearScanFuse, ANNOUNCEMENTS_FILE, MEMORY_ANNOUNCEMENTS_MAX, SCAN_FUSE_FILE, SCAN_FUSE_THRESHOLD, erasureSelectHash, computeMemoryBundleHash, SCOPE_SEGMENT_MAX_ENCODED, PROJECT_MARKER_PATH, encodeScopeSegment, decodeScopeSegment, parseScopeKey, formatUserScope, formatOrgScope, formatProjScope, formatUserProjScope, isPersonalScope, assertScopeContractPlacement, formatProjectMarker, parseProjectMarker, resolveProjectId, PROJECT_ID_REGEX, migrateScope, materializeEntriesToFiles, harvestFilesToPatches, projectionsToWriteBack, screenInboundEntries, REMOTE_HARVEST_PER_FILE_BYTES, REMOTE_MASS_DELETION_FUSE_RATIO, deriveProjectMemoryDir, deriveProjectControlDir, recordProjectIdHint, lookupProjectIdHint, PROJECT_ID_HINTS_FILE, reconcileMemoryEntries, nextSyncBaseline, mergeRecallHits, syncMemoryScope, } from "./core/memory-engine/index.js";
203
+ export { STORE_FORM_REFUSAL_CODES, TARGET_OUTSIDE_STORE, SCOPE_HOME_NOT_DIRECTORY, SCOPE_HOME_FORMS } from "./core/memory-engine/layout.js";
201
204
  export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, } from "./core/shared-memory/types.js";
202
205
  export { sharedMemoryStoreContract, } from "./core/shared-memory/contract.js";
203
206
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
@@ -421,6 +421,9 @@ export interface WorkflowRun {
421
421
  * read or written carrying this token's `parked` entry, so
422
422
  * absence is the confirmed state and an entry written before this member reads as confirmed, exactly as it did; the
423
423
  * engine's own material read identity-checks what it finds, so an unconfirmed origin degrades rather than mis-binds.
424
+ * `parkedBy` is the run standing on the park: a record's run holds it iff `entry.parkedBy === record.id` (never
425
+ * `originRunId`); inheritance keeps it. `generation` is the inherited entry's, else `0`, plus one per admission — the
426
+ * highest on a session is the chain's tail, a tie is a fork. Both or neither; an older entry has neither (no holder).
424
427
  */
425
428
  parks?: Array<{
426
429
  callKey: string;
@@ -428,6 +431,8 @@ export interface WorkflowRun {
428
431
  token: string;
429
432
  originRunId: string;
430
433
  originUnconfirmed?: true;
434
+ parkedBy?: string;
435
+ generation?: number;
431
436
  }>;
432
437
  /**
433
438
  * Set (`true`) on a resume run's record from its creation and REMOVED the moment its admission completes — so a record
@@ -223,8 +223,9 @@ export interface WorkflowAgentHandle {
223
223
  * legs of one steering ingress are equally replay-safe. ⚠️ ONE arm of that contract is NOT reachable through this
224
224
  * handle, deliberately: the idempotent-REPLAY arm ("same id, same payload ⇒ injects nothing"). Each call mints a
225
225
  * FRESH unguessable correlation marker into the framing it delivers, so a retry under the same id is a
226
- * same-id-DIFFERENT-instruction call and refuses typed `steering.duplicate_input_id`. What the key buys on this
227
- * lane is therefore AT-MOST-ONCE: a retried ingress is refused LOUDLY instead of injecting a second copy.
226
+ * same-id-DIFFERENT-instruction call and refuses typed `steering.duplicate_input_id` (`detail.differs` always names
227
+ * `text` on this lane). What the key buys on this lane is therefore AT-MOST-ONCE: a retried ingress is refused
228
+ * LOUDLY instead of injecting a second copy.
228
229
  */
229
230
  steer(content: string, opts?: {
230
231
  inputId?: string;