@sema-agent/core 5.21.1 → 5.22.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 (72) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/agents/send-message-tool.js +6 -3
  3. package/dist/agents/subagent.d.ts +6 -0
  4. package/dist/agents/subagent.js +45 -4
  5. package/dist/brain/errors.d.ts +20 -0
  6. package/dist/brain/errors.js +40 -0
  7. package/dist/brain/retry.d.ts +16 -2
  8. package/dist/brain/retry.js +3 -2
  9. package/dist/brain/status-sink.d.ts +9 -2
  10. package/dist/brain/stream-engine.d.ts +22 -0
  11. package/dist/brain/stream-engine.js +41 -10
  12. package/dist/core/ask-class.d.ts +48 -0
  13. package/dist/core/ask-class.js +33 -0
  14. package/dist/core/checkpoint-store.d.ts +103 -10
  15. package/dist/core/checkpoint-store.js +3 -1
  16. package/dist/core/governance-codes.d.ts +38 -0
  17. package/dist/core/governance-codes.js +11 -0
  18. package/dist/core/hooks.d.ts +39 -0
  19. package/dist/core/hooks.js +26 -2
  20. package/dist/core/locked-config.d.ts +7 -1
  21. package/dist/core/locked-config.js +2 -1
  22. package/dist/core/memory-engine/delegation-provenance.d.ts +62 -0
  23. package/dist/core/memory-engine/delegation-provenance.js +26 -0
  24. package/dist/core/memory-engine/engine.d.ts +67 -1
  25. package/dist/core/memory-engine/engine.js +270 -12
  26. package/dist/core/memory-engine/header-hints.d.ts +30 -0
  27. package/dist/core/memory-engine/header-hints.js +41 -0
  28. package/dist/core/memory-engine/index.d.ts +3 -2
  29. package/dist/core/memory-engine/index.js +3 -2
  30. package/dist/core/memory-engine/layout.d.ts +166 -0
  31. package/dist/core/memory-engine/layout.js +399 -0
  32. package/dist/core/memory-engine/tools.d.ts +30 -0
  33. package/dist/core/memory-engine/tools.js +108 -17
  34. package/dist/core/permission-rule-consent.d.ts +25 -9
  35. package/dist/core/permission-rule-consent.js +91 -20
  36. package/dist/core/permission-rule-model.d.ts +9 -1
  37. package/dist/core/permission-rule-model.js +2 -2
  38. package/dist/core/permission-rule-org.d.ts +161 -0
  39. package/dist/core/permission-rule-org.js +211 -0
  40. package/dist/core/permission-rule-store.d.ts +249 -6
  41. package/dist/core/permission-rule-store.js +313 -3
  42. package/dist/core/permission-rule-sync.d.ts +131 -0
  43. package/dist/core/permission-rule-sync.js +314 -0
  44. package/dist/core/runner/prepare-memory.js +35 -8
  45. package/dist/core/runner/prepare-task.d.ts +54 -1
  46. package/dist/core/runner/prepare-task.js +246 -27
  47. package/dist/core/runner/runtask.js +147 -6
  48. package/dist/core/shared-memory/contract.js +19 -4
  49. package/dist/core/shared-memory/normalize.d.ts +3 -1
  50. package/dist/core/shared-memory/tools.js +73 -17
  51. package/dist/core/shared-memory/types.d.ts +27 -1
  52. package/dist/core/store-contracts/permission-rule-sync-contract.d.ts +33 -0
  53. package/dist/core/store-contracts/permission-rule-sync-contract.js +186 -0
  54. package/dist/core/task-notification.d.ts +5 -2
  55. package/dist/core/task-registry-agent.d.ts +1 -1
  56. package/dist/core/task-registry-agent.js +6 -2
  57. package/dist/core/task-registry-shared.d.ts +9 -2
  58. package/dist/core/task-registry.d.ts +9 -3
  59. package/dist/core/task-registry.js +2 -0
  60. package/dist/core/tool-policy.d.ts +120 -2
  61. package/dist/core/tool-policy.js +116 -6
  62. package/dist/core/trace.d.ts +32 -1
  63. package/dist/core/types.d.ts +56 -3
  64. package/dist/index.d.ts +12 -7
  65. package/dist/index.js +10 -5
  66. package/dist/stores/file/checkpoint-store.d.ts +4 -0
  67. package/dist/stores/file/checkpoint-store.js +1 -0
  68. package/dist/stores/file/permission-rule-adopt.d.ts +62 -0
  69. package/dist/stores/file/permission-rule-adopt.js +95 -0
  70. package/dist/stores/file/permission-rule-store.d.ts +80 -2
  71. package/dist/stores/file/permission-rule-store.js +189 -46
  72. package/package.json +1 -1
@@ -1,4 +1,6 @@
1
+ import { createHash } from "node:crypto";
1
2
  import { homedir } from "node:os";
3
+ import { brandPolicyAskClass } from "./ask-class.js";
2
4
  import { join, normalize as normalizePath, posix as posixPath, sep, win32 as winPath } from "node:path";
3
5
  import { BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName } from "../tools/fs/index.js";
4
6
  import { boundInputHashOf } from "./canonical-json.js";
@@ -12,6 +14,67 @@ export function isApprovalSettledBy(v) {
12
14
  export function decisionText(d) {
13
15
  return d.message;
14
16
  }
17
+ export function checkToolPolicyProjection(projection, req) {
18
+ for (const c of projection.components) {
19
+ if (c.kind === "tool_deny") {
20
+ if (c.names.includes(req.toolName)) {
21
+ return { action: "deny", message: `tool "${req.toolName}" is denied by a frozen inherited policy projection` };
22
+ }
23
+ continue;
24
+ }
25
+ if (c.kind === "tool_allowlist") {
26
+ if (!c.names.includes(req.toolName)) {
27
+ return { action: "deny", message: `tool "${req.toolName}" is not in a frozen inherited policy projection's allowlist` };
28
+ }
29
+ continue;
30
+ }
31
+ if (!c.tools.includes(req.toolName))
32
+ continue;
33
+ const command = req.args?.command;
34
+ if (typeof command !== "string") {
35
+ if (c.unparseableAction === "deny") {
36
+ return { action: "deny", message: `tool "${req.toolName}" call has no parseable command string (frozen inherited policy projection)` };
37
+ }
38
+ continue;
39
+ }
40
+ const parsed = parseLeadingCommandName(command);
41
+ if ("reject" in parsed) {
42
+ if (c.unparseableAction === "deny") {
43
+ return { action: "deny", message: `command is not a single simple command (${parsed.reject}) (frozen inherited policy projection)` };
44
+ }
45
+ continue;
46
+ }
47
+ if (c.deny.includes(parsed.name)) {
48
+ return { action: "deny", message: `command "${parsed.name}" is denied by a frozen inherited policy projection` };
49
+ }
50
+ if (c.allow !== undefined && !c.allow.includes(parsed.name) && c.unmatchedAction === "deny") {
51
+ return { action: "deny", message: `command "${parsed.name}" is not in a frozen inherited policy projection's allowlist` };
52
+ }
53
+ }
54
+ return undefined;
55
+ }
56
+ export function constraintChainEntryOf(policy, meta) {
57
+ const m = {
58
+ ...(meta?.autoModeArmed ? { autoModeArmed: true } : {}),
59
+ ...(meta?.durableMandate ? { durableMandate: true } : {}),
60
+ ...(meta?.contentMandate ? { contentMandate: true } : {}),
61
+ };
62
+ const p = policy.projection;
63
+ if (p === undefined)
64
+ return { opaque: true, ...m };
65
+ return { components: p.components, requiresLiveRemainder: p.requiresLiveRemainder, ...m };
66
+ }
67
+ function stableJson(v) {
68
+ if (v === null || typeof v !== "object")
69
+ return JSON.stringify(v) ?? "null";
70
+ if (Array.isArray(v))
71
+ return `[${v.map(stableJson).join(",")}]`;
72
+ const keys = Object.keys(v).sort();
73
+ return `{${keys.map((k) => `${JSON.stringify(k)}:${stableJson(v[k])}`).join(",")}}`;
74
+ }
75
+ export function constraintChainDigest(chain) {
76
+ return `cpv1:${createHash("sha256").update(stableJson(chain)).digest("hex")}`;
77
+ }
15
78
  const ALLOW = { action: "allow" };
16
79
  const RETIRED_TEXT_FIELD = "reason";
17
80
  const RETIRED_TEXT_FIELD_DENY_MESSAGE = `a permission decision carries the retired "${RETIRED_TEXT_FIELD}" field — rename it to "message" (the one text field ` +
@@ -100,6 +163,13 @@ export function createAllowDenyPolicy(opts) {
100
163
  const allow = opts.allow ? new Set(opts.allow) : undefined;
101
164
  const deny = new Set(opts.deny ?? []);
102
165
  return {
166
+ projection: {
167
+ components: [
168
+ ...(opts.deny && opts.deny.length > 0 ? [{ kind: "tool_deny", names: [...opts.deny] }] : []),
169
+ ...(opts.allow ? [{ kind: "tool_allowlist", names: [...opts.allow] }] : []),
170
+ ],
171
+ requiresLiveRemainder: false,
172
+ },
103
173
  nameSets: [{ ...(opts.allow ? { allow: [...opts.allow] } : {}), ...(opts.deny ? { deny: [...opts.deny] } : {}) }],
104
174
  check(req) {
105
175
  const toolName = req.toolName;
@@ -124,6 +194,13 @@ export function createApprovalPolicy(opts) {
124
194
  const deny = new Set(opts.deny ?? []);
125
195
  const auto = new Set(opts.autoAllow ?? []);
126
196
  return {
197
+ projection: {
198
+ components: [
199
+ ...(opts.deny && opts.deny.length > 0 ? [{ kind: "tool_deny", names: [...opts.deny] }] : []),
200
+ ...(opts.denyByDefault === true ? [{ kind: "tool_allowlist", names: [...opts.requireApproval, ...(opts.autoAllow ?? [])] }] : []),
201
+ ],
202
+ requiresLiveRemainder: opts.requireApproval.length > 0,
203
+ },
127
204
  nameSets: [
128
205
  {
129
206
  ask: [...opts.requireApproval],
@@ -179,7 +256,25 @@ export function createApprovalPolicy(opts) {
179
256
  }
180
257
  export function combinePolicies(...policies) {
181
258
  const nameSets = policies.flatMap(toolPolicyNameSets);
259
+ const childProjections = policies.map((p) => p.projection);
260
+ const projectedComponents = [];
261
+ let combinedRemainder = false;
262
+ for (const p of childProjections) {
263
+ if (p === undefined) {
264
+ combinedRemainder = true;
265
+ break;
266
+ }
267
+ projectedComponents.push(...p.components);
268
+ if (p.requiresLiveRemainder) {
269
+ combinedRemainder = true;
270
+ break;
271
+ }
272
+ }
273
+ const combinedProjection = childProjections.some((p) => p !== undefined)
274
+ ? { components: projectedComponents, requiresLiveRemainder: combinedRemainder }
275
+ : undefined;
182
276
  return {
277
+ ...(combinedProjection !== undefined ? { projection: combinedProjection } : {}),
183
278
  ...(nameSets.length > 0 ? { nameSets } : {}),
184
279
  async check(req, signal) {
185
280
  let asked;
@@ -225,7 +320,22 @@ export function createCoarseCommandNamePolicy(opts) {
225
320
  const fallback = (reason) => defaultAction === "deny"
226
321
  ? { action: "deny", message: reason, decisionReason: "rule" }
227
322
  : { action: "ask", message: reason, decisionReason: "rule" };
228
- return {
323
+ const fallbackIsDeny = defaultAction === "deny";
324
+ const projection = {
325
+ components: [
326
+ {
327
+ kind: "shell_command",
328
+ tools: [...shellTools],
329
+ deny: [...deny],
330
+ ...(allow !== undefined ? { allow: [...allow] } : {}),
331
+ unmatchedAction: fallbackIsDeny ? "deny" : "none",
332
+ unparseableAction: fallbackIsDeny ? "deny" : "none",
333
+ },
334
+ ],
335
+ requiresLiveRemainder: !fallbackIsDeny,
336
+ };
337
+ return brandPolicyAskClass({
338
+ projection,
229
339
  check(req) {
230
340
  if (!shellTools.has(req.toolName))
231
341
  return ALLOW;
@@ -245,7 +355,7 @@ export function createCoarseCommandNamePolicy(opts) {
245
355
  }
246
356
  return ALLOW;
247
357
  },
248
- };
358
+ }, "sandbox_local");
249
359
  }
250
360
  const UNVERIFIABLE_DELETE_SAFE_VARS = ["TMPDIR", "HOME", "PWD"];
251
361
  const DELETE_HEADS = new Set(["rm", "xargs", "Remove-Item"]);
@@ -473,7 +583,7 @@ function hasRecursiveForce(argvTail) {
473
583
  export function createUnverifiableDeletePolicy(opts) {
474
584
  const safeVars = new Set([...UNVERIFIABLE_DELETE_SAFE_VARS, ...(opts?.safeVars ?? [])]);
475
585
  const shellTools = canonicalToolNameSet(opts?.tools);
476
- return {
586
+ return brandPolicyAskClass({
477
587
  check(req) {
478
588
  if (!shellTools.has(req.toolName))
479
589
  return ALLOW;
@@ -492,7 +602,7 @@ export function createUnverifiableDeletePolicy(opts) {
492
602
  `(or assign the variable in the same command, e.g. \`DIR=/exact/path; rm -rf "$DIR"\`) so the target can be verified.`,
493
603
  };
494
604
  },
495
- };
605
+ }, "external_authority");
496
606
  }
497
607
  function pathSegments(p) {
498
608
  return p.split(/[\\/]/).filter(Boolean);
@@ -569,7 +679,7 @@ export function createTranscriptIntegrityPolicy(opts) {
569
679
  `files — modifying or deleting them tampers with the run's own audit trail. Reading them (ls/cat/grep ` +
570
680
  `as a single simple command) is fine.`,
571
681
  });
572
- return {
682
+ return brandPolicyAskClass({
573
683
  check(req) {
574
684
  const toolName = req.toolName;
575
685
  if (shellTools.has(toolName)) {
@@ -597,7 +707,7 @@ export function createTranscriptIntegrityPolicy(opts) {
597
707
  }
598
708
  return ALLOW;
599
709
  },
600
- };
710
+ }, "external_authority");
601
711
  }
602
712
  const delegatedApproverRoot = new WeakMap();
603
713
  export function withDelegationProvenance(onAsk, delegation) {
@@ -16,7 +16,7 @@
16
16
  * core's own contract is only the field names here; it deliberately stops at supplying the FACTS a bridge
17
17
  * needs (ids, turn indices, token counts) rather than adopting the convention's vocabulary internally.
18
18
  */
19
- import type { TaskStatus, ToolEffect } from "./types.js";
19
+ import type { BrainRetryErrClass, TaskStatus, ToolEffect } from "./types.js";
20
20
  import type { ThinkingLevel } from "../internal/harness-types.js";
21
21
  import type { ToolManifestRow } from "../prompt-assembly/tool-catalog.js";
22
22
  /**
@@ -382,6 +382,29 @@ export type TraceEvent = {
382
382
  taskId: string;
383
383
  message: string;
384
384
  ts: number;
385
+ } | {
386
+ /**
387
+ * F-012 L2 — a pending ask was AUTO-ADMITTED by the sandbox-admission leg: the deployment's
388
+ * execution env declares an isolated sandbox, every surviving ask on the call was
389
+ * engine-classified `sandbox_local`, and the call crosses no declared boundary. This record is
390
+ * the durable admission ledger's operator half (the transcript half rides the tool result's
391
+ * system-reminder context); a consumer anchors on THIS kind, never on wording.
392
+ */
393
+ kind: "permission.sandbox_admitted";
394
+ version: 1;
395
+ taskId: string;
396
+ toolName: string;
397
+ toolCallId: string;
398
+ /** The engine ask classes of the admitted call's surviving asks (all `sandbox_local` by the
399
+ * admission predicate; carried explicitly so the ledger states what was judged, not just that
400
+ * judgment passed). */
401
+ askClasses: readonly string[];
402
+ /** Which layers raised the admitted asks (`caller_policy` / `ancestor_constraint` /
403
+ * `gate_safety_tighten`). */
404
+ sourceLayers: readonly string[];
405
+ /** The boundary classification the admission asserted. */
406
+ boundary: "sandbox_internal";
407
+ ts: number;
385
408
  } | {
386
409
  /** C1 — the failover brain served this call from a FALLBACK entry (`createFailoverBrain`): the
387
410
  * primary (and possibly earlier hops) failed cleanly upfront. Without this, same-model gateway
@@ -418,6 +441,14 @@ export type TraceEvent = {
418
441
  /** 1-based attempt number that was ABANDONED (the retry that follows is attempt+1). */
419
442
  attempt: number;
420
443
  phase: "connect" | "midstream";
444
+ /** WHY the attempt is being retried, as the closed neutral bucket the user-facing status frame
445
+ * also carries ({@link BrainRetryErrClass}) — an operator reading this and a user reading a
446
+ * progress line then agree on the reason. Optional: absent on frames minted before it existed. */
447
+ errClass?: BrainRetryErrClass;
448
+ /** The backoff about to be slept, ms — 0 for an immediate re-send. Together with `attempt` this
449
+ * makes a whole retry chain reconstructible from the trace alone, which is what a caller that saw
450
+ * only silence needs to explain where the time went. */
451
+ nextDelayMs?: number;
421
452
  ts: number;
422
453
  } | {
423
454
  /** C2 — the agent loop drove one of its self-heal recoveries (malformed-tool retry / thinking-only
@@ -737,6 +737,17 @@ export interface ToolExecuteContext {
737
737
  * tool runs outside a Runner task.
738
738
  */
739
739
  inheritedGateForChildren?: () => import("./runner/prepare-task.js").InheritedGate;
740
+ /**
741
+ * design/180 half A — the delegation runtime-provenance ARMING face. Runner-filled; a delegation
742
+ * tool calls it at spawn time: a non-undefined return means this (parent) run is armed (it mounts
743
+ * a memory session, or is itself recording for its own parent) and carries the chain's FROZEN
744
+ * content-safety snapshot — the tool then mints the child's recorder ref and threads both into
745
+ * the child's trusted `RunInternals.delegationProvenance`. Undefined return / absent field ⇒ the
746
+ * child spawns without a recorder (its deliveries read `unknown` and every judgment stays on the
747
+ * static floor — v1 behavior byte-identical). Same trust posture as
748
+ * {@link inheritedGateForChildren}: never a model/tool argument, never a TaskSpec field.
749
+ */
750
+ delegationProvenanceForChildren?: () => import("./memory-engine/delegation-provenance.js").DelegationContentSafety | undefined;
740
751
  /**
741
752
  * RB-201 FO-3 (form-one audit, CC 220 `Ipd`/`ein` parity) — the auto-mode classifier decider ARMED
742
753
  * for THIS task (`RuntimeCaps.autoMode === true` AND `RunnerDeps.autoMode` both present; the same
@@ -1802,6 +1813,17 @@ export interface TaskSpec {
1802
1813
  agents?: AgentDefinition[];
1803
1814
  /** Gate tool calls before they run (allow/deny/approval). Overrides `RunnerDeps.toolPolicy`. */
1804
1815
  toolPolicy?: import("./tool-policy.js").ToolPolicy;
1816
+ /**
1817
+ * #93 (F-012 L3) — the OVERRIDE seat for the durable resume-edit re-adjudication policy: the policy
1818
+ * an approver's `updatedInput` EDIT is re-checked against before a resumed pending call executes
1819
+ * (and, at park-mint time, the policy a store-codec-moved projection is re-adjudicated by). ABSENT
1820
+ * falls back to the caller policy (`toolPolicy ?? RunnerDeps.toolPolicy`) — never to a silent skip:
1821
+ * the pre-#93 shape skipped the whole recheck for deployments with no caller policy, which let a
1822
+ * fidelity-projection-moved value land unadjudicated. Supply this only to make the resume-edit
1823
+ * boundary STRICTER/different from the live caller policy; it never widens (the frozen ancestor
1824
+ * projections and the deny-narrowing layers still apply regardless).
1825
+ */
1826
+ basePolicyForResumeEdit?: import("./tool-policy.js").ToolPolicy;
1805
1827
  /** How `ask` decisions resolve for this task (headless auto-deny by default). Overrides `RunnerDeps.onAsk`. */
1806
1828
  onAsk?: import("./tool-policy.js").OnAsk;
1807
1829
  /** Content-ask seam (design/64 §5): routes an AskUserQuestion tool call to a real human/UI. When set, the
@@ -2999,6 +3021,24 @@ export type BrainStatusPhase = "rate_limited" | "retrying" | "reconnecting" | "c
2999
3021
  * Both mean the same thing to a renderer — stop showing the retry state.
3000
3022
  */
3001
3023
  | "recovered" | "gave_up";
3024
+ /**
3025
+ * WHY a retry wait is happening, as a closed, provider-NEUTRAL bucket — the companion to
3026
+ * {@link BrainStatusPhase}, which says what the brain is doing about it. A consumer rendering an
3027
+ * unattended progress line ("no answer for three minutes") needs the reason, and until this existed the
3028
+ * only carriers of it were the HTTP status and the syscall code, neither of which may cross this
3029
+ * channel. Values are about the SHAPE of the failure, never its provider taxonomy:
3030
+ * - `connect_refused` — the attempt got a definite negative about the target itself (nothing accepts
3031
+ * at that address, or the name has no address). This is the class the SHORT retry lane serves.
3032
+ * - `transport` — any other transport-level failure: a connect timeout, a reset, a mid-stream
3033
+ * tear, a stalled stream. No verdict about the target; the full ladder applies.
3034
+ * - `rate_limit` — the provider asked the caller to slow down.
3035
+ * - `server` — the provider reported a failure on its own side.
3036
+ * - `http` — a response the status predicate calls terminal, retried anyway because the
3037
+ * provider's own explicit retry verdict said to.
3038
+ * - `output_cap` — not a failure of the connection at all: the request is being re-sent with a
3039
+ * lowered output cap after the provider reported the context limit exceeded (no backoff).
3040
+ */
3041
+ export type BrainRetryErrClass = "connect_refused" | "transport" | "rate_limit" | "server" | "http" | "output_cap";
3002
3042
  /** design/99 §E3/§E10 — the payload of a {@link TaskEvent} `status` event (and the brain→runner signal). */
3003
3043
  export interface BrainStatus {
3004
3044
  phase: BrainStatusPhase;
@@ -3013,8 +3053,14 @@ export interface BrainStatus {
3013
3053
  /** RB-420-c — 1-based index of the attempt that just failed (the wait precedes attempt `attempt + 1`);
3014
3054
  * same numbering as the `brain.retry` telemetry frame. Absent on frames that are not a retry wait. */
3015
3055
  attempt?: number;
3016
- /** RB-420-c — the retry budget of THIS lane, so a consumer can render "attempt 3 of 10". */
3056
+ /** RB-420-c — the retry budget of THIS lane, so a consumer can render "attempt 3 of 10". Lane, not
3057
+ * engine: a failure class served by a shorter ladder reports that ladder's budget, so the fraction a
3058
+ * consumer renders is the one actually in force rather than the engine-wide ceiling. */
3017
3059
  maxRetries?: number;
3060
+ /** Why this wait is happening ({@link BrainRetryErrClass}). Present on retry-wait frames whose cause
3061
+ * the engine classified; absent on frames that are not a retry wait (`recovered`/`gave_up`) and on a
3062
+ * `circuit_open` fast-fail, which is a local verdict rather than an observed failure. */
3063
+ errClass?: BrainRetryErrClass;
3018
3064
  }
3019
3065
  /**
3020
3066
  * design/97 CORE-8 (③): one lightweight TOOL-ACTIVITY beat surfaced from a running task, for a per-agent live
@@ -3955,8 +4001,11 @@ export interface BackgroundChildEvent {
3955
4001
  */
3956
4002
  editedFiles?: import("../agents/subagent-steps.js").SubagentEditedFile[];
3957
4003
  /**
3958
- * terminal (residual observability, lane E): `true` when the child can be revived with `SendMessage` (its session is
3959
- * retained and it was not stopped by the user); `false` for a user-stopped / non-resumable child.
4004
+ * terminal (residual observability, lane E): `true` when the child can be revived with `SendMessage`
4005
+ * either its session is retained live and the run was not killed, or it has a NAMED durable row that no
4006
+ * USER stop closed (a parent teardown, a reap or a host death is precisely what the durable revival
4007
+ * lane recovers from). `false` for a user-stopped child, an anonymous or store-less one, and for the
4008
+ * session-teardown reap frame, whose lane cannot know what survives the teardown.
3960
4009
  * Lets a parent's orchestration logic decide "continue it" vs "start fresh" without trial-and-error.
3961
4010
  */
3962
4011
  resumable?: boolean;
@@ -4543,6 +4592,10 @@ export interface RunnerDeps {
4543
4592
  mcpImageResizer?: import("./mcp.js").McpImageResizer;
4544
4593
  /** Default tool-call gate for all tasks (a task's own `toolPolicy` overrides this). */
4545
4594
  toolPolicy?: import("./tool-policy.js").ToolPolicy;
4595
+ /** Deployment default for {@link TaskSpec.basePolicyForResumeEdit} (#93 / F-012 L3): the resume-edit
4596
+ * re-adjudication override. Resolution: `spec.basePolicyForResumeEdit ?? THIS ?? (spec.toolPolicy ??
4597
+ * deps.toolPolicy)` — absence falls back to the caller policy, never to a silent skip. */
4598
+ basePolicyForResumeEdit?: import("./tool-policy.js").ToolPolicy;
4546
4599
  /**
4547
4600
  * How `ask` decisions resolve when a policy/hook requests human confirmation (design/37). Default
4548
4601
  * (omitted) = `"deny"`: **headless auto-deny** — no approver, so `ask` resolves deterministically to
package/dist/index.d.ts CHANGED
@@ -87,8 +87,8 @@ export type { InvariantKind, FunctionContract, Invariant, InvariantViolation, Ch
87
87
  export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
88
88
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, type BashReadonlyRootBoundary, type CompoundReadonlyVerdict, } from "./tools/fs/index.js";
89
89
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
90
- export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, type ToolResultStore, type ToolResultSlice, } from "./core/tool-result-store.js";
91
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
90
+ export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, type ToolResultStore, type ToolResultSlice, } from "./core/tool-result-store.js";
91
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, type ActorAssertion, type PendingSteerEntry, type PendingSteerInput, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, type RiskDescriptor, type CheckpointStore, type CheckpointSummary, type Checkpoint, type CheckpointToken, type CheckpointGate, type CheckpointState, type SerializedCheckpointState, type CheckpointFaultMode, type PendingAction, type ResumeOutcome, type ResolvedOutcome, type ReopenReason, type ResolveExpectation, type SafetyAxis, type ResourceLedger, type ResourceLimitReason, type PlatformLimitReason, } from "./core/checkpoint-store.js";
92
92
  export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, type UsageWindow, type UsageWindowStore, type UsageWindowReading, type UsageWindowRecord, type UsageSlot, type UsageBucketRow, } from "./core/usage-window-store.js";
93
93
  export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
94
94
  export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
@@ -128,7 +128,7 @@ export type { SchedulerCapability, SchedulerErrorCode, ScheduledIntent, Schedule
128
128
  export { createSchedulerTools, type SchedulerToolContext, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
129
129
  export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, type AutonomousLoopPromptOptions, } from "./tools/loop-tick.js";
130
130
  export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
131
- export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type ApprovalSettledBy, APPROVAL_SETTLED_BY_VALUES, isApprovalSettledBy, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, } from "./core/tool-policy.js";
131
+ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, type ToolPolicyNameSets, type NamedToolPolicy, type ToolPolicyProjection, type ToolPolicyProjectionComponent, type ConstraintChainEntry, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, type ToolPolicy, type ToolCallRequest, type PermissionResult, type DecisionReason, type ApprovalSettledBy, APPROVAL_SETTLED_BY_VALUES, isApprovalSettledBy, type OnAsk, type AskOutcome, type ResolvedAsk, type AskRequest, type AskDelegationProvenance, } from "./core/tool-policy.js";
132
132
  export { parseAutoModeResponse, createAutoModeDecider, type AutoModeVerdict, type AutoModeDecider, type AutoModeDeciderOptions, type AutoModeClassifyFn, type AutoModeClassifyInput, } from "./core/auto-mode.js";
133
133
  export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, type AutoModeRules, type BuildAutoModePromptOptions, type AutoModeWindowOptions, } from "./core/auto-mode-prompt.js";
134
134
  export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
@@ -143,13 +143,17 @@ export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRul
143
143
  * and widening is not.
144
144
  */
145
145
  export { parseAllowRuleText, formatAllowRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, type PersistedAllowRule, type RuleTombstone, type RuleScope, type RuleDot, type RuleAdd, type RuleAddOrigin, type RuleSuggestion, type RuleReject, type RuleRejectCode, type ParsedAllowRule, type PersistedRuleTool, type PersistedRuleMatch, } from "./core/permission-rule-model.js";
146
- export { removePersistedRule, applyTombstones, sameScope, InMemoryPermissionRuleStore, EMPTY_RULE_STORE, type PermissionRuleStore, type PermissionRuleStoreProvider, type StoredAllowRules, type RemoveResult, type PutResult, } from "./core/permission-rule-store.js";
146
+ export { removePersistedRule, applyTombstones, sameScope, InMemoryPermissionRuleStore, EMPTY_RULE_STORE, type PermissionRuleStore, type PermissionRuleStoreProvider, type StoredAllowRules, type RemoveResult, type PutResult, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, type RuleSyncState, type RuleSyncFrontier, type RuleSyncDrop, type RuleSyncLandingReport, type RuleOwner, type QuarantinedRuleAdd, } from "./core/permission-rule-store.js";
147
+ export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, type PermissionRuleSyncTransport, type PermissionRuleSyncResult, type RuleSyncRequestBody, type RuleSyncResponseBody, } from "./core/permission-rule-sync.js";
148
+ export { createOrgRuleOverlay, orgRuleVerdictFor, effectivePermissionRules, orgRuleStatePersistenceOf, ORG_UNAVAILABLE_DECISION_REASON, type OrgPermissionRule, type OrgRuleSnapshot, type OrgRuleSnapshotProvider, type OrgRuleStatePersistence, type PersistedOrgRuleState, type OrgRuleOverlay, type OrgOverlayResolution, type OrgOverlayStatus, type EffectivePermissionRule, } from "./core/permission-rule-org.js";
149
+ export { RULE_SYNC_DROP_CODES, type RuleSyncDropReason, type RuleQuarantineReason } from "./core/governance-codes.js";
147
150
  export { prepareCardApproval, confirmRuleApproval, type ConfirmResult, type ConfirmRefusalReason, redeemRuleTicket, redeemRuleBatch, prepareCcImport, prepareStarterBatch, mintRuleTicket, STARTER_RULES, InMemoryRuleApprovalRecordStore, type RuleTicket, type RuleCandidate, type RuleApprovalKind, type RuleApprovalRecord, type RuleApprovalRecordStore, type RuleConsentDeps, type RedeemResult, type CcImportLayer, type ImportedSettingsLayer, type ImportPreview, type ImportResult, } from "./core/permission-rule-consent.js";
148
151
  export { FilePermissionRuleStoreProvider } from "./stores/file/permission-rule-store.js";
152
+ export { adoptFilePermissionRuleStore, type AdoptFileRuleStoreResult } from "./stores/file/permission-rule-adopt.js";
149
153
  export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, type Hooks, type HookToolContext, type HookEnvCapabilities, type HookToolOutput, type PreToolUseResult, type PostToolUseResult, type UserPromptSubmitResult, type HookToolFailure, type PostToolUseFailureResult, type PostToolBatchCall, type PostToolBatchResult, type PreCompactContext, type PreCompactResult, type PostCompactContext, type StopFailureContext, type PermissionDeniedPayload, type PermissionDeniedSource, } from "./core/hooks.js";
150
154
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, type NormalizedMemorySpec, type MemorySpecInput, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, type Embedder, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, type UtilityGate, type MemoryStore, type MemoryVectorMode, type ScoredMemory, type MemoryNoteHeader, type MemoryNoteRecord, type MemoryNoteType, type StructuredNoteInput, } from "./core/memory.js";
151
- export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type MemoryGetDetails, 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 MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, 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";
152
- export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, type SharedMemoryStoreProvider, type SharedMemoryStoreReader, type SharedMemoryStoreInfo, type SharedMemoryDocumentEntry, type SharedMemorySnapshot, type SharedMemoryRequestContext, type MemoryListDetails, type MemoryReadDetails, } from "./core/shared-memory/types.js";
155
+ export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, type MemoryBackendContractHooks, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, readV2HeaderHints, type V2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, 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_ENGINE_TOOL_NAMES, type MemorySearchDetails, type MemorySearchHit, type MemoryGetDetails, 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 MemoryBackend, type MemoryEntry, type MemoryEntryFrontmatter, type MemoryEntryHeader, 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";
156
+ 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";
153
157
  export { sharedMemoryStoreContract, type SharedMemoryFixture, type SharedMemoryStoreContractHooks, } from "./core/shared-memory/contract.js";
154
158
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
155
159
  export { encodeSurfacedKey, buildManifestText, validateSelectedIds, composeSelectiveBody, formatMemoryAge, resolveLinkedIds, RECALL_CAVEAT, DEFAULT_MAX_SELECTED, DEFAULT_MAX_LINKED, type MemorySelector, type MemorySelectRequest, type SelectiveRecallOptions, type SelectiveRecallResult, type LayeredRecallOptions, type LayeredRecallResult, type ScopedNoteHeader, type ScopedNoteRecord, } from "./core/memory-recall.js";
@@ -199,6 +203,7 @@ export { checkpointStoreContract } from "./core/store-contracts/checkpoint-store
199
203
  export { sessionRepoContract } from "./core/store-contracts/session-repo-contract.js";
200
204
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
201
205
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
206
+ export { permissionRuleSyncContract, type PermissionRuleSyncContractHooks } from "./core/store-contracts/permission-rule-sync-contract.js";
202
207
  export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
203
208
  export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
204
209
  export { type BackgroundAgentStore, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentUsage, canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, type BackgroundAgentQuery, } from "./core/background-agent-store.js";
@@ -237,7 +242,7 @@ export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
237
242
  export { type BrainTimeoutConfig } from "./brain/timeout.js";
238
243
  export { createAssistantMessageEventStream } from "./internal/llm.js";
239
244
  export type { AssistantMessage, AssistantMessageEvent, CompleteSimpleFn, Context, DocumentContent, ImageContent, Message, StopReason, StreamFn, TextContent, ThinkingContent, ToolCall, ToolResultMessage, Usage, UserMessage, } from "./internal/llm.js";
240
- export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
245
+ export type { AgentDefinition, BeforeWriteHook, BeforeWriteRequest, BeforeWriteResult, HandsBandOptions, Brain, BrainStatus, BrainStatusPhase, BrainRetryErrClass, ImageInput, McpElicitRequest, McpElicitResponse, McpServerSpec, A2aServerSpec, OnElicit, Model, ModelRef, ProjectMemoryLoad, RunnerDeps, RuntimeCaps, BackgroundChildEvent, SkillManifest, SkillSpec, TaskEvent, TaskEventIdentity, ToolActivity, TaskLimits, StaleToolResultOffloadOptions, TaskResult, RemoteEnvFailureNote, TaskSpec, TaskStatus, TaskStream, CompactOutcome, ThinkingLevel, ToolExecuteContext, ToolReturn, ToolSpec, ToolEffect, ToolContentOrigin, WorkflowGovernanceBaseline, DelegationTaskType, } from "./core/types.js";
241
246
  export { Type } from "typebox";
242
247
  export type { TSchema, Static } from "typebox";
243
248
  export { explainPromptAssembly, describeDefaultPack, type DefaultPackDescription, type ExplainInput } from "./prompt-assembly/explain.js";
package/dist/index.js CHANGED
@@ -68,8 +68,8 @@ export { deriveInvariants, checkInvariants } from "./core/property-harness.js";
68
68
  export { HAND_TOOL_EFFECTS, bashReversibilityProbe, BASH_READONLY_DEFAULT_ALLOW, parseLeadingCommandName, classifyCompoundReadonly, MAX_EDIT_BYTES } from "./tools/fs/index.js";
69
69
  export { classifyCompoundReadonlyDetailed, formatOutOfRootReadApprovalOption, } from "./tools/fs/index.js";
70
70
  export { resolveBashTimeoutCaps } from "./tools/fs/index.js";
71
- export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, } from "./core/tool-result-store.js";
72
- export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
71
+ export { InMemoryToolResultStore, OFFLOAD_TOOL_NAME, DEFAULT_TOOL_RESULT_THRESHOLD_CHARS, assertSafeToolResultRef, buildToolResultRef, } from "./core/tool-result-store.js";
72
+ export { InMemoryCheckpointStore, CheckpointError, mintCheckpointToken, checkpointVersionOf, CURRENT_CHECKPOINT_VERSION, MAX_SUPPORTED_CHECKPOINT_VERSION, ORG_ADMISSION_CHECKPOINT_VERSION, F012_CHECKPOINT_VERSION, RESOURCE_CHECKPOINT_VERSION, TOKEN_CHECKPOINT_VERSION, debitLedger, remainingBudgetMicroUsd, remainingTokens, winnerFromOutcome, validatePendingSteer, readPendingSteerQueue, appendPendingSteer, MAX_PENDING_STEER_CHARS, MAX_PENDING_STEER_ENTRIES, PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES, PENDING_STEER_FROZEN_FIELDS, ACTOR_ASSERTION_FROZEN_FIELDS, MAX_ACTOR_FIELD_CHARS, MAX_STEER_INPUT_ID_CHARS, LEGACY_PENDING_STEER_INPUT_ID, riskSeverity, buildRiskDescriptor, summarizeCheckpoint, } from "./core/checkpoint-store.js";
73
73
  export { InMemoryUsageWindowStore, GLOBAL_USAGE_KEY, EMPTY_USAGE_WINDOW_RECORD, chargeUsageRecord, readUsageRecord, usageRetryAfterMs, resolveUsageWindows, } from "./core/usage-window-store.js";
74
74
  export { FileUsageWindowStore } from "./stores/file/usage-window-store.js";
75
75
  export { ENV_LIFETIME_SUSPEND_MARGIN_MS, USAGE_WINDOW_REAP_MARGIN_MS } from "./core/runner/prepare-task.js";
@@ -106,18 +106,22 @@ export { hasScheduler, isValidCronExpr, SchedulerError } from "./core/scheduler.
106
106
  export { createSchedulerTools, SCHEDULE_WAKEUP_TOOL_NAME, AUTONOMOUS_LOOP_SENTINEL, AUTONOMOUS_LOOP_DYNAMIC_SENTINEL, } from "./tools/scheduler-tools.js";
107
107
  export { resolveAutonomousLoopPrompt, AUTONOMOUS_LOOP_PREAMBLE, AUTONOMOUS_LOOP_PREAMBLE_PERSISTENT, } from "./tools/loop-tick.js";
108
108
  export { tightenTaskSpec, TaskSpecTightenError } from "./core/tighten-task-spec.js";
109
- export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, APPROVAL_SETTLED_BY_VALUES, isApprovalSettledBy, } from "./core/tool-policy.js";
109
+ export { createAllowDenyPolicy, createApprovalPolicy, COARSE_SHELL_TOOLS, createCoarseCommandNamePolicy, createTranscriptIntegrityPolicy, createUnverifiableDeletePolicy, findUnverifiableRecursiveDelete, combinePolicies, decisionText, resolveAsk, toolPolicyNameSets, checkToolPolicyProjection, constraintChainEntryOf, constraintChainDigest, APPROVAL_SETTLED_BY_VALUES, isApprovalSettledBy, } from "./core/tool-policy.js";
110
110
  export { parseAutoModeResponse, createAutoModeDecider, } from "./core/auto-mode.js";
111
111
  export { buildAutoModePrompt, renderAutoModeWindow, renderAutoModeAction, AUTO_MODE_DEFAULTS_SENTINEL, } from "./core/auto-mode-prompt.js";
112
112
  export { AUTO_MODE_BASE_PROMPT, AUTO_MODE_PERMISSIONS_EXTERNAL } from "./core/auto-mode-prompt-assets.js";
113
113
  export { createPermissionRulePolicy, validatePermissionRules, parsePermissionRule, wildcardMatch, } from "./core/permission-rules.js";
114
114
  export { parseAllowRuleText, formatAllowRuleText, ruleAdmitsCommand, findAdmittingRule, suggestRulesForCommand, scopeCoversCwd, pathWithinRoot, isRuleLive, BARE_INTERPRETER_NAMES, MAX_RULE_TEXT_CHARS, } from "./core/permission-rule-model.js";
115
- export { removePersistedRule, applyTombstones, sameScope, InMemoryPermissionRuleStore, EMPTY_RULE_STORE, } from "./core/permission-rule-store.js";
115
+ export { removePersistedRule, applyTombstones, sameScope, InMemoryPermissionRuleStore, EMPTY_RULE_STORE, joinRuleStates, screenRuleSyncState, collectBelowFrontier, ruleSyncVector, joinFrontiers, dotAtOrBelowFrontier, sameRuleOwner, } from "./core/permission-rule-store.js";
116
+ export { syncPermissionRules, parseRuleSyncResponse, PERMISSION_RULE_SYNC_PATH, LOCAL_OWNER_UNSYNCABLE_CODE, } from "./core/permission-rule-sync.js";
117
+ export { createOrgRuleOverlay, orgRuleVerdictFor, effectivePermissionRules, orgRuleStatePersistenceOf, ORG_UNAVAILABLE_DECISION_REASON, } from "./core/permission-rule-org.js";
118
+ export { RULE_SYNC_DROP_CODES } from "./core/governance-codes.js";
116
119
  export { prepareCardApproval, confirmRuleApproval, redeemRuleTicket, redeemRuleBatch, prepareCcImport, prepareStarterBatch, mintRuleTicket, STARTER_RULES, InMemoryRuleApprovalRecordStore, } from "./core/permission-rule-consent.js";
117
120
  export { FilePermissionRuleStoreProvider } from "./stores/file/permission-rule-store.js";
121
+ export { adoptFilePermissionRuleStore } from "./stores/file/permission-rule-adopt.js";
118
122
  export { formatHookFeedback, runToolGate, createHookEnvCapabilities, createPreToolUseConstraintPolicy, } from "./core/hooks.js";
119
123
  export { InMemoryMemoryStore, composeMemoryBlock, composeLayeredMemoryBlock, normalizeMemorySpec, supportsConsolidation, supportsPeriodicConsolidation, firstSentence, expandLexicalTerms, lexicalSearchMatch, classifyPromotable, enforcePromotableWriteGate, guardedMemoryStore, MemoryGateError, detectSecret, enforceSecretWriteGate, enforceStructuredNoteSecretGate, } from "./core/memory.js";
120
- export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, 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, 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";
124
+ export { MemoryEngine, FileMemoryEngineBackend, memoryBackendContract, assertMemoryBackendSearchEquivalence, buildMemoryInstruction, truncateIndex, scanEntryFiles, deriveRepoKey, deriveRepoMemoryDir, deriveControlPlaneDir, deriveRepoControlPlaneDir, resolveMemoryEngineRoot, scopeDirName, ControlPlaneCorruptError, parseEntryFile, serializeEntryFile, computeEntryRev, entryFromFile, MEMORY_INSTRUCTION_TEMPLATE, MEMORY_RECALL_DISCIPLINE, MEMORY_PREFERENCE_DISCIPLINE, readV2HeaderHints, LINEAGE_FILE, CHALLENGES_FILE, CHALLENGED_HISTORY_FILE, MEMORY_INDEX_FILENAME, MEMORY_INDEX_MAX_LINES, MEMORY_INDEX_MAX_BYTES, MEMORY_SEARCH_TOOL_NAME, MEMORY_GET_TOOL_NAME, MEMORY_ENGINE_TOOL_NAMES, 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, 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";
121
125
  export { SHARED_MEMORY_READ_CAP_BYTES, SHARED_MEMORY_LIST_PAGE_SIZE, SharedMemoryStoreError, } from "./core/shared-memory/types.js";
122
126
  export { sharedMemoryStoreContract, } from "./core/shared-memory/contract.js";
123
127
  export { termSet, jaccardDistance, cosineDistance } from "./core/memory-vector.js";
@@ -167,6 +171,7 @@ export { checkpointStoreContract } from "./core/store-contracts/checkpoint-store
167
171
  export { sessionRepoContract } from "./core/store-contracts/session-repo-contract.js";
168
172
  export { toolResultStoreContract } from "./core/store-contracts/tool-result-store-contract.js";
169
173
  export { fileSnapshotStoreContract } from "./core/store-contracts/file-snapshot-store-contract.js";
174
+ export { permissionRuleSyncContract } from "./core/store-contracts/permission-rule-sync-contract.js";
170
175
  export { MAILBOX_CONTRACT_SCOPE, mailboxStoreContract, mailboxAckOwnershipContract, mailboxBundledOnlyContract, } from "./core/store-contracts/mailbox-store-contract.js";
171
176
  export { BACKGROUND_AGENT_CONTRACT_SCOPE, backgroundAgentStoreContract, backgroundAgentStoreScopesContract, } from "./core/store-contracts/background-agent-store-contract.js";
172
177
  export { canAccessAgentRecord, STALE_RUNNING_REAP_ATTRIBUTION, BackgroundAgentStoreError, InMemoryBackgroundAgentStore, reconcileParkedAgents, queryBackgroundAgents, } from "./core/background-agent-store.js";
@@ -18,6 +18,10 @@ export declare class FileCheckpointStore implements CheckpointStore {
18
18
  * the loss is invisible until something reads the disk; the declaration is what makes it visible to
19
19
  * the mint BEFORE the row is filed. */
20
20
  readonly fidelity: "json";
21
+ /** F-012 L2: `reopen` here is a real resolved→pending CAS journaled to the ledger — declared, not sniffed. */
22
+ readonly redecision: {
23
+ readonly reopen: true;
24
+ };
21
25
  private readonly fsyncEnabled;
22
26
  private readonly compactEvery;
23
27
  /** RB-134: the directory's ONE authority (map + token mutex + append log), joined not rebuilt. */
@@ -61,6 +61,7 @@ const checkpointLedgers = new SharedLedgerTable({
61
61
  export class FileCheckpointStore {
62
62
  durability = "durable";
63
63
  fidelity = "json";
64
+ redecision = { reopen: true };
64
65
  fsyncEnabled;
65
66
  compactEvery;
66
67
  ledger;
@@ -0,0 +1,62 @@
1
+ /**
2
+ * design/182 §4.5 (F-011) — adopting a local rule bucket into a cloud principal: a RECOVERABLE state
3
+ * machine, not a rename.
4
+ *
5
+ * "Local first, connect later, keep everything" is the arc this helper carries. It is assembled from
6
+ * facts the store already holds — per-add provenance stores NO principal (so a rebind rewrites zero
7
+ * rows), the actor is a replica axis orthogonal to identity (so every dot stays valid), and the store
8
+ * seam is backend-agnostic (so the same contract covers a PG bucket, whose row-migration half lives on
9
+ * the server). What this file adds is ATOMICITY: an exclusive writer lock plus a durable intent marker
10
+ * whose `phase` field is a monotonically-advanced position — each mutating stage persists its phase
11
+ * BEFORE the next stage runs, so a crash anywhere resumes idempotently and no stage can lose bytes.
12
+ *
13
+ * ① take the write lock (a concurrent redemption/writer is refused loudly while adoption runs)
14
+ * ② land the durable intent marker → phase 2
15
+ * ③ rename the bucket file to the principal's → phase 3 (complete ⟺ target present ∧ source absent)
16
+ * ④ flip owner resolution — the marker IS the truth `forLocalOwner` reads, so publishing phase 4 is
17
+ * itself the switch; host configuration follows the marker, never the reverse → phase 4
18
+ * ⑤ first sync round against the (empty) cloud bucket — the full local state rides up → phase 5
19
+ * ⑥ rewrite the marker into its PERMANENT terminal record. Never deleted: after phase 4 the marker
20
+ * is the owner-resolution truth, and deleting it would resolve local-owner back to a retired empty
21
+ * bucket — rules gone from adjudication, new writes forking into a grave.
22
+ *
23
+ * A pre-existing TARGET bucket refuses the whole adoption: merging two existing buckets is a sync
24
+ * join, deliberately not a rename. Rows the far side refuses during ⑤ move to the local quarantine
25
+ * area — preserved and disclosed, never deleted (the F-011 "nothing is lost" floor).
26
+ */
27
+ import type { RuleOwner } from "../../core/permission-rule-store.js";
28
+ import { type PermissionRuleSyncResult, type PermissionRuleSyncTransport } from "../../core/permission-rule-sync.js";
29
+ export type AdoptFileRuleStoreResult =
30
+ /** The full arc completed (this call, or an earlier one — the terminal marker makes it idempotent). */
31
+ {
32
+ status: "adopted";
33
+ syncResult?: PermissionRuleSyncResult;
34
+ }
35
+ /** A stage failed. The marker holds the last COMPLETED phase; call again to resume from there.
36
+ * No bytes were lost — that is the state machine's whole contract. */
37
+ | {
38
+ status: "stalled";
39
+ phase: 2 | 3 | 4 | 5;
40
+ error: string;
41
+ };
42
+ /**
43
+ * Run (or resume) the adoption state machine for the bucket directory `dir`.
44
+ *
45
+ * Contract notes for the calling deployment:
46
+ * - stop (dispose) any live writer over this directory first — the adoption takes the same exclusive
47
+ * lock, and a live holder is refused loudly rather than interleaved with;
48
+ * - after the arc completes, run tasks under the NEW principal: a deployment still declaring
49
+ * local-owner resolves through the terminal marker to the adopted bucket (fail-closed against the
50
+ * retired one), but the honest configuration names the principal;
51
+ * - pending approval records are NOT migrated: their recorded owner stays historical, so an old
52
+ * ticket redeemed after adoption is refused by the existing owner-binding arm — the person simply
53
+ * sees the card again. That refusal is the invalidation mechanism, not a defect.
54
+ */
55
+ export declare function adoptFilePermissionRuleStore(opts: {
56
+ dir: string;
57
+ from: RuleOwner;
58
+ toPrincipal: string;
59
+ transport: PermissionRuleSyncTransport;
60
+ now?: () => number;
61
+ onError?: (message: string) => void;
62
+ }): Promise<AdoptFileRuleStoreResult>;