@sema-agent/core 5.20.0 → 5.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/agents/agent-definition.d.ts +7 -0
  3. package/dist/agents/agent-transcript-tool.d.ts +30 -0
  4. package/dist/agents/builtin-agents.d.ts +60 -0
  5. package/dist/agents/cascade.d.ts +107 -0
  6. package/dist/agents/cumulative-stats.d.ts +56 -0
  7. package/dist/agents/observer.d.ts +162 -0
  8. package/dist/agents/peer-admission.d.ts +95 -0
  9. package/dist/agents/repair-loop.d.ts +226 -0
  10. package/dist/agents/retain-ledger.d.ts +141 -0
  11. package/dist/agents/roster-store.d.ts +105 -0
  12. package/dist/agents/send-message-tool.d.ts +92 -0
  13. package/dist/agents/session-util.d.ts +5 -0
  14. package/dist/agents/subagent-steps.d.ts +66 -0
  15. package/dist/agents/subagent.d.ts +600 -0
  16. package/dist/agents/suspend-guard.d.ts +29 -0
  17. package/dist/agents/teacher.d.ts +75 -0
  18. package/dist/agents/team.d.ts +120 -1
  19. package/dist/agents/tool-filter.d.ts +34 -0
  20. package/dist/agents/verify.d.ts +198 -0
  21. package/dist/bench/metrics.d.ts +455 -0
  22. package/dist/brain/anthropic.d.ts +30 -0
  23. package/dist/brain/circuit-breaker.d.ts +33 -0
  24. package/dist/brain/context-overflow.d.ts +60 -3
  25. package/dist/brain/degrading.d.ts +67 -0
  26. package/dist/brain/errors.d.ts +42 -0
  27. package/dist/brain/failover.d.ts +15 -0
  28. package/dist/brain/media-degrade.d.ts +39 -0
  29. package/dist/brain/model-presets.d.ts +31 -0
  30. package/dist/brain/open-responses.d.ts +19 -0
  31. package/dist/brain/openai.d.ts +46 -0
  32. package/dist/brain/reasoning.d.ts +106 -1
  33. package/dist/brain/repetition.d.ts +83 -0
  34. package/dist/brain/request-params.d.ts +56 -0
  35. package/dist/brain/retry.d.ts +46 -0
  36. package/dist/brain/routing.d.ts +12 -0
  37. package/dist/brain/status-sink.d.ts +30 -1
  38. package/dist/brain/stream-engine.d.ts +147 -0
  39. package/dist/brain/stream-shared.d.ts +34 -0
  40. package/dist/brain/terminal-cause.d.ts +31 -0
  41. package/dist/brain/timeout.d.ts +107 -0
  42. package/dist/brain/tool-call-id.d.ts +20 -0
  43. package/dist/brain/tool-call-repair.d.ts +13 -0
  44. package/dist/config/catalog.d.ts +47 -0
  45. package/dist/config/defaults.d.ts +33 -0
  46. package/dist/core/a2a-task-state.d.ts +53 -0
  47. package/dist/core/a2a.d.ts +51 -0
  48. package/dist/core/arg-summary.d.ts +62 -0
  49. package/dist/core/ask-question.d.ts +272 -2
  50. package/dist/core/auto-compaction.d.ts +467 -0
  51. package/dist/core/auto-compaction.js +20 -6
  52. package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
  53. package/dist/core/auto-mode-prompt.d.ts +27 -0
  54. package/dist/core/auto-mode.d.ts +54 -3
  55. package/dist/core/auto-promote.d.ts +100 -0
  56. package/dist/core/background-agent-store.d.ts +292 -0
  57. package/dist/core/background-shell.d.ts +110 -0
  58. package/dist/core/cache-break-detector.d.ts +34 -0
  59. package/dist/core/canonical-json.d.ts +57 -0
  60. package/dist/core/checkpoint-store.d.ts +1574 -16
  61. package/dist/core/compliance.d.ts +30 -0
  62. package/dist/core/consolidate-scope.d.ts +75 -0
  63. package/dist/core/context-edit.d.ts +99 -0
  64. package/dist/core/context-guard.d.ts +46 -0
  65. package/dist/core/exec-gate.d.ts +44 -0
  66. package/dist/core/exec-output-tail.d.ts +61 -0
  67. package/dist/core/file-snapshot-store.d.ts +104 -0
  68. package/dist/core/fs-write-gate-policy.d.ts +36 -0
  69. package/dist/core/git-worktree-env.d.ts +31 -0
  70. package/dist/core/governance-codes.d.ts +19 -0
  71. package/dist/core/hooks.d.ts +608 -1
  72. package/dist/core/human-input-projection.d.ts +37 -0
  73. package/dist/core/human-input-projection.js +13 -0
  74. package/dist/core/image-downsample.d.ts +74 -0
  75. package/dist/core/locked-config.d.ts +37 -0
  76. package/dist/core/lsp-diagnostics.d.ts +77 -0
  77. package/dist/core/lsp-protocol.d.ts +29 -0
  78. package/dist/core/lsp-session.d.ts +60 -1
  79. package/dist/core/lsp.d.ts +150 -1
  80. package/dist/core/mailbox-store.d.ts +57 -0
  81. package/dist/core/mcp.d.ts +381 -0
  82. package/dist/core/media-byte-cap.d.ts +21 -0
  83. package/dist/core/memory-admission.d.ts +71 -0
  84. package/dist/core/memory-engine/content-origin.d.ts +64 -0
  85. package/dist/core/memory-engine/data-plane.d.ts +43 -0
  86. package/dist/core/memory-engine/dual-root.d.ts +24 -0
  87. package/dist/core/memory-engine/engine.d.ts +230 -0
  88. package/dist/core/memory-engine/engine.js +103 -35
  89. package/dist/core/memory-engine/file-backend.d.ts +155 -0
  90. package/dist/core/memory-engine/frontmatter.d.ts +16 -0
  91. package/dist/core/memory-engine/layout.d.ts +217 -0
  92. package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
  93. package/dist/core/memory-engine/migrate.d.ts +9 -0
  94. package/dist/core/memory-engine/scan.d.ts +12 -0
  95. package/dist/core/memory-engine/scope-contract.d.ts +61 -1
  96. package/dist/core/memory-engine/sync-client.d.ts +87 -0
  97. package/dist/core/memory-engine/sync.d.ts +60 -0
  98. package/dist/core/memory-engine/tools.d.ts +41 -0
  99. package/dist/core/memory-engine/types.d.ts +188 -0
  100. package/dist/core/memory-recall.d.ts +141 -0
  101. package/dist/core/memory-vector.d.ts +20 -0
  102. package/dist/core/memory.d.ts +458 -0
  103. package/dist/core/message-utils.d.ts +6 -0
  104. package/dist/core/oracle-isolation.d.ts +69 -0
  105. package/dist/core/permission-rule-consent.d.ts +138 -0
  106. package/dist/core/permission-rule-model.d.ts +122 -0
  107. package/dist/core/permission-rule-store.d.ts +119 -3
  108. package/dist/core/permission-rules.d.ts +87 -1
  109. package/dist/core/present-plan-tool.d.ts +20 -0
  110. package/dist/core/pricing.d.ts +26 -0
  111. package/dist/core/property-harness.d.ts +86 -0
  112. package/dist/core/protocol-naming.d.ts +38 -0
  113. package/dist/core/protocol-table.d.ts +61 -0
  114. package/dist/core/push-queue.d.ts +1 -0
  115. package/dist/core/remote-env.d.ts +383 -1
  116. package/dist/core/retention-policy.d.ts +33 -0
  117. package/dist/core/retention.d.ts +51 -0
  118. package/dist/core/roles.d.ts +59 -0
  119. package/dist/core/runner/active-skill-scope.d.ts +34 -0
  120. package/dist/core/runner/assemble-result.d.ts +134 -0
  121. package/dist/core/runner/compaction-call-options.d.ts +97 -1
  122. package/dist/core/runner/grounding-signal.d.ts +10 -0
  123. package/dist/core/runner/image.d.ts +17 -0
  124. package/dist/core/runner/image.js +29 -15
  125. package/dist/core/runner/memory-consolidation.d.ts +60 -0
  126. package/dist/core/runner/prepare-memory.d.ts +59 -0
  127. package/dist/core/runner/prepare-task.d.ts +1011 -2
  128. package/dist/core/runner/prepare-task.js +12 -11
  129. package/dist/core/runner/prompt-suggestions.d.ts +7 -0
  130. package/dist/core/runner/runtask.d.ts +304 -3
  131. package/dist/core/runner/session-file-state-replay.d.ts +49 -0
  132. package/dist/core/runner/session-rule-policy.d.ts +58 -0
  133. package/dist/core/runner/strict-output-schema.d.ts +18 -3
  134. package/dist/core/runner/synthetic-tools.d.ts +113 -0
  135. package/dist/core/runner/teardown-bounded.d.ts +34 -0
  136. package/dist/core/runner/tool-disclosure.d.ts +227 -0
  137. package/dist/core/runner/tool-output-projection.d.ts +6 -0
  138. package/dist/core/runner/turn-attachments.d.ts +634 -0
  139. package/dist/core/runner/usage-accounting.d.ts +32 -0
  140. package/dist/core/runtime.d.ts +9 -0
  141. package/dist/core/safe-notify.d.ts +64 -0
  142. package/dist/core/safety-axis-vocab.d.ts +23 -0
  143. package/dist/core/safety-merge-corpus.d.ts +37 -0
  144. package/dist/core/scheduler.d.ts +121 -0
  145. package/dist/core/secret-env.d.ts +32 -0
  146. package/dist/core/select-model.d.ts +15 -0
  147. package/dist/core/sensitive-path-policy.d.ts +42 -0
  148. package/dist/core/session-policy-store.d.ts +94 -0
  149. package/dist/core/session-reconcile.d.ts +80 -0
  150. package/dist/core/session-store.d.ts +85 -0
  151. package/dist/core/session.d.ts +153 -0
  152. package/dist/core/shared-memory/contract.d.ts +22 -0
  153. package/dist/core/shared-memory/normalize.d.ts +123 -2
  154. package/dist/core/shared-memory/tools.d.ts +14 -0
  155. package/dist/core/shared-memory/types.d.ts +105 -0
  156. package/dist/core/shutdown-debug.d.ts +6 -0
  157. package/dist/core/side-query.d.ts +38 -0
  158. package/dist/core/side-query.js +6 -1
  159. package/dist/core/skill-tool-specifier.d.ts +72 -0
  160. package/dist/core/skills-directory.d.ts +100 -1
  161. package/dist/core/spec-contract.d.ts +89 -0
  162. package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
  163. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
  164. package/dist/core/store-contracts/contract-harness.d.ts +20 -0
  165. package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
  166. package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
  167. package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
  168. package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
  169. package/dist/core/strategy-store.d.ts +37 -0
  170. package/dist/core/stub-env.d.ts +7 -0
  171. package/dist/core/surrogate-safe-slice.d.ts +35 -0
  172. package/dist/core/task-notification.d.ts +202 -0
  173. package/dist/core/task-outcome.d.ts +53 -0
  174. package/dist/core/task-registry-agent.d.ts +337 -1
  175. package/dist/core/task-registry-monitor.d.ts +12 -0
  176. package/dist/core/task-registry-shared.d.ts +540 -0
  177. package/dist/core/task-registry.d.ts +343 -0
  178. package/dist/core/task-registry.js +13 -2
  179. package/dist/core/task-tool-shape.d.ts +44 -0
  180. package/dist/core/tighten-task-spec.d.ts +21 -0
  181. package/dist/core/tool-detach.d.ts +21 -0
  182. package/dist/core/tool-errors.d.ts +131 -0
  183. package/dist/core/tool-errors.js +4 -0
  184. package/dist/core/tool-name-aliases.d.ts +27 -0
  185. package/dist/core/tool-policy.d.ts +555 -0
  186. package/dist/core/tool-result-budget.d.ts +32 -0
  187. package/dist/core/tool-result-store.d.ts +174 -1
  188. package/dist/core/tools.d.ts +45 -0
  189. package/dist/core/trace.d.ts +323 -0
  190. package/dist/core/types.d.ts +3859 -2
  191. package/dist/core/untrusted-egress.d.ts +8 -0
  192. package/dist/core/untrusted-text.d.ts +156 -0
  193. package/dist/core/usage-window-store.d.ts +95 -0
  194. package/dist/core/version.d.ts +1 -0
  195. package/dist/core/warm-resume.d.ts +17 -0
  196. package/dist/core/wiring-manifest.d.ts +169 -0
  197. package/dist/core/with-retry.d.ts +24 -0
  198. package/dist/core/workflow-journal-store.d.ts +160 -0
  199. package/dist/core/workflow-run-store-contract.d.ts +25 -0
  200. package/dist/core/workflow-run-store.d.ts +119 -0
  201. package/dist/engine/compaction/compaction.d.ts +256 -1
  202. package/dist/engine/compaction/utils.d.ts +94 -0
  203. package/dist/engine/execution-env/kill-tree.d.ts +29 -0
  204. package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
  205. package/dist/engine/harness/agent-harness.d.ts +116 -0
  206. package/dist/engine/harness/agent-harness.js +3 -14
  207. package/dist/engine/harness/messages.d.ts +15 -0
  208. package/dist/engine/harness/types.d.ts +464 -2
  209. package/dist/engine/llm/diagnostics.d.ts +4 -0
  210. package/dist/engine/llm/event-stream.d.ts +3 -0
  211. package/dist/engine/llm/index.d.ts +7 -0
  212. package/dist/engine/llm/types.d.ts +500 -3
  213. package/dist/engine/llm/validation.d.ts +3 -0
  214. package/dist/engine/loop/agent-loop.d.ts +87 -2
  215. package/dist/engine/loop/runtime-deps.d.ts +7 -0
  216. package/dist/engine/loop/types.d.ts +424 -0
  217. package/dist/engine/lsp/frame-decoder.d.ts +13 -0
  218. package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
  219. package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
  220. package/dist/engine/session/import-validate.d.ts +27 -0
  221. package/dist/engine/session/log-digest.d.ts +93 -0
  222. package/dist/engine/session/memory-repo.d.ts +6 -0
  223. package/dist/engine/session/memory-storage.d.ts +2 -0
  224. package/dist/engine/session/session.d.ts +75 -0
  225. package/dist/engine/session/storage-base.d.ts +8 -0
  226. package/dist/fixtures/index.d.ts +36 -0
  227. package/dist/index.d.ts +16 -1
  228. package/dist/index.js +0 -1
  229. package/dist/internal/harness-types.d.ts +6 -0
  230. package/dist/internal/harness.d.ts +11 -0
  231. package/dist/internal/llm.d.ts +6 -0
  232. package/dist/orchestration/builtin-workflows.d.ts +53 -0
  233. package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
  234. package/dist/orchestration/goal.d.ts +57 -0
  235. package/dist/orchestration/goal.js +3 -0
  236. package/dist/orchestration/run-spec.d.ts +42 -0
  237. package/dist/orchestration/run-workflow-tool.d.ts +169 -0
  238. package/dist/orchestration/workflow-governance.d.ts +61 -0
  239. package/dist/orchestration/workflow-meta.d.ts +28 -0
  240. package/dist/orchestration/workflow-observe.d.ts +60 -0
  241. package/dist/orchestration/workflow-primitives.d.ts +23 -1
  242. package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
  243. package/dist/orchestration/workflow-script-runner.d.ts +88 -0
  244. package/dist/orchestration/workflow-script-store.d.ts +98 -0
  245. package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
  246. package/dist/orchestration/workflow-types.d.ts +169 -2
  247. package/dist/orchestration/workflow.d.ts +358 -0
  248. package/dist/prompt-assembly/artifact-store.d.ts +33 -0
  249. package/dist/prompt-assembly/artifact.d.ts +25 -0
  250. package/dist/prompt-assembly/assemble.d.ts +20 -0
  251. package/dist/prompt-assembly/composer.d.ts +29 -0
  252. package/dist/prompt-assembly/epoch.d.ts +55 -1
  253. package/dist/prompt-assembly/event-registry.d.ts +35 -0
  254. package/dist/prompt-assembly/explain.d.ts +12 -0
  255. package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
  256. package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
  257. package/dist/prompt-assembly/types.d.ts +115 -0
  258. package/dist/prompts/coordinator.d.ts +27 -0
  259. package/dist/prompts/default.d.ts +539 -0
  260. package/dist/prompts/simple-sections.d.ts +45 -0
  261. package/dist/prompts/supervisor.d.ts +66 -0
  262. package/dist/scenarios/env.d.ts +28 -0
  263. package/dist/scenarios/full-body.d.ts +50 -0
  264. package/dist/scenarios/scenario-registry.d.ts +60 -0
  265. package/dist/scenarios/teacher-quickstart.d.ts +27 -0
  266. package/dist/server/http.d.ts +17 -0
  267. package/dist/stores/cc/lockfile.d.ts +6 -0
  268. package/dist/stores/cc/mailbox-store.d.ts +8 -0
  269. package/dist/stores/cc/roster-adapter.d.ts +4 -0
  270. package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
  271. package/dist/stores/file/background-agent-store.d.ts +24 -0
  272. package/dist/stores/file/checkpoint-store.d.ts +38 -0
  273. package/dist/stores/file/file-snapshot-store.d.ts +25 -0
  274. package/dist/stores/file/fs-atomic.d.ts +155 -0
  275. package/dist/stores/file/index.d.ts +89 -0
  276. package/dist/stores/file/mailbox-store.d.ts +36 -0
  277. package/dist/stores/file/memory-store.d.ts +82 -0
  278. package/dist/stores/file/permission-rule-store.d.ts +79 -0
  279. package/dist/stores/file/session-policy-store.d.ts +28 -0
  280. package/dist/stores/file/session-store.d.ts +40 -0
  281. package/dist/stores/file/shared-ledger.d.ts +83 -0
  282. package/dist/stores/file/tool-result-store.d.ts +11 -0
  283. package/dist/stores/file/usage-window-store.d.ts +18 -0
  284. package/dist/stores/file/workflow-journal-store.d.ts +100 -0
  285. package/dist/stores/file/workflow-run-store.d.ts +11 -0
  286. package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
  287. package/dist/tools/fs/encoding.d.ts +60 -0
  288. package/dist/tools/fs/fs-bash.d.ts +133 -0
  289. package/dist/tools/fs/fs-pdf.d.ts +28 -0
  290. package/dist/tools/fs/fs-search-tools.d.ts +5 -0
  291. package/dist/tools/fs/fs-search-tools.js +0 -1
  292. package/dist/tools/fs/fs-shared.d.ts +360 -0
  293. package/dist/tools/fs/fs-write.d.ts +16 -0
  294. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  295. package/dist/tools/fs/index.d.ts +79 -0
  296. package/dist/tools/fs/notebook.d.ts +56 -0
  297. package/dist/tools/fs/pdf.d.ts +70 -0
  298. package/dist/tools/fs/pdf.js +8 -2
  299. package/dist/tools/fs/repo-map.d.ts +10 -0
  300. package/dist/tools/fs/safety.d.ts +376 -0
  301. package/dist/tools/fs/search.d.ts +131 -0
  302. package/dist/tools/loop-tick.d.ts +24 -0
  303. package/dist/tools/monitor.d.ts +55 -0
  304. package/dist/tools/scheduler-tools.d.ts +51 -0
  305. package/dist/tools/sql-adapters.d.ts +18 -0
  306. package/dist/tools/sql.d.ts +25 -0
  307. package/dist/tools/task-list.d.ts +77 -0
  308. package/dist/tools/todo.d.ts +8 -0
  309. package/dist/tools/web.d.ts +184 -0
  310. package/dist/tools/worktree.d.ts +81 -0
  311. package/package.json +2 -2
  312. package/dist/tools/gitea-issue.d.ts +0 -13
  313. package/dist/tools/gitea-issue.js +0 -75
@@ -1,17 +1,36 @@
1
1
  import { type BackgroundAgentReapOptions, type BackgroundAgentRecord, type BackgroundAgentRowSummary, type BackgroundAgentStore, type BackgroundAgentUpdateIfExpect } from "../../core/background-agent-store.js";
2
2
  export interface FileBackgroundAgentStoreOptions {
3
+ /** When false, a ledger append is NOT fsync'd. Default true. */
3
4
  fsync?: boolean;
5
+ /** Compact the ledger into a snapshot once it exceeds this many events (then truncate). Default 1000. */
4
6
  compactEvery?: number;
5
7
  }
6
8
  export declare class FileBackgroundAgentStore implements BackgroundAgentStore {
7
9
  private readonly fsyncEnabled;
8
10
  private readonly compactEvery;
11
+ /** RB-55: all mutable state is SHARED per canonical directory (see the note above the class). */
9
12
  private readonly ledger;
13
+ /** RB-145: this instance's own close latch — the refcount belongs to the DIRECTORY, not to callers. */
10
14
  private closed;
11
15
  private get rows();
12
16
  constructor(root: string, opts?: FileBackgroundAgentStoreOptions);
17
+ /**
18
+ * RB-60 (2026-07-25, red probe): the composite key must be INJECTIVE — `get`/`update` no longer re-check
19
+ * scope, so tenant isolation rests entirely on this function. A SPACE separator is not injective
20
+ * (`scope="a", handle="b c"` and `scope="a b", handle="c"` produce the same key), which let one tenant's
21
+ * row collide with another's. The in-memory reference implementation (`core/background-agent-store.ts`)
22
+ * uses `\u0000` for exactly this reason ("the composite key keeps the info-hiding property structural") —
23
+ * a NUL can never occur in a scope or handle, so the mapping is injective. Matching it also restores this
24
+ * backend's stated "byte-for-byte the InMemory reference implementation's" claim.
25
+ *
26
+ * MIGRATION: the key is IN-MEMORY only (the ledger stores whole records with their own `scope`/`handle`
27
+ * fields, and replay rebuilds keys through this function), so changing the separator needs no on-disk
28
+ * migration — an existing directory replays into the new key space on next open.
29
+ */
13
30
  static key(handle: string, scope: string): string;
14
31
  private withLock;
32
+ /** Durable append FIRST, in-memory flip AFTER, then best-effort compaction — all in the base
33
+ * (RB-150/RB-167: a failing housekeeping compaction must never be reported as this CAS failing). */
15
34
  private commit;
16
35
  put(record: BackgroundAgentRecord): Promise<void>;
17
36
  get(handle: string, scope: string): Promise<BackgroundAgentRecord | null>;
@@ -32,7 +51,12 @@ export declare class FileBackgroundAgentStore implements BackgroundAgentStore {
32
51
  rev: number;
33
52
  }): Promise<boolean>;
34
53
  reap(scope: string, now: number, opts?: BackgroundAgentReapOptions): Promise<number>;
54
+ /** Force a compaction now (test/inspection). RB-167's closeForSwap recipe lives in the base. */
35
55
  compactNow(): void;
56
+ /** Test/inspection helper: number of stored rows. */
36
57
  get size(): number;
58
+ /** Release the append handle (best-effort). RB-55: refcounted — the directory's shared authority
59
+ * (rows/locks/log) is torn down only when the LAST instance over it closes, so a sibling instance
60
+ * is never left holding a closed fd or a half-dropped view. */
37
61
  close(): void;
38
62
  }
@@ -1,19 +1,44 @@
1
1
  import { type Checkpoint, type PendingSteerInput, type CheckpointFaultMode, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type ReopenReason, type ResolveExpectation, type ResumeOutcome } from "../../core/checkpoint-store.js";
2
2
  export interface FileCheckpointStoreOptions {
3
+ /** When false, an `appendLine` for a state transition is NOT fsync'd. The checkpoint COMMIT POINT always
4
+ * fsyncs regardless (its crash-safety depends on it); this only affects whether `put` fsyncs. Default true. */
3
5
  fsync?: boolean;
6
+ /** Compact the ledger into a snapshot once it exceeds this many events (then truncate). Default 1000. */
4
7
  compactEvery?: number;
5
8
  }
6
9
  export declare class FileCheckpointStore implements CheckpointStore {
10
+ /** design/173 §2.3 — honest declaration on the restart-survival axis the vocabulary claims: rows
11
+ * live on disk (fsync'd append log) and survive a process restart. Multi-replica coordination is
12
+ * NOT claimed by this axis (see {@link StoreDurability}) — this backend is deliberately
13
+ * single-instance-per-data-dir (the boot lock refuses a second process); Pg/TiDB own that. */
7
14
  readonly durability: "durable";
15
+ /** Honest declaration on the fidelity axis: the ledger is JSONL, so what survives the restart this
16
+ * backend promises is the JSON PROJECTION of the row — a `Date` replays as its ISO string, a
17
+ * `Map`/`Set` as `{}`, `NaN` as `null`. The in-process map holds the structured clone, which is why
18
+ * the loss is invisible until something reads the disk; the declaration is what makes it visible to
19
+ * the mint BEFORE the row is filed. */
8
20
  readonly fidelity: "json";
9
21
  private readonly fsyncEnabled;
10
22
  private readonly compactEvery;
23
+ /** RB-134: the directory's ONE authority (map + token mutex + append log), joined not rebuilt. */
11
24
  private readonly ledger;
12
25
  private closed;
13
26
  private get cps();
27
+ /** One-shot crash fault (mirrors `InMemoryCheckpointStore.testInjectFault`). */
14
28
  private fault;
15
29
  constructor(root: string, opts?: FileCheckpointStoreOptions);
30
+ /** Serialize an op behind any in-flight op on the same token (the in-process per-token async mutex). */
16
31
  private withLock;
32
+ /**
33
+ * Commit one ledger event (append + fsync) THEN flip the in-memory map (crash-safe ordering, §2.4).
34
+ *
35
+ * RB-150 (2026-07-25, cross-backend differential): the compaction that may follow is HOUSEKEEPING and
36
+ * runs AFTER the operation is durable and the memory flip has happened — so its failure must never be
37
+ * reported as the operation's failure. It was: a snapshot write hitting EACCES made `resolve()` REJECT
38
+ * while the row was already `resolved` and the winner recorded, i.e. a consumed approval presented to
39
+ * the caller as "this did not happen" — the worst possible direction for a once-only gate, and something
40
+ * the in-memory reference cannot do because it has no I/O here. Both halves are now in the base.
41
+ */
17
42
  private commit;
18
43
  put(token: CheckpointToken, cp: Checkpoint): Promise<void>;
19
44
  get(token: CheckpointToken): Promise<Checkpoint | null>;
@@ -24,8 +49,21 @@ export declare class FileCheckpointStore implements CheckpointStore {
24
49
  reap(scope: string, cutoff: number): Promise<number>;
25
50
  listByScope(scope: string): Promise<CheckpointSummary[]>;
26
51
  listScopes(): Promise<string[]>;
52
+ /** Force a compaction now (test/inspection). The snapshot rewrite + RB-167 closeForSwap swap that
53
+ * makes `replay` read the full state from the snapshot alone is the base's {@link LedgerCore.compact}. */
27
54
  compactNow(): void;
55
+ /** Arm a one-shot fault on the next `resolve` (mirrors InMemory `testInjectFault`, council #5). */
28
56
  testInjectFault(mode: CheckpointFaultMode | null): void;
57
+ /** Test/inspection helper: number of stored checkpoints. */
29
58
  get size(): number;
59
+ /**
60
+ * Release the append handle (best-effort). The boot LOCK is released by the backend factory.
61
+ *
62
+ * RB-134: refcounted, and the LAST holder REVOKES the directory's authority. Adding the shared table
63
+ * without this would have repeated RB-73's mistake exactly — a cache with no invalidation: after a
64
+ * `close()` the next `new FileCheckpointStore(sameRoot)` joined a table whose log was already closed and
65
+ * every write threw `log_closed`, instead of replaying the on-disk truth into a fresh authority. Idempotent:
66
+ * a second `close()` on the same instance must not decrement someone else's share.
67
+ */
30
68
  close(): void;
31
69
  }
@@ -1,6 +1,18 @@
1
1
  import type { ExecutionEnv } from "../../internal/harness-types.js";
2
2
  import { type FileSnapshotBounds, type FileSnapshotResult, type FileSnapshotStore } from "../../core/file-snapshot-store.js";
3
3
  export interface FileFileSnapshotStoreOptions {
4
+ /**
5
+ * Disclosure sink for a durable read this store treats as ABSENT (ruled 2026-08-03). Same name and
6
+ * same `{path, reason}` shape as the sibling file stores' seat — "unreadable read as missing" and
7
+ * "corrupt read as missing" are one failure grammar, so they get one seat name.
8
+ *
9
+ * Fires for: a corrupt/unreadable MANIFEST collapsed to "no snapshot" (the never-throw seam's
10
+ * documented fail-open — `has`/`restore`/`exportManifest`/`listKeys` all report absence), an
11
+ * unreadable manifest DIRECTORY that degrades an enumeration to "no keys", and a blob-GC pass that
12
+ * aborted because its live set could not be completed (blobs are kept — leaked, not lost).
13
+ *
14
+ * Never fires on plain ENOENT: a scope with no snapshots yet really is empty. Swallow-guarded.
15
+ */
4
16
  onCorruptRead?: (info: {
5
17
  path: string;
6
18
  reason: string;
@@ -10,14 +22,27 @@ export declare class FileFileSnapshotStore implements FileSnapshotStore {
10
22
  private readonly base;
11
23
  private readonly blobsDir;
12
24
  private readonly manifestsDir;
25
+ /**
26
+ * RB-163 (2026-07-26): the in-flight blob set is authority over a DIRECTORY, so it lives with the
27
+ * directory. On the instance, a second store on the same base ran `reap()` while the first was midway
28
+ * through `importManifest` — its live set did not include the peer's in-flight blobs, so it collected
29
+ * blobs the peer had already published, and the import still reported `ok` with a manifest referencing
30
+ * files that no longer exist. Keyed by {@link canonicalStoreKey} so two spellings of one directory
31
+ * cannot each keep their own idea of what is in flight.
32
+ */
13
33
  private get inFlight();
14
34
  private readonly inFlightKey;
15
35
  private readonly bounds;
16
36
  private readonly onCorruptRead;
17
37
  constructor(root: string, bounds?: Partial<FileSnapshotBounds>, opts?: FileFileSnapshotStoreOptions);
38
+ /** The one delivery point for {@link FileFileSnapshotStoreOptions.onCorruptRead}; swallow-guarded
39
+ * here so no call site has to remember (and so the never-throw seam contract cannot be broken by a
40
+ * host's sink). */
18
41
  private disclose;
19
42
  private scopeDir;
20
43
  private manifestPath;
44
+ /** manifestPath, but a key that fails the strict path-component guard → null (so the seam's NEVER-throw
45
+ * contract holds for a direct SDK caller; engine keys are uuidv7 so this never fires in practice). */
21
46
  private tryManifestPath;
22
47
  private blobPath;
23
48
  private readManifest;
@@ -1,34 +1,189 @@
1
+ /**
2
+ * Validate an engine-minted id (sessionId / tool-result ref) before using it as a path component. These are
3
+ * `uuidv7` / `tr_<sessionId>_<toolCallId>` — already filename-safe — but a strict guard is cheap
4
+ * defense-in-depth: reject `.`/`..`/empty/separators so nothing can traverse out of the store dir.
5
+ */
1
6
  export declare function sanitizePathComponent(raw: string): string;
7
+ /**
8
+ * Map a model-influenced memory `scope` to a safe directory name (CC `sanitizePath` parity). Replace every
9
+ * non-alphanumeric run with `-`; if the result is over 200 chars, append a short content hash so two long
10
+ * scopes can't collide. The ORIGINAL scope is the partition key the engine passes — this only affects the
11
+ * on-disk dir name, never the stored data. Never `path.join` a raw scope.
12
+ */
2
13
  export declare function sanitizeScope(scope: string): string;
14
+ /**
15
+ * Resolve the data root (CC `getClaudeConfigHomeDir` analog): `$AGENT_DATA_DIR ?? ~/.ai-agent`,
16
+ * NFC-normalized, and `realpath`-canonicalized once the dir exists. Creates the dir (0o700) if absent.
17
+ */
3
18
  export declare function resolveDataRoot(explicit?: string): string;
19
+ /** Ensure a directory exists with 0o700 perms (idempotent). */
20
+ /**
21
+ * Atomically CREATE `target` carrying `content` — it appears in ONE step already fully written, no empty/partial
22
+ * window. Fixes the create-then-write race (codex review BUG-1/BUG-3): a reader/pruner can see a half-written
23
+ * file, and a crash mid-write leaves a zero-byte target a retry would silently keep. Writes a temp in `target`'s
24
+ * OWN dir (same FS → `link` is atomic) + fsync, then `linkSync`-publishes it; throws `EEXIST` if `target` exists.
25
+ */
4
26
  export declare function writeThenLink(target: string, content: string | Uint8Array): void;
5
27
  export declare function ensureDir(dir: string): void;
28
+ /**
29
+ * The 5-step atomic whole-file replace (§2.1). Skipping any of steps 3/5/6 is the classic corruption bug:
30
+ * 1. open a temp under `root/tmp/` (same FS → rename is atomic),
31
+ * 2. write the bytes,
32
+ * 3. fsync the DATA (else ext4 "zero-length file after crash"),
33
+ * 4. close → rename(tmp, target) (atomic intra-FS namespace swap),
34
+ * 5. fsync the containing DIRECTORY (persists the rename itself).
35
+ * On any failure the temp is unlinked so a crashed write leaves no scratch behind.
36
+ */
6
37
  export declare function atomicWriteFile(tmpDir: string, target: string, bytes: string): void;
38
+ /**
39
+ * Read a JSONL file and return every COMPLETE, parseable record — the universal torn-tail recovery (§2.2):
40
+ * - a trailing line with no terminating `\n` (a crash mid-write) is discarded,
41
+ * - any line (interior or tail) that fails `JSON.parse` is skipped (never throws — `listRemoteAgentMetadata`
42
+ * parity), so a single corrupt interior line never poisons the whole replay.
43
+ * A missing file → `[]`. This is why JSONL beats one big JSON blob: a torn tail can never corrupt the store.
44
+ *
45
+ * `onCorrupt` (optional, review-510 disclosure-seat family): fired once per skipped INTERIOR record so a
46
+ * caller-side seat can observe real corruption — a silently-skipped record is otherwise indistinguishable
47
+ * from "less data". The torn TAIL stays out of it by design: dying mid-write is the documented crash
48
+ * shape this format exists to absorb, not corruption. The callback is invoked as given — a seat that
49
+ * must not throw swallow-guards on ITS side (the stores do).
50
+ */
7
51
  export declare function readJsonlRecords<T>(path: string, onCorrupt?: (info: {
8
52
  path: string;
9
53
  reason: string;
10
54
  }) => void): T[];
55
+ /**
56
+ * An append-only JSONL log opened once with `O_APPEND` and held for the file's lifetime. One record =
57
+ * one `JSON.stringify(...) + "\n"` written in a SINGLE `writeSync` call (never split across writes → the
58
+ * only torn line possible is a crash tail, which {@link readJsonlRecords} drops). `fsync` is opt-in per
59
+ * append (the checkpoint commit point ALWAYS fsyncs; session/memory cadence is the caller's `fsyncEvery`).
60
+ */
61
+ /**
62
+ * RB-144 (2026-07-25, 按面收口): THE canonical key for "one authority per physical location".
63
+ *
64
+ * Every file backend keeps a module-level table so that N instances over one directory collapse into one
65
+ * CAS authority. Getting the KEY wrong reopens the exact defect the table exists to close — and this repo
66
+ * has now paid for that four separate times: RB-62 taught the mailbox to realpath, RB-101 taught the
67
+ * session store, RB-119 added case folding there, and a defect hunt then found the agent store, the run store
68
+ * and the task-list still keying on a lexical `resolve()` while two of them cite the mailbox as the
69
+ * precedent they copied. Point fixes kept missing siblings, so the rule now lives in ONE place that all of
70
+ * them call.
71
+ *
72
+ * Two normalizations, each for a demonstrated failure:
73
+ * - REALPATH — a symlinked data dir (`/var` → `/private/var` on macOS, a container bind-mount, a linked
74
+ * `~/.ai-agent`) otherwise yields two authorities for one directory, and both writers win the CAS.
75
+ * - CASE FOLD — on a case-insensitive filesystem (macOS/Windows default) `Foo/` and `foo/` are the same
76
+ * directory; `realpath` does NOT fold case there, so realpath alone is not enough (measured).
77
+ *
78
+ * The key is used ONLY for table lookup — never for I/O, so the on-disk name stays verbatim. A path that
79
+ * does not exist yet resolves through its parent directory; if even that fails, the lexical form is used
80
+ * (a store must not fail to construct because canonicalization is unavailable).
81
+ */
11
82
  export declare function canonicalStoreKey(p: string): string;
12
83
  export declare class AppendLog {
13
84
  private fd;
85
+ /**
86
+ * RB-167 (2026-07-26): distinguishes "closed because the holder is done with it" from "closed for a
87
+ * compaction swap". Only the first is permanent.
88
+ *
89
+ * Every store that compacts does close → rewrite → reopen, and the rewrite can fail (EACCES, ENOSPC, a
90
+ * read-only mount, an immutable flag). The stores handled that in three different and individually
91
+ * insufficient ways: three of them left the log CLOSED FOREVER, so one transient I/O error turned into
92
+ * `log_closed` on every later write — and because these logs are now SHARED per directory, that bricks
93
+ * every instance on it, not just the one that compacted. The fourth reopened in a `finally`, which only
94
+ * covers the failure shapes where reopening still works and, worse, replaces the original error with the
95
+ * reopen's own when it does not.
96
+ *
97
+ * The reopen therefore belongs here, lazily: a swap-closed log reopens on its next write, so a fault that
98
+ * has cleared simply resolves itself, a fault that has not surfaces at the write (with its own error, the
99
+ * original having already propagated from the compaction), and `close()` keeps meaning exactly what
100
+ * RB-99 made it mean.
101
+ */
14
102
  private disposed;
15
103
  private readonly path;
104
+ /**
105
+ * RB-438 — the file size as of the end of THIS log's last successful append (or of the last time it
106
+ * observed the file at a record boundary). `-1` = unknown, re-establish on the next append.
107
+ *
108
+ * It is the cheap arbiter for "did the file change under us since we last left it whole": equal ⇒
109
+ * nothing to check, different ⇒ read the last byte and repair if it is not a newline. See
110
+ * {@link repairTornTail}.
111
+ */
16
112
  private boundary;
17
113
  constructor(path: string);
18
114
  private sizeOrUnknown;
115
+ /**
116
+ * RB-438 (2026-07-31, hardening probe R2) — re-establish the last-complete-record boundary before a write.
117
+ *
118
+ * The constructor's {@link truncateTornTail} (and the RB-167 lazy reopen) only ever ran at OPEN time, and
119
+ * the RB-66 loop below only repairs a SHORT write — not a `writeSync` that THROWS mid-loop (ENOSPC/EDQUOT/
120
+ * EIO after a partial `write(2)`, the classic full-volume shape) and not the `n <= 0` guard. Both leave
121
+ * `written` bytes on disk with no terminating newline while the fd and this object stay live, and every
122
+ * caller retries through the SAME AppendLog (`FileSessionStorage.appendEntry` throws before `recordEntry`,
123
+ * so the in-memory leaf is unchanged and the CAS retry appends again). The retry's record was then GLUED
124
+ * onto the remnant, so replay dropped BOTH — after that second append had returned and fsync'd. Measured:
125
+ * records [1,2,3] + a torn remnant + appends 5,6 replayed as [1,2,3,6].
126
+ *
127
+ * Cost on the healthy path is ONE `fstat` per append (the sizes match and we return); the whole-file read
128
+ * only happens when the file actually moved off a boundary. A legitimate concurrent appender (another
129
+ * process under the boot-lock handoff) leaves the file newline-terminated, so it is adopted, not truncated.
130
+ */
19
131
  private repairTornTail;
132
+ /**
133
+ * Append one record (`json + "\n"`). `fsync:true` makes the record durable before return.
134
+ *
135
+ * RB-66 (2026-07-25, red probe): `writeSync(fd, string)` issues ONE write(2) and may SHORT-WRITE — the
136
+ * same defect class this file's own `writeThenLink` already documents and fixed ("silently SHORT-WRITES
137
+ * (codex/Opus review B1)"), never propagated to this shared primitive. A short write here leaves a torn
138
+ * line with no trailing newline, so the NEXT append concatenates onto it and replay drops BOTH records.
139
+ * Loop until every byte lands (write(2) returns how many it took) — the O_APPEND atomicity per call is
140
+ * unchanged, and a genuine I/O error still throws.
141
+ */
20
142
  append(record: unknown, fsync: boolean): void;
21
143
  close(): void;
144
+ /**
145
+ * RB-167 — release the descriptor for a compaction SWAP. The next write reopens it lazily.
146
+ *
147
+ * Callers must use this rather than `close()` around a rewrite: `close()` means "this log is finished",
148
+ * and a store that used it for a swap and then failed to rewrite left the log permanently unusable —
149
+ * one transient I/O error becoming a permanent brick, shared by every instance on that directory.
150
+ */
22
151
  closeForSwap(): void;
23
152
  private releaseFd;
24
153
  }
154
+ /**
155
+ * The SINGLE coarse boot guard (§2.4): an `O_EXCL` PID file at `root/LOCK` that forbids two processes
156
+ * sharing a data dir. A second instance fails fast ("another instance owns this data dir"). A STALE lock
157
+ * (the writing PID is dead) is pruned and re-acquired — `proper-lockfile`/CC `concurrentSessions` parity.
158
+ *
159
+ * This is the ONLY legitimate file lock in the backend: the once-only CAS is in-process (one event loop +
160
+ * a per-token async mutex), so there is NO per-operation flock — this fence just guarantees the
161
+ * in-process model's premise (a single writer to the dir) holds. Cross-process CORRECT concurrency is the
162
+ * Pg/TiDB backend's job, by design.
163
+ */
25
164
  export declare class BootLock {
26
165
  private readonly lockPath;
27
166
  private held;
28
167
  constructor(lockPath: string);
168
+ /** Acquire the lock or throw. Prunes a stale lock whose recorded PID is not running. */
29
169
  acquire(): void;
30
170
  private writeLock;
31
171
  private readLockPid;
172
+ /** Release the lock (only if we hold it). Best-effort; never throws. */
32
173
  release(): void;
33
174
  }
175
+ /**
176
+ * design/84 Seam B (TOC profile) — a per-scope CONSOLIDATION lock factory for the file backend's
177
+ * {@link import("../../core/consolidate-scope.js").ConsolidateScopeDeps.acquire} injection point. A single
178
+ * machine may run a periodic-consolidation timer AND a task-end inline pass concurrently; this advisory lock
179
+ * stops two processes consolidating the SAME scope at once (the in-process model the file backend assumes —
180
+ * see {@link BootLock} — does not cover a second OS process with its own timer).
181
+ *
182
+ * `acquire(scope)` writes `lockDir/<sanitizedScope>.consolidate.lock` carrying THIS pid (atomic
183
+ * {@link writeThenLink}, so the lock appears with its pid already in it — no empty-window prune race). It
184
+ * returns a `release` callback on success, or `undefined` when a LIVE owner already holds it (the caller
185
+ * treats `undefined` as "busy → skip this pass", a no-op). A STALE lock (recorded pid is dead) is pruned and
186
+ * re-acquired once. The implementation lives HERE (the deployment shell's persist/exec axis), NOT core — core
187
+ * only DEFINES the injection point (the constitutional split: gate-presence in core, mechanism in the profile).
188
+ */
34
189
  export declare function createFileConsolidationLock(lockDir: string): (scope: string) => (() => void) | undefined;
@@ -18,38 +18,127 @@ export { FileWorkflowJournalStore, MAX_JOURNAL_RESULT_BYTES, oversizeJournalResu
18
18
  export { FileUsageWindowStore } from "./usage-window-store.js";
19
19
  export { resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsolidationLock } from "./fs-atomic.js";
20
20
  export { atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog } from "./fs-atomic.js";
21
+ /**
22
+ * design/80 — the file-backed `StorageBackend` for the local (TOC) single-user binary: the 3rd store impl
23
+ * alongside `InMemory*` and `Pg*`, selected purely by what the embedder injects into `RunnerDeps` (no engine
24
+ * change). Construct one over a single data root and pass its four members straight into `RunnerDeps`:
25
+ *
26
+ * ```ts
27
+ * const backend = new FileStorageBackend(); // ~/.ai-agent (or $AGENT_DATA_DIR)
28
+ * const runner = new Runner({
29
+ * brain,
30
+ * sessionStore: backend.sessionStore,
31
+ * checkpointStore: backend.checkpointStore,
32
+ * memoryStore: backend.memoryStore,
33
+ * toolResultStore: backend.toolResultStore,
34
+ * });
35
+ * // …on shutdown:
36
+ * await backend.dispose();
37
+ * ```
38
+ *
39
+ * **Single-instance-per-data-dir (§2.4 / §7 decision 4):** the constructor takes a coarse boot `flock` on
40
+ * `root/LOCK`. A second `FileStorageBackend` over the same dir FAILS FAST ("another instance owns this data
41
+ * dir"); a stale lock from a dead PID is pruned. This is the ONLY file lock here — the once-only checkpoint
42
+ * CAS is in-process (one event loop), so there is no per-operation lock. Cross-process correct concurrency
43
+ * is the Pg/TiDB backend's job, by design.
44
+ */
21
45
  export interface FileStorageBackendOptions {
46
+ /** Data root. Default `$AGENT_DATA_DIR ?? ~/.ai-agent`, NFC-normalized + realpath-canonicalized. */
22
47
  root?: string;
48
+ /** Profile-injected promotable-write gate (design/77 §2). Threaded into `guardedMemoryStore`. */
23
49
  utilityGate?: UtilityGate;
50
+ /** `TtlSessionStore` idle-eviction policy. Default `"forget"` (§7 decision 5 — durable history is never
51
+ * deleted by an idle timer). */
24
52
  evict?: EvictPolicy;
53
+ /** Checkpoint store tuning (fsync cadence for `put`, ledger compaction threshold). */
25
54
  checkpoint?: FileCheckpointStoreOptions;
55
+ /** design/101 §E19 — file-snapshot enumerator bounds (maxFiles/maxBytes/ignoreDirs). Default
56
+ * {@link DEFAULT_SNAPSHOT_BOUNDS}. */
26
57
  snapshotBounds?: Partial<import("../../core/file-snapshot-store.js").FileSnapshotBounds>;
58
+ /** design/81 Slice 5 — an optional {@link import("../../core/memory.js").Embedder}. Injected ⇒ the memory
59
+ * store does portable (in-process) vector recall over a rebuildable sidecar index (`vectorMode:"portable"`);
60
+ * absent ⇒ the lexical floor, byte-identical to before. Config-driven (the deployment injects it); OFF by
61
+ * default. 🔴 the consolidation band `{0.05,0.3}` is tuned for the lexical distance — a real embedding model
62
+ * needs it re-tuned + a no-mis-merge live check BEFORE production-enable (design/81 Slice 5 release gate). */
27
63
  embedder?: import("../../core/memory.js").Embedder;
64
+ /**
65
+ * Disclosure sink for a durable read this backend's stores treat as ABSENT because the bytes were
66
+ * corrupt or unreadable (never fires on plain ENOENT — real absence).
67
+ *
68
+ * Why it lives on the BACKEND options and not only on the individual store: the fail-open it discloses
69
+ * exists for the DEFAULT deployment (a corrupt policy file yields an apparently normal, UNCONSTRAINED
70
+ * task), and the default deployment constructs its stores through this one-argument constructor — the
71
+ * per-store constructor parameter was unreachable from here, so the disclosure was wired exactly
72
+ * nowhere for the deployments that need it most.
73
+ *
74
+ * Reach TODAY: {@link FileStorageBackend.sessionPolicyStore} (rules read as ABSENT ⇒ an unconstrained
75
+ * task), {@link FileStorageBackend.sessionStore}'s repo (a session listing that silently omits what it
76
+ * could not read) and {@link FileStorageBackend.fileSnapshotStore} (a snapshot/scope read as missing,
77
+ * and a blob GC that aborted). The roster and CC-mailbox stores also carry the seat, but a deployment
78
+ * builds those itself and passes the sink directly. A store that grows the seat later is wired here in
79
+ * the same constructor.
80
+ *
81
+ * The payload is the UNION shape ({@link FileStorageCorruptReadInfo}): `path` + `reason` always,
82
+ * with the session-policy face's `sessionId`/`principal` present only when the reading store keys by
83
+ * them. One sink for one failure grammar — a host does not register three.
84
+ */
28
85
  onCorruptRead?: (info: FileStorageCorruptReadInfo) => void;
29
86
  }
87
+ /**
88
+ * The payload of {@link FileStorageBackendOptions.onCorruptRead} — the widest shape any store this
89
+ * backend constructs can deliver, so ONE sink reaches all of them (a per-store payload type would make
90
+ * the backend's forwarding contravariance-illegal, which is what kept the seat single-store).
91
+ * `SessionPolicyCorruptReadInfo` is assignable to it; the two-field store seats are satisfied by it.
92
+ */
30
93
  export interface FileStorageCorruptReadInfo {
94
+ /** Absolute path of the offending file/directory. */
31
95
  path: string;
96
+ /** What was observed and what the read degraded to. */
32
97
  reason: string;
98
+ /** Present only when the reading store keys by session (the session-policy face). */
33
99
  sessionId?: string;
100
+ /** Present only when the read was keyed by a principal. */
34
101
  principal?: string;
35
102
  }
36
103
  export declare class FileStorageBackend {
104
+ /** The resolved, canonical data root all four stores live under. */
37
105
  readonly root: string;
38
106
  readonly sessionStore: SessionStore;
39
107
  readonly checkpointStore: CheckpointStore;
108
+ /** Wrapped in `guardedMemoryStore` (Gate-2 chokepoint). design/81: implements the id-addressable trio on
109
+ * a lexical cosine-distance → `supportsConsolidation` is true → end-of-task consolidation lights up. */
40
110
  readonly memoryStore: MemoryStore;
41
111
  readonly toolResultStore: ToolResultStore;
112
+ /** design/99 §E6 — file-backed per-session permission rules (E6). Wire into `RunnerDeps.sessionPolicyStore`
113
+ * for a local deployment that needs session rules to survive a restart. */
42
114
  readonly sessionPolicyStore: SessionPolicyStore;
115
+ /** design/101 §E19 — file-backed working-tree snapshots (rewind-files). Wire into
116
+ * `RunnerDeps.fileSnapshotStore`. Content-addressed blobs persist across restarts (local-only; a remote env
117
+ * defers rewind to its own VM-snapshot backend). */
43
118
  readonly fileSnapshotStore: FileSnapshotStore;
119
+ /** SVC-2 / [381]⑥ (onboarded per [375]) — file-backed durable workflow resume journal. Wire into
120
+ * `RunnerDeps.workflowJournalStore` so `resumeFromRunId` survives a process restart on a TOC box. */
44
121
  readonly workflowJournalStore: WorkflowJournalStore;
122
+ /** design/164 件五 — file-backed cross-task usage-governance ledger. Wire into
123
+ * `RunnerDeps.usageWindowStore` so a deployment's `usageWindows` survive a restart (an in-memory
124
+ * ledger silently re-grants every allowance on every boot). */
45
125
  readonly usageWindowStore: UsageWindowStore;
126
+ /**
127
+ * design/84 Seam B (TOC) — the per-scope consolidation lock for `consolidateScope`'s `acquire` injection
128
+ * point: `consolidateScope(scope, { store: backend.memoryStore, llm, acquire: backend.consolidationLock })`.
129
+ * Stops two OS processes sharing this data dir from consolidating the SAME scope at once (a busy scope ⇒
130
+ * `undefined` ⇒ the pass is a no-op). The locks live under `root/consolidation-locks/`.
131
+ */
46
132
  readonly consolidationLock: (scope: string) => (() => void) | undefined;
47
133
  private readonly lock;
48
134
  private readonly fileCheckpoints;
49
135
  private readonly fileMemory;
50
136
  private readonly ttl;
137
+ /** RB-437 — kept so {@link dispose} can release the shared per-session authorities (and their append
138
+ * descriptors) this backend joined; `TtlSessionStore.dispose()` only clears the sweep timer. */
51
139
  private readonly fileSessions;
52
140
  private readonly fileWorkflowJournal;
53
141
  constructor(opts?: FileStorageBackendOptions);
142
+ /** Release file handles + the boot lock (best-effort). Call on shutdown so a successor can acquire. */
54
143
  dispose(): Promise<void>;
55
144
  }
@@ -1,7 +1,13 @@
1
1
  import { type MailboxAppendMessage, type MailboxLease, type MailboxStore } from "../../core/mailbox-store.js";
2
2
  export interface FileMailboxStoreOptions {
3
+ /** When false, ledger appends are NOT fsync'd. Default true. */
3
4
  fsync?: boolean;
5
+ /** Compact a box's event log into a snapshot-form log once it exceeds this many events. Default 500. */
4
6
  compactEvery?: number;
7
+ /** Disclosure seat (review-510 family; server pickup receipt named this store's gap): a corrupt
8
+ * INTERIOR record dropped by the JSONL replay is disclosed here instead of silently reading as
9
+ * "less mail". The torn tail stays silent by design — that is the append-log's documented
10
+ * crash-recovery shape, not corruption. Swallow-guarded; absent = the old silent tolerance. */
5
11
  onCorruptRead?: (info: {
6
12
  path: string;
7
13
  reason: string;
@@ -12,10 +18,39 @@ export declare class FileMailboxStore implements MailboxStore {
12
18
  private readonly tmpDir;
13
19
  private readonly fsyncEnabled;
14
20
  private readonly compactEvery;
21
+ /** Paths THIS instance has touched → the EXACT BoxState it took a ref on (server[1523] 对等复审
22
+ * 发现1: after a drop/reap deletes the shared box, another instance's stale close() must not
23
+ * decrement a REBUILT box's refs — identity is checked, not just the path). */
15
24
  private readonly touched;
25
+ /** The swallow-guarded corrupt-read seat (undefined = the old silent tolerance). */
16
26
  private readonly discloseCorrupt;
17
27
  constructor(root: string, opts?: FileMailboxStoreOptions);
28
+ /**
29
+ * RB-67 (2026-07-25, red probe): the on-disk name is CASE-FOLDED, so the in-memory key and the physical
30
+ * file can never disagree. Before this, `AgentOne` and `agentone` produced two DIFFERENT shared-state
31
+ * keys but the SAME file on a case-insensitive filesystem (macOS/Windows default) — one recipient read
32
+ * the other's messages after a restart. Folding is also the semantically correct answer, not just the
33
+ * safe one: the addressing layer's `normalizeAgentName` (task-registry.ts:621) already lowercases, so
34
+ * two case-variant handles ARE the same agent; this makes the storage layer say so explicitly instead of
35
+ * depending on an upstream coincidence, and behave identically on case-SENSITIVE filesystems (Linux),
36
+ * where the old code silently split one logical agent's mail across two boxes.
37
+ */
18
38
  private boxPath;
39
+ /**
40
+ * The canonical mutex / shared-state key — instance-independent (X-5).
41
+ *
42
+ * RB-162 (2026-07-26): this went through `realpath` (RB-62) but NOT the case fold (RB-67/RB-119), even
43
+ * though the module header above claims "the shared-state KEY goes through `canonicalStoreKey`, which
44
+ * also folds case". It did not — that name appeared exactly once in this file, inside that sentence.
45
+ * The handle component was folded by `boxPath`, but the ROOT was not: two spellings of the same
46
+ * directory on a case-insensitive filesystem produced two shared-state slots over one physical file, and
47
+ * each allocated its own `seq` — the very contract violation the realpath comment above describes,
48
+ * reached by the other half of the same canonicalization.
49
+ *
50
+ * Worse for the record: the enumerative guard written for this exact family tested
51
+ * `src.includes("canonicalStoreKey")`, which that one comment satisfied. The guard was green because the
52
+ * file talked about the rule.
53
+ */
19
54
  private lockKey;
20
55
  private load;
21
56
  private commit;
@@ -29,5 +64,6 @@ export declare class FileMailboxStore implements MailboxStore {
29
64
  reap(scope: string, now: number, opts?: {
30
65
  maxAgeMs?: number;
31
66
  }): Promise<number>;
67
+ /** Release THIS instance's share of the box handles (fd closes when the last instance leaves). */
32
68
  close(): void;
33
69
  }