@sema-agent/core 5.20.0 → 5.21.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 (312) hide show
  1. package/CHANGELOG.md +9 -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-shared.d.ts +360 -0
  292. package/dist/tools/fs/fs-write.d.ts +16 -0
  293. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  294. package/dist/tools/fs/index.d.ts +79 -0
  295. package/dist/tools/fs/notebook.d.ts +56 -0
  296. package/dist/tools/fs/pdf.d.ts +70 -0
  297. package/dist/tools/fs/pdf.js +8 -2
  298. package/dist/tools/fs/repo-map.d.ts +10 -0
  299. package/dist/tools/fs/safety.d.ts +376 -0
  300. package/dist/tools/fs/search.d.ts +131 -0
  301. package/dist/tools/loop-tick.d.ts +24 -0
  302. package/dist/tools/monitor.d.ts +55 -0
  303. package/dist/tools/scheduler-tools.d.ts +51 -0
  304. package/dist/tools/sql-adapters.d.ts +18 -0
  305. package/dist/tools/sql.d.ts +25 -0
  306. package/dist/tools/task-list.d.ts +77 -0
  307. package/dist/tools/todo.d.ts +8 -0
  308. package/dist/tools/web.d.ts +184 -0
  309. package/dist/tools/worktree.d.ts +81 -0
  310. package/package.json +2 -2
  311. package/dist/tools/gitea-issue.d.ts +0 -13
  312. package/dist/tools/gitea-issue.js +0 -75
@@ -1,11 +1,41 @@
1
+ /** Closed compliance profile set (CC 2.1.221 policy-limits profiles). */
1
2
  export type ComplianceProfile = "hipaa" | "zdr";
3
+ /** Closed capability set the ENGINE can veto end-to-end (see the module header for the entry-point
4
+ * map — a capability is admitted here only with its full interception story). */
2
5
  export type ComplianceCapability = "mcp_servers" | "workflows" | "web_fetch" | "org_memory_mount";
6
+ /** Every member of {@link ComplianceCapability} — the fail-closed "deny everything managed" set used
7
+ * when the posture resolver itself fails. `satisfies` keeps it in lockstep with the union. */
3
8
  export declare const COMPLIANCE_CAPABILITIES: readonly ["mcp_servers", "workflows", "web_fetch", "org_memory_mount"];
9
+ /**
10
+ * A principal's resolved compliance posture, supplied by the trusted deployment resolver. The
11
+ * effective deny set is `BUILTIN_COMPLIANCE_DENIES[profile] ∪ additionalDenies` — supply can only
12
+ * TIGHTEN a profile's builtin floor, never carve a builtin deny back out.
13
+ */
4
14
  export interface CompliancePosture {
5
15
  profile: ComplianceProfile;
16
+ /** Extra denies on top of the profile's builtin floor (closed set; unknown values are refused). */
6
17
  additionalDenies?: readonly ComplianceCapability[];
7
18
  }
19
+ /**
20
+ * Builtin per-profile deny floors, mapped from the CC 2.1.221 policy-limits pair table onto the
21
+ * capabilities this engine manages: hipaa denies `allow_web_fetch` ⇒ `web_fetch`. (CC's
22
+ * `allow_memory_sync` row maps onto the org-memory plane and joins this table together with the
23
+ * memory-admission seam; CC has no MCP/workflow rows — those stay reachable via `additionalDenies`.)
24
+ */
8
25
  export declare const BUILTIN_COMPLIANCE_DENIES: Record<ComplianceProfile, readonly ComplianceCapability[]>;
26
+ /**
27
+ * Resolve a posture into its effective deny set. Fail-loud on any value outside the closed sets
28
+ * (`config.compliance_posture`): a posture that does not parse must be treated by the caller as a
29
+ * resolver FAULT (deny every managed capability), never as a partially-applied profile.
30
+ */
9
31
  export declare function resolveComplianceDenies(posture: CompliancePosture): ReadonlySet<ComplianceCapability>;
32
+ /** The core web-fetch tool face's canonical mounted name (`createWebFetchTool` in tools/web.ts). */
10
33
  export declare const WEB_FETCH_TOOL_NAME = "WebFetch";
34
+ /**
35
+ * The CALL-TIME half of the `web_fetch` double point (CC form — mount check + call guard): given the
36
+ * run's frozen deny set and a tool-call name, return the refusal text when the call must be blocked,
37
+ * else `undefined`. Kept as a pure exported decision so the gate wiring and the tests hold ONE
38
+ * predicate; today every roster lane that can mint a `WebFetch`-named tool is already refused at
39
+ * prepare, so this is the standing second lock for any future dynamic roster lane.
40
+ */
11
41
  export declare function complianceCallDenial(denies: ReadonlySet<ComplianceCapability>, toolName: string): string | undefined;
@@ -1,18 +1,93 @@
1
1
  import type { MemoryStore } from "./memory.js";
2
2
  import { type ConsolidationLLM, type ConsolidationStats } from "./runner/memory-consolidation.js";
3
+ /**
4
+ * design/84 Seam B (M6+M10) — **cursor-incremental scope consolidation**. A thin function over the pure
5
+ * {@link runMemoryConsolidation}: it reads the scope's persisted cursor, feeds ONLY the notes appended
6
+ * AFTER it (the incremental batch) into one reconcile pass, then — IFF the whole pass succeeds — advances
7
+ * the cursor to the high-water mark it observed. This is the externally-triggerable periodic path (a
8
+ * deployment's timer / N-session gate fires it); the TRIGGER and any cross-process LOCK live OUTSIDE this
9
+ * function (the deployment shell's exec/persist axes — see {@link ConsolidateScopeOptions.acquire}).
10
+ *
11
+ * **Cursor marker semantics (no-miss / no-dup):** the cursor is an OPAQUE ordering marker the STORE defines
12
+ * (this core never parses it). In the three reference stores it is a note **id** — `uuidv7`, which is
13
+ * lexicographically time-sortable, so "after the cursor" is a string `>` comparison and the high-water mark
14
+ * is the lexicographic MAX. Each pass:
15
+ * - reads `cursor = getConsolidationCursor(scope)` (undefined ⇒ whole scope pending),
16
+ * - lists the scope's note headers (stable store ordering) and keeps those with `id > cursor` AND not
17
+ * already `consolidationGenerated` (a prior pass's own output — excluded so it is never re-merged),
18
+ * - reconciles that incremental batch via `runMemoryConsolidation` (which itself re-excludes
19
+ * `consolidationGenerated` + this-batch ids from each note's candidate set),
20
+ * - advances the cursor to the high-water mark of the fed batch ∪ `stats.addedIds`, but capped STRICTLY
21
+ * BELOW the smallest note this pass FAILED to process (`stats.failedIds`) — a contiguous successful-prefix
22
+ * marker, not the plain max (the MAJOR1 BLOCKER: a single max marker cannot keep a sub-max failed note
23
+ * pending; see {@link cappedHighWater}).
24
+ * No-dup: a note with `id <= cursor` is never re-fed. No-miss: a note appended after the advance, or one at/
25
+ * above a failure floor this pass, keeps `id > cursor` (uuidv7 monotonic) and is picked up by a later pass. A
26
+ * pass's own ADDs carry `consolidationGenerated:true` AND (when below the failure floor) are folded into the
27
+ * high-water mark, so they are excluded twice over.
28
+ *
29
+ * **Whole-pass advance (decision 3):** the cursor advances (up to the success boundary) ONLY when the pass
30
+ * returns (no throw). A pass that THROWS (LLM hard failure) does NOT advance at all — the batch is fully
31
+ * retried next time. A pass that returns with per-note failures advances only past the contiguous successful
32
+ * prefix below the smallest failure (fail-open: at worst a near-duplicate survives an extra pass, never data
33
+ * loss; consistent with the memory-store contract).
34
+ *
35
+ * **No-op safety (the BLOCKER §2 closes):** when the store lacks the cursor pair
36
+ * ({@link supportsPeriodicConsolidation} false) this is a NO-OP that calls `onWarn` — it NEVER degrades into a
37
+ * full re-consolidation of the whole scope (which would re-merge already-consolidated notes forever). It is
38
+ * also a no-op when the store can't consolidate at all ({@link supportsConsolidation} false) or the manifest
39
+ * read pair ({@link MemoryStore.listStructuredNotes} / {@link MemoryStore.getByIds}) is incomplete.
40
+ */
3
41
  export interface ConsolidateScopeDeps {
4
42
  store: MemoryStore;
5
43
  llm: ConsolidationLLM;
44
+ /** Routes diagnostics (skipped decisions, no-op-because-unsupported, lock-busy) — same sink as the Runner's
45
+ * `onError(phase:"memory")`. Never throws back into this function. */
6
46
  onWarn?: (err: unknown) => void;
47
+ /**
48
+ * design/84 Seam B (TOC profile) — OPTIONAL cross-process consolidation lock. When provided,
49
+ * {@link consolidateScope} acquires it for `scope` before the pass and releases it after; a `release` of
50
+ * `undefined` (lock busy) makes the pass a NO-OP (another process is already consolidating this scope).
51
+ * The implementation (writeThenLink + stale-PID prune) lives in the deployment shell (`stores/file`), NOT
52
+ * core — core only DEFINES the injection point (the constitutional persist/exec-axis split).
53
+ */
7
54
  acquire?: (scope: string) => Promise<(() => void) | undefined> | (() => void) | undefined;
8
55
  }
56
+ /** Tuning for one {@link consolidateScope} pass (mirrors the inline consolidation settings; all optional). */
9
57
  export interface ConsolidateScopeOptions {
10
58
  band?: {
11
59
  lo: number;
12
60
  hi: number;
13
61
  };
14
62
  searchLimit?: number;
63
+ /** Cap on notes fed into ONE pass (token bound). The cursor advances only past the contiguous SUCCESSFUL
64
+ * prefix of the FED batch (the first `maxNotes` pending) — never past the un-fed tail beyond the cap, and
65
+ * never past a note this pass FAILED to process — so a backlog larger than `maxNotes`, and any failed note,
66
+ * keep `id > cursor` and drain over successive passes without ever re-feeding the notes already handled. */
15
67
  maxNotes?: number;
16
68
  }
69
+ /**
70
+ * Run ONE cursor-incremental consolidation pass for `scope` (design/84 Seam B). Returns the pass stats
71
+ * (or `undefined` when it was a no-op: unsupported store, empty incremental batch, or lock busy). Never
72
+ * throws for a no-op reason; a hard LLM failure inside `runMemoryConsolidation` propagates (the caller's
73
+ * fire-and-forget envelope catches it) and the cursor is left UN-advanced (the batch retries next pass).
74
+ */
17
75
  export declare function consolidateScope(scope: string, deps: ConsolidateScopeDeps, opts?: ConsolidateScopeOptions): Promise<ConsolidationStats | undefined>;
76
+ /**
77
+ * design/84 Seam B (切片 4) — advance ONLY the cursor after an INLINE (task-end) consolidation pass has
78
+ * already run, so a later periodic {@link consolidateScope} starts from the inline-processed high-water mark
79
+ * (it does NOT re-consolidate the notes the inline pass just handled). The inline path consolidates the
80
+ * notes the model saved THIS task (the newest, highest-id notes); advancing the cursor over the PROCESSED
81
+ * ids ∪ addedIds makes inline and periodic share ONE cursor.
82
+ *
83
+ * **MAJOR1 BLOCKER:** the advance caps STRICTLY BELOW the smallest FAILED note (`failedIds`). A single
84
+ * max-marker cursor cannot keep a sub-max failed note pending, so a low-id note whose handling failed must
85
+ * stop the cursor below it even when a higher-id sibling succeeded — otherwise the failed note (id <= the
86
+ * plain max) would lose `id > cursor` and be exiled from consolidation forever. Pass the pass's
87
+ * `stats.consolidatedIds` (processed), `stats.addedIds`, and `stats.failedIds`.
88
+ *
89
+ * No-op when the store lacks the cursor pair (back-compat: an old store keeps the pure-inline behavior).
90
+ * Never throws — a cursor-advance failure routes to `onWarn` (the inline notes are already durable; the
91
+ * worst case is the next periodic pass re-sees them, which `runMemoryConsolidation` handles idempotently).
92
+ */
18
93
  export declare function advanceCursorAfterInline(store: MemoryStore, scope: string, seenNoteIds: ReadonlyArray<string | undefined>, addedIds: ReadonlyArray<string>, failedIds?: ReadonlyArray<string>, onWarn?: (err: unknown) => void): Promise<void>;
@@ -1,20 +1,119 @@
1
1
  import type { AgentMessage } from "../internal/harness.js";
2
2
  import type { Model } from "../internal/llm.js";
3
+ /**
4
+ * Small-window FLOOR fraction of the clearStale/compaction frontier (see {@link contextEditFrontier},
5
+ * which is the single source for both the clearStale budget and the compaction-threshold clamp).
6
+ * CC's fixed-deduction trigger geometry only exists for ≥100k autocompact windows (its configured-
7
+ * window floor is 100000), and `W − 33000` goes degenerate below ~47k — small windows keep the
8
+ * historical fractional trigger instead.
9
+ */
3
10
  export declare const EDIT_FRACTION = 0.7;
11
+ /**
12
+ * CC-parity trigger geometry (verified against CC 2.1.207): the reactive autocompact trigger sits a
13
+ * FIXED DISTANCE below the window, not at a fixed fraction —
14
+ * effectiveWindow = autocompactWindow − min(maxOutputTokens, 20000) (CC `Nye`, cap `uMd`)
15
+ * trigger = effectiveWindow − 13000 (CC `dSo`, buffer `rMd`)
16
+ * i.e. trigger = W − 33000 for every model whose max output is ≥ 20k: a 200k window triggers at
17
+ * 167000 (83.5% of nominal), a 1M window at 967000. (CC additionally ships a sonnet-5-only 1M
18
+ * autocompact-window special of 967000 via dynamic config, making ITS 1M trigger 934000; that is a
19
+ * per-model config delivery, not geometry — an embedder reproduces it EXACTLY via
20
+ * `model.autoCompactTokens = 967000`, which lowers only this trigger-side window while the guard
21
+ * and physical request budgeting stay on the 1M window — CC's dual-window shape.) We take the
22
+ * 20000 cap branch unconditionally (flat 33000), i.e. the `min(maxOutputTokens, 20000)` branch is
23
+ * deliberately NOT ported: the deduction is exact parity only for models with max output ≥ 20k. A
24
+ * model with a smaller max output would deduct less in CC (trigger LATER); we deduct the full
25
+ * 20000 and so trigger EARLIER there — the conservative direction (early compaction is bounded
26
+ * cost; a late trigger risks the window). It also keeps the frontier a pure function of the
27
+ * window — single source for the death-band clamp below.
28
+ */
4
29
  export declare const CONTEXT_OUTPUT_RESERVE_TOKENS = 20000;
5
30
  export declare const COMPACTION_TRIGGER_BUFFER_TOKENS = 13000;
31
+ /**
32
+ * The clearStale/compaction frontier for a window — SINGLE SOURCE for two coupled points
33
+ * (design/64 §26.4 fix 2): the budget at which the request-layer stale-result clearing engages
34
+ * ({@link editBudget}) AND the ceiling the compaction threshold is clamped to
35
+ * (`sanitizeCompactionSettings`). Deriving both from one function keeps `compaction ≡ clearStale`
36
+ * an invariant: a threshold above the clearing frontier would put every request between the two
37
+ * points on a moving clearing frontier that breaks the prefix cache (~frontier re-prefilled PER
38
+ * REQUEST — the "death band"). `max()` keeps the frontier monotonic in the window; exact
39
+ * crossover (integer domain, pinned by test): the fractional floor strictly wins through
40
+ * W = 109996, the two legs are EQUAL for W = 109997…110000 (floor(0.7W) meets W − 33000 there),
41
+ * and the fixed deduction strictly wins from W = 110001 up.
42
+ */
6
43
  export declare function contextEditFrontier(window: number): number;
44
+ /**
45
+ * checklist #54 (CC microCompact.ts:41-50 `COMPACTABLE_TOOLS` parity): the INCLUSION whitelist of
46
+ * tools whose results may be content-cleared by the stale-result pass. CC's set is exactly
47
+ * { Read, Bash, PowerShell (SHELL_TOOL_NAMES), Grep, Glob, WebSearch, WebFetch, Edit, Write } —
48
+ * cheap-to-regenerate I/O. Everything else is PRESERVED: expensive/decision-bearing results
49
+ * (Agent subagent reports, Task* registry state, TodoWrite acks, Monitor, MCP tools, custom
50
+ * ToolSpecs) survive to the harder defenses (compaction summarizes them instead of blanking them).
51
+ * PowerShell is kept for CC fidelity even though sema does not mount it. Overridable per call via
52
+ * {@link ContextEditOptions.compactableTools} for custom-tool-heavy embedders.
53
+ */
7
54
  export declare const COMPACTABLE_TOOLS: ReadonlySet<string>;
8
55
  export interface ContextEditOptions {
56
+ /** Start clearing once estimated context tokens exceed this. */
9
57
  budgetTokens: number;
58
+ /** Always keep the content of this many most-recent tool results. Default 3. */
10
59
  keepRecentToolResults?: number;
60
+ /**
61
+ * roadmap #6② (CC contentReplacementState parity): when set, a result's FULL TEXT is offloaded to
62
+ * the store before its content is cleared, and the marker carries the ReadToolResult ref — a
63
+ * cleared result becomes pageable instead of gone-from-view. `persist` must be idempotent per ref
64
+ * (the store's write-once put) because clearing re-runs on every request build. Absent ⇒ the bare
65
+ * marker (pre-#6 behavior; the durable session still holds the full result either way).
66
+ */
11
67
  offload?: {
68
+ /** Write-once persist; the returned ref goes into the marker. Sync (in-memory) or async stores both fit. */
12
69
  persist: (toolCallId: string, fullText: string) => string;
13
70
  };
71
+ /**
72
+ * design/123 D3 (codex-B1 = fable-M5) — ANCHORED accounting start: `estimateContextTokens(messages,
73
+ * charsPerToken).tokens` for the SAME message array. When set, the trigger gate AND the internal
74
+ * bookkeeping start from this usage-anchored value instead of the pure structural sum (which
75
+ * underestimates code by ~25% and CJK by 60–75% — the defense would self-certify and pass
76
+ * over-window requests). Bookkeeping semantics (pinned): clearing a message AFTER the usage anchor
77
+ * decrements by its structural delta; clearing a message AT/BEFORE the anchor decrements ZERO —
78
+ * the anchor usage was billed with that content included and does not shrink on a request-view
79
+ * edit (the clear only pays off on the NEXT request, after a fresh anchor lands), so the defense
80
+ * keeps clearing deeper until the anchored total is met or nothing clearable remains.
81
+ * Absent ⇒ legacy structural gate + accounting (byte-identical behavior).
82
+ */
14
83
  anchoredTotalTokens?: number;
84
+ /** design/123 D2 — structural coefficient (`Model.charsPerToken`); default 4. */
15
85
  charsPerToken?: number;
86
+ /**
87
+ * checklist #54 — which tools' results are clearable. Defaults to {@link COMPACTABLE_TOOLS}
88
+ * (CC microCompact.ts:41-50). A result whose `toolName` is not in the set is NEVER cleared by
89
+ * this pass, no matter how far over budget the request is — expensive subagent reports and
90
+ * registry state are compaction's job, not a blanking marker's.
91
+ */
16
92
  compactableTools?: ReadonlySet<string>;
17
93
  }
94
+ /**
95
+ * Context-editing (the lightest, safest compaction; Anthropic reports ~29% improvement alone):
96
+ * when context exceeds the budget, replace the CONTENT of older tool-result messages with a short
97
+ * marker, keeping the turn structure (tool_call/tool_result pairing) intact. The most recent
98
+ * `keepRecentToolResults` results are preserved.
99
+ *
100
+ * Request-only and non-destructive: returns a new array; the durable session keeps the full results.
101
+ * Older results are cleared first, stopping as soon as the budget is met.
102
+ */
103
+ /**
104
+ * audit A-1 (view-level heal for HISTORICAL pollution): drop synthetic EMPTY failure assistants —
105
+ * stopReason aborted/error with no tool calls and no non-whitespace text/thinking. Sessions persisted
106
+ * before 1.92.0 may carry one parked between an interrupted tool batch and its reconcile tool_results
107
+ * (`A(tu×3), TR1, TR2, A(aborted,""), TR3`) — an API-invalid sequence on strict providers, and
108
+ * append-only sessions cannot be rewritten. Dropping the junk from the REQUEST VIEW restores a legal
109
+ * transcript (TR3 rejoins its batch). Deterministic ⇒ byte-stable per request ⇒ prefix-cache safe.
110
+ * New sessions never contain these (the loop exits cleanly on abort; the harness skips persisting them).
111
+ */
18
112
  export declare function dropEmptyFailureAssistants(messages: AgentMessage[]): AgentMessage[];
19
113
  export declare function clearStaleToolResults(messages: AgentMessage[], opts: ContextEditOptions): AgentMessage[];
114
+ /** The token budget at which context-editing begins for a model (below the harder guard trim).
115
+ * = {@link contextEditFrontier} of the model's AUTOCOMPACT window (CC-parity fixed deduction with
116
+ * a 0.7 small-window floor) — the same point the compaction threshold is clamped to. Dual-window
117
+ * semantics: `autoCompactTokens` (when declared) feeds this trigger-side geometry only; the guard
118
+ * trim (`guardBudget`) stays on the physical window. */
20
119
  export declare function editBudget(model: Model): number;
@@ -1,8 +1,49 @@
1
1
  import type { AgentMessage } from "../internal/harness.js";
2
2
  import type { Model } from "../internal/llm.js";
3
+ /**
4
+ * Last-resort, in-task context trim. Proper compaction (LLM summary) runs *between* tasks;
5
+ * this prevents a single task whose internal tool-loop balloons from overflowing the window.
6
+ *
7
+ * Keeps all summary messages (compaction/branch) and the most recent messages that fit the
8
+ * budget, dropping older regular messages at a safe boundary (never starting on an orphan
9
+ * toolResult). Returns the original array when already within budget.
10
+ *
11
+ * design/123 D3 (codex-B1 = fable-M5) — anchored accounting: when `anchoredTotalTokens`
12
+ * (= `estimateContextTokens(messages, charsPerToken).tokens` for the SAME array) is provided, the
13
+ * trigger gate and the internal bookkeeping start from the usage-anchored value instead of the
14
+ * structural sum (which underestimates code/CJK and lets over-window requests through). Dropping a
15
+ * message AFTER the usage anchor reduces the accounted total by its structural estimate; dropping a
16
+ * message AT/BEFORE the anchor reduces it by ZERO (the anchor usage was billed with that content —
17
+ * a request-view drop only pays off on the NEXT request), so the trim keeps cutting deeper until
18
+ * the anchored total meets the budget or only the minimal tail is left. Absent ⇒ legacy structural
19
+ * behavior, byte-identical. `charsPerToken` (design/123 D2): structural coefficient, default 4.
20
+ */
3
21
  export declare function trimToBudget(messages: AgentMessage[], budgetTokens: number, anchoredTotalTokens?: number, charsPerToken?: number): AgentMessage[];
22
+ /**
23
+ * In-band notice for a request view whose oldest messages were dropped by the guard trim. Every
24
+ * other history-reducing pass in the pipeline announces itself to the model (compaction injects a
25
+ * summary); a silent trim leaves the model unaware that earlier instructions or constraints are no
26
+ * longer visible. MUST remain a single static string: the notice is re-inserted on every trimmed
27
+ * request, and a byte-identical prefix keeps provider prefix caching effective.
28
+ */
4
29
  export declare const CONTEXT_TRIM_NOTICE: string;
30
+ /**
31
+ * Insert the static trim notice ahead of the kept tail of a trimmed request view (after any
32
+ * always-kept summary messages, which lead the rebuilt array). Call ONLY when the trim actually
33
+ * dropped messages. Request-view only — the synthetic message is never persisted to the session
34
+ * (fixed timestamp keeps it fully deterministic).
35
+ */
5
36
  export declare function insertTrimNotice(trimmed: AgentMessage[]): AgentMessage[];
37
+ /**
38
+ * design/123 D3 belt (invariant-level, live-caught 16k 400s): the FINAL request view must never
39
+ * contain a toolResult whose tool-call assistant is absent — strict gateways hard-400 on it
40
+ * ("Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"). Every
41
+ * individual producer is turn-aligned (findCutPoint never cuts on a toolResult; trimToBudget
42
+ * turn-aligns its floor), but NO pipeline combination may ship an orphan, so the prepare-task
43
+ * context hook sweeps its output through this last. Deterministic ⇒ byte-stable per request ⇒
44
+ * prefix-cache safe. Returns the SAME array when clean (zero-cost fast path); `dropped` carries a
45
+ * diagnostic per removed orphan (toolCallId + neighbor roles) for onError attribution.
46
+ */
6
47
  export declare function dropOrphanToolResults(messages: AgentMessage[]): {
7
48
  messages: AgentMessage[];
8
49
  dropped: Array<{
@@ -12,4 +53,9 @@ export declare function dropOrphanToolResults(messages: AgentMessage[]): {
12
53
  nextRole: string;
13
54
  }>;
14
55
  };
56
+ /** Budget the in-task guard targets for a model — CC-aligned headroom numbers with a 0.85
57
+ * small-window floor, sema-owned drop-oldest action (see {@link GUARD_HEADROOM_TOKENS}); always
58
+ * above the compaction/clearStale frontier. Dual-window semantics: deliberately the PHYSICAL
59
+ * window (`contextTokens ?? contextWindow`), NOT `autoCompactTokens` — the guard protects the
60
+ * real request limit; a lowered autocompact window only moves the trigger-side geometry. */
15
61
  export declare function guardBudget(model: Model): number;
@@ -1,29 +1,73 @@
1
+ /**
2
+ * L2 mechanical verification gate (design/54) — the "verifiable outputs" exit oracle.
3
+ *
4
+ * Runs a TRUSTED, spec-derived suite of commands (build / type-check / test) in an {@link ExecutionEnv}
5
+ * and gates on the **real exit codes**: pass = every step exited 0. This is the mechanical half of
6
+ * verifiable outputs (design/54 §2); the de-correlated LLM-judge half is {@link runWithVerification}
7
+ * (L3). It catches what tests cover; service[33] measured L2 alone misses 50-100% of semantic/edge
8
+ * defects, which is why L3 runs on what passes L2.
9
+ *
10
+ * **It is a thin exit oracle, not a framework** — no model, no Runner, no agents dependency. It just runs
11
+ * commands and reports their exit truthfully, choosing the streaming `execStream` on a remote env (long
12
+ * builds, read-timeout, output cap) or the buffered `exec` on a base env. Which commands to run, and how
13
+ * to compose L2 with L3 / per-module sub-gates, is the caller's (profile's) job (design/54 §4).
14
+ *
15
+ * 🔴 SECURITY (design/53 §2.B, threat BUG8 — "L2 can be gamed"): `steps` MUST be a trusted, spec-derived
16
+ * suite — NOT test files an **untrusted worker** authored (a worker can write `assert(true)` / happy-path
17
+ * tests that pass while the code is broken, pushing all pressure onto an uncalibrated L3). This helper does
18
+ * not and cannot know which commands are trustworthy; the caller owns that. The gate's guarantee is narrow:
19
+ * "did these exact commands all exit 0 in this env" — nothing about whether the commands are meaningful,
20
+ * whether the env is isolated (design/53 §E = deployment), or the semantics of the change (that is L3).
21
+ */
1
22
  import type { ExecutionEnv } from "../internal/harness-types.js";
23
+ /** One command in an L2 suite. */
2
24
  export interface ExecStep {
25
+ /** Shell command to run (e.g. `"npm test"`, `"tsc --noEmit"`, `"git diff"`). */
3
26
  command: string;
27
+ /** Human label for reporting. Default: the command string. */
4
28
  label?: string;
29
+ /** Working directory; relative paths resolve against the env root. Default: the env's cwd. */
5
30
  cwd?: string;
31
+ /** Extra environment variables for this command. */
6
32
  env?: Record<string, string>;
33
+ /** Per-step timeout (seconds). Default: none. */
7
34
  timeoutSec?: number;
8
35
  }
36
+ /** The outcome of a single {@link ExecStep}. */
9
37
  export interface ExecStepResult {
10
38
  label: string;
11
39
  command: string;
40
+ /** The real exit code, or `null` when the command never produced one (transport error / timeout / abort). */
12
41
  exitCode: number | null;
13
42
  stdout: string;
14
43
  stderr: string;
44
+ /** `exitCode === 0`. A `null` exit is **never** `ok` (we can't confirm success, so we don't pass it). */
15
45
  ok: boolean;
46
+ /** Set when the step failed to RUN (an `ExecutionError`/`RemoteExecutionError` code) — distinct from a non-zero exit. */
16
47
  errorCode?: string;
48
+ /** True when captured output was truncated at {@link ExecGateOptions.maxOutputBytes}. */
17
49
  truncated?: boolean;
18
50
  }
51
+ /** The L2 verdict over a whole suite. */
19
52
  export interface ExecGateResult {
53
+ /** True iff there was ≥1 step AND every step ran and exited 0. An EMPTY suite is `false` (nothing was verified — not a vacuous pass). */
20
54
  passed: boolean;
55
+ /** Per-step detail, in order. With `stopOnFailure` (default), steps after the first failure are absent. */
21
56
  steps: ExecStepResult[];
22
57
  }
58
+ /** Options for {@link runExecGate}. */
23
59
  export interface ExecGateOptions {
60
+ /** Stop at the first failed/non-zero step (default `true` — a cheap CI-style short-circuit). */
24
61
  stopOnFailure?: boolean;
62
+ /** Cap captured output **per step** in UTF-8 bytes (default 64 KiB) so a `find /` can't flood memory. */
25
63
  maxOutputBytes?: number;
64
+ /** Idle read timeout (ms) for the streaming (remote) path; ignored on the buffered path. */
26
65
  readTimeoutMs?: number;
66
+ /** Abort the whole gate (also forwarded to each command). */
27
67
  signal?: AbortSignal;
28
68
  }
69
+ /**
70
+ * Run an L2 mechanical gate: execute `steps` in `env` and gate on real exit codes. See the file header for
71
+ * the security contract — `steps` must be a trusted, spec-derived suite, not worker-authored tests.
72
+ */
29
73
  export declare function runExecGate(env: ExecutionEnv, steps: ExecStep[], options?: ExecGateOptions): Promise<ExecGateResult>;
@@ -1,5 +1,21 @@
1
+ /**
2
+ * Bounded rolling-TAIL accumulator for streaming exec output (sema D2) — FIRST-PARTY, vendor-independent.
3
+ *
4
+ * A model-driven `yes` / `cat big.bin` over a 120s/600s shell can emit gigabytes; accumulating it unbounded OOMs
5
+ * a durable worker. We keep only the LAST `maxBytes` — the tail (errors + the exit code are at the end, which is
6
+ * what the model needs) — dropping the head as it overflows, plus a count of dropped bytes for a visible marker.
7
+ *
8
+ * This lives in `src/core/` — NOT `src/vendor/` — on purpose: it is OUR robustness invariant, shared by the
9
+ * (currently-vendored) NodeExecutionEnv AND a downstream exec adapter (service host/ssh/adb/docker/k8s, [267]).
10
+ * One implementation + ONE model-facing marker text = zero drift, and the public export points at a STABLE path
11
+ * that survives the planned de-vendoring (when NodeExecutionEnv is naturalized out of `src/vendor/`, nothing rebinds).
12
+ */
1
13
  import { StringDecoder } from "node:string_decoder";
2
14
  export declare const MAX_EXEC_OUTPUT_BYTES: number;
15
+ /**
16
+ * Push-based bounded tail: feed it raw output chunks (Buffers); it retains only the last `maxBytes`, dropping the
17
+ * head incrementally so memory is O(maxBytes) regardless of total output. Byte-precise (the OOM bound is bytes).
18
+ */
3
19
  export declare class RollingTailBuffer {
4
20
  private readonly maxBytes;
5
21
  private readonly chunks;
@@ -7,26 +23,71 @@ export declare class RollingTailBuffer {
7
23
  private headDropped;
8
24
  private sourceSkipped;
9
25
  constructor(maxBytes?: number);
26
+ /** Append a chunk; evict head bytes (whole or partial chunks) until within `maxBytes`. */
10
27
  push(chunk: Buffer): void;
28
+ /** Account bytes that were dropped BEFORE ever reaching the buffer (e.g. a spool reader skipping
29
+ * un-retainable backlog at the source). They join `droppedBytes` so `markTruncated` discloses the
30
+ * TRUE number of missing bytes — recording them here instead of pushing keeps the drop O(1). */
11
31
  recordSkippedBytes(n: number): void;
32
+ /** The retained tail decoded as UTF-8, plus how many bytes are missing in total (head evictions +
33
+ * source skips — the foreground `markTruncated` disclosure keeps the combined figure). */
12
34
  result(): {
13
35
  text: string;
14
36
  droppedBytes: number;
15
37
  };
38
+ /** RB-234 ([1937]): the retained window's RAW bytes — cursor slicing must happen in the byte domain
39
+ * (re-encoding a lossily-decoded string inflates every invalid byte to a 3-byte U+FFFD and lands
40
+ * byte cursors on the wrong offsets). */
16
41
  bytes(): Buffer;
42
+ /** RB-234 ([1937]): head-eviction count ALONE — the retention window is [headDroppedBytes, pushed-total)
43
+ * in the accepted-byte domain; source skips must not shift this origin. */
17
44
  headDroppedBytes(): number;
45
+ /** RB-234 ([1937]): source-skip count alone (see {@link recordSkippedBytes}) — poll disclosure reports
46
+ * the per-poll increment of this figure instead of silently absorbing it into the window origin. */
18
47
  sourceSkippedBytes(): number;
19
48
  }
49
+ /** RB-234 ([1937]): per-stream cursor state for incremental (poll-style) consumption of a
50
+ * {@link RollingTailBuffer}. All counters live in the ACCEPTED-byte domain (bytes actually pushed);
51
+ * source skips are tracked separately for disclosure. Module-level export (not on the package
52
+ * surface) so the slice arithmetic is unit-pinnable without an 8MB integration harness. */
20
53
  export interface StreamCursorState {
21
54
  tail: RollingTailBuffer;
55
+ /** Consumer position in the accepted-byte domain (bytes already delivered). */
22
56
  cursorBytes: number;
57
+ /** Bytes actually pushed into `tail` (excludes source skips — those never had content to deliver). */
23
58
  acceptedBytes: number;
59
+ /** `tail.sourceSkippedBytes()` as of the last slice — the delta is disclosed exactly once. */
24
60
  disclosedSkippedBytes: number;
61
+ /** Incremental UTF-8 decoder (CC 2.1.220 shape: StringDecoder holds a split multi-byte char across
62
+ * reads instead of emitting replacement chars at every read boundary). */
25
63
  decoder: StringDecoder;
26
64
  }
65
+ /** Fresh cursor state over a new tail. */
27
66
  export declare function newStreamCursorState(tail?: RollingTailBuffer): StreamCursorState;
67
+ /**
68
+ * RB-234 ([1937]): slice the undelivered increment out of a rolling tail — in the BYTE domain, decoded
69
+ * incrementally. Replaces the former decode→re-encode→byte-offset-subarray shape, which mixed two
70
+ * domains: byte cursors landed inside a re-encoded string whose length differs from the raw stream as
71
+ * soon as any invalid-UTF-8 byte sits in the window (each inflates to a 3-byte U+FFFD), making every
72
+ * later poll re-deliver the same trailing garbage forever (a sleeping process "producing" output).
73
+ *
74
+ * - Continuity: a multi-byte char split across two slices is held by the decoder and completed on the
75
+ * next slice — zero replacement chars, zero duplication.
76
+ * - Discontinuity (`droppedBeforeCursor > 0`): the decoder is rebuilt, so bytes on either side of a
77
+ * hole are never joined into a fake character.
78
+ * - `terminal`: flush the decoder (a trailing split char becomes one honest U+FFFD) — without this
79
+ * the last 1–3 bytes of a finished stream would never surface.
80
+ *
81
+ * `droppedBeforeCursor` = head-evicted bytes the cursor never got to + the NEW source-skip increment
82
+ * since the previous slice (formerly silent: skips shifted the window origin instead, re-delivering
83
+ * already-served bytes with `truncated` unset).
84
+ */
28
85
  export declare function sliceStreamIncrement(s: StreamCursorState, terminal: boolean): {
29
86
  inc: string;
30
87
  droppedBeforeCursor: number;
31
88
  };
89
+ /**
90
+ * Prepend a model-visible marker when `droppedBytes > 0` (only the TAIL was kept). The SINGLE source of the
91
+ * marker wording so the engine and any downstream adapter show the model the SAME thing.
92
+ */
32
93
  export declare function markTruncated(text: string, droppedBytes: number): string;
@@ -1,7 +1,14 @@
1
+ /** rel path of `child` under `root` in "/" form (win root) / verbatim form (posix root); null when not under.
2
+ * codex 1.237 F7: fold "\" only under a WIN-family root ({@link isWinFormPath}); a POSIX tree may legally
3
+ * contain literal backslashes in FILE NAMES, and folding them corrupted both the manifest key and the
4
+ * restore target. */
1
5
  declare function relUnder(root: string, child: string): string | null;
6
+ /** Join root + a "/"-form relPath using the ROOT's native separator (keys stay family-consistent). */
2
7
  declare function joinUnder(root: string, rel: string): string;
3
8
  import type { ExecutionEnv } from "../internal/harness-types.js";
4
9
  export interface FileSnapshotError {
10
+ /** `too_large` = the tree exceeded a bound (fail-CLOSED, NOT a silent partial snapshot); `not_found` = no
11
+ * snapshot for that key; `aborted` = the signal fired; the rest = an underlying fs op failed. */
5
12
  code: "too_large" | "enumerate_failed" | "read_failed" | "restore_failed" | "not_found" | "aborted";
6
13
  message: string;
7
14
  }
@@ -11,23 +18,106 @@ export type FileSnapshotResult = {
11
18
  ok: false;
12
19
  error: FileSnapshotError;
13
20
  };
21
+ /**
22
+ * Capture/restore a working-tree file set keyed by `(scope, key)` — `scope` = sessionId, `key` =
23
+ * `SessionTreeEntry.id` (same anchor as E18 resume-at). All methods are best-effort and NEVER throw — failures
24
+ * are encoded in the returned {@link FileSnapshotResult} (mirrors the ExecutionEnv FileSystem contract).
25
+ *
26
+ * **v1 fidelity bounds (design/101 §defer):** files only — symlinks are NOT captured and are REMOVED by
27
+ * `restore` (they are a path-escape vector); empty directories are not tracked; `restore` re-enumerates under
28
+ * the SAME bounds, so a tree that grew past a bound since the snapshot cannot be rewound (fail-closed).
29
+ */
14
30
  export interface FileSnapshotStore {
31
+ /** Capture the tree under `root` for `(scope, key)`. CREATE-ONCE: a second call for an existing key is a
32
+ * no-op `{ok:true}` (a session entry id is immutable, so its tree state is too). */
15
33
  snapshot(scope: string, key: string, env: ExecutionEnv, root: string, signal?: AbortSignal): Promise<FileSnapshotResult>;
34
+ /** Converge the tree under `root` back to the snapshot for `(scope, key)`: remove obstructions/strays
35
+ * (symlinks + files created since), then write every captured file — so the tree MATCHES the snapshot. */
16
36
  restore(scope: string, key: string, env: ExecutionEnv, root: string, signal?: AbortSignal): Promise<FileSnapshotResult>;
37
+ /** Whether a snapshot exists for `(scope, key)`. */
17
38
  has(scope: string, key: string): Promise<boolean>;
39
+ /** GC: drop every snapshot in `scope` whose key is NOT in `keepKeys` (e.g. unreachable branches). Returns the
40
+ * number of snapshots removed. */
18
41
  reap(scope: string, keepKeys: string[]): Promise<number>;
42
+ /** Every snapshot key in `scope` (order unspecified). The enumeration counterpart of {@link reap} (which
43
+ * already iterates the same set internally) — exposed for a cross-backend session EXPORT (service 2c
44
+ * session-sync, [266]): list a session's snapshot keys to move its {entries + file snapshots} to another
45
+ * backend. A durable backend implements it as a `SELECT key WHERE scope = ?`. */
19
46
  listKeys(scope: string): Promise<string[]>;
47
+ /**
48
+ * 2c session-sync ([271]): the manifest (`relPath → blobHash`) for `(scope, key)`, or `null` if absent — to
49
+ * EXPORT a snapshot's content to another backend. Pairs with {@link getBlob} for CONTENT-ADDRESSED (deduped)
50
+ * blob transfer: the caller fetches each distinct hash ONCE across all of a session's snapshots. Optional — a
51
+ * backend that supports cross-backend snapshot export implements it.
52
+ */
20
53
  exportManifest?(scope: string, key: string): Promise<Map<string, string> | null>;
54
+ /** 2c session-sync ([271]): the content-addressed bytes for `hash` (undefined if absent). */
21
55
  getBlob?(hash: string): Promise<Uint8Array | undefined>;
56
+ /**
57
+ * 2c session-sync ([273]): STORE a snapshot INTO this store from another store's {@link exportManifest} +
58
+ * {@link getBlob} output — the import-side mirror that closes the cross-backend transfer loop. For each DISTINCT
59
+ * blob hash in `manifest`, fetch its bytes via `srcGetBlob`, VERIFY content-address integrity
60
+ * (`sha256(bytes) === hash`), and store it (content-addressed dedup); THEN record `(scope, key) → manifest`.
61
+ *
62
+ * - CREATE-ONCE: a second import for an existing key is a no-op `{ok:true}` (an entry id is immutable).
63
+ * - FAIL-CLOSED: a missing OR hash-mismatched source blob → `read_failed` and NO manifest is committed (never a
64
+ * partial snapshot that a later {@link restore} would silently truncate). The manifest's relPaths are NOT
65
+ * re-validated here — `restore` remains the path-escape gate (it already neutralizes unsafe relPaths).
66
+ * - Pure store→store: does NOT touch an `ExecutionEnv` (unlike `applyManifest`, which converges ONE snapshot to a
67
+ * working tree; import preserves ALL historical snapshots in the dst store so a later rewind-to-past finds them).
68
+ *
69
+ * Optional — a backend that supports cross-backend snapshot import implements it.
70
+ */
22
71
  importManifest?(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
72
+ /**
73
+ * 2c session-sync ([277]): STORE a single content-addressed blob — the symmetric WRITE side of {@link getBlob},
74
+ * for a two-phase PUSH (upload blobs, THEN import the manifest that references them). VERIFIES content-address
75
+ * integrity (`sha256(bytes) === hash`) so a corrupt/mismatched upload can never poison the store (a later
76
+ * getBlob/restore would otherwise return wrong content); a mismatch → `read_failed`, nothing stored. IMMUTABLE +
77
+ * content-addressed: a repeat putBlob for the same hash is a no-op (the bytes are identical by definition).
78
+ * Returns a {@link FileSnapshotResult} (NOT void) so the integrity failure is encodable under the never-throw
79
+ * contract. Optional — a backend that supports a two-phase push implements it.
80
+ *
81
+ * ⚠️ ORCHESTRATION CAVEAT: a pushed blob is NOT yet referenced by any manifest (the matching
82
+ * {@link importManifest} runs LATER), so — unlike `snapshot`/`importManifest`, which hold their blobs in an
83
+ * `inFlight` live-set across the whole store-then-commit — a `putBlob`'d blob is reap-ELIGIBLE in the window
84
+ * before its manifest is imported. The two-phase pusher MUST NOT `reap` the scope between PUT and import (a
85
+ * grace-window). This is fail-closed, not corrupting: blobs are content-addressed (re-push is always safe) and
86
+ * `importManifest` re-verifies+stores every blob before committing, so a reaped blob → `read_failed` with NO
87
+ * dangling-reference manifest, never wrong content.
88
+ */
23
89
  putBlob?(hash: string, bytes: Uint8Array): Promise<FileSnapshotResult>;
24
90
  }
91
+ /** Bounds for the reference enumerator — a deliberate, fail-CLOSED cost policy (NOT the grep walk's silent caps). */
25
92
  export interface FileSnapshotBounds {
93
+ /** Hard cap on file count; exceeding it REFUSES the snapshot (`too_large`) rather than silently truncating. */
26
94
  maxFiles: number;
95
+ /** Hard cap on total bytes; exceeding it REFUSES the snapshot. */
27
96
  maxBytes: number;
97
+ /** Directory BASENAMES skipped anywhere in the tree (cost bound). Default `.git` + `node_modules`. */
28
98
  ignoreDirs: Set<string>;
29
99
  }
30
100
  export declare const DEFAULT_SNAPSHOT_BOUNDS: FileSnapshotBounds;
101
+ /**
102
+ * Capture the working tree under `root` into a manifest `relPath → sha256`, handing each file's bytes to
103
+ * `putBlob` (the backend stores them content-addressed). **The env-operating + security-critical half a durable
104
+ * backend MUST reuse** (not re-implement — duplication risks re-introducing the symlink-escape / fail-closed
105
+ * bugs the dual-review fixed). Fail-CLOSED: an enumerate/read/bound failure returns an error and the caller must
106
+ * NOT persist a partial manifest. Never throws.
107
+ *
108
+ * [789] vanished-file tolerance: a file that DISAPPEARED between enumerate and read (`not_found`) is OMITTED
109
+ * from the manifest instead of failing the whole capture. This is semantically SAFE — the E19 snapshot runs
110
+ * concurrently with a live tree (the `done` frame is emitted BEFORE the snapshot, so shell-side per-turn
111
+ * markers, `.git/index.lock`, editor swap files etc. legitimately vanish mid-walk), and omitting a
112
+ * just-deleted file yields the CONSISTENT tree state of one instant later — NOT a partial snapshot (which
113
+ * would mean "captured bytes are missing for a file that exists"). No re-stat second check is needed:
114
+ * `not_found` is a stable backend-independent FileErrorCode (locally the SOLE mapping of ENOENT,
115
+ * node-execution-env.ts toFileError) — the read itself IS the authoritative existence probe at capture time,
116
+ * and a re-stat would only re-open the same race one window later. Every OTHER read error (permission_denied/
117
+ * EIO/unknown…) and any enumerate failure keeps the fail-closed whole-capture rejection: those mean "the file
118
+ * is still there but we could not capture it" — omitting it WOULD be a data-lossy partial snapshot.
119
+ * `skippedVanished` reports the count for observability/tests.
120
+ */
31
121
  export declare function captureManifest(env: ExecutionEnv, root: string, bounds: FileSnapshotBounds, signal: AbortSignal | undefined, putBlob: (hash: string, bytes: Uint8Array) => void | Promise<void>): Promise<{
32
122
  ok: true;
33
123
  value: Map<string, string>;
@@ -36,7 +126,19 @@ export declare function captureManifest(env: ExecutionEnv, root: string, bounds:
36
126
  ok: false;
37
127
  error: FileSnapshotError;
38
128
  }>;
129
+ /**
130
+ * CONVERGE the tree under `root` to `manifest`, loading each captured file's bytes via `getBlob`. **The
131
+ * env-operating + security-critical half a durable backend MUST reuse.** Order is load-bearing (codex BLOCKER +
132
+ * Opus M1): PHASE 1 removes every current symlink (neutralizes a `dir -> /outside` ancestor that writeFile would
133
+ * otherwise follow OUT of root) + every file created since; PHASE 2 writes each captured file, clearing a
134
+ * directory that now occupies a file's path first. Never throws.
135
+ */
39
136
  export declare function applyManifest(env: ExecutionEnv, root: string, bounds: FileSnapshotBounds, signal: AbortSignal | undefined, manifest: Map<string, string>, getBlob: (hash: string) => Uint8Array | undefined | Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
137
+ /**
138
+ * In-memory, content-addressed reference {@link FileSnapshotStore}. Blobs are deduplicated by sha256 ACROSS all
139
+ * snapshots (a file unchanged between turns is stored once); each snapshot keeps a manifest `relPath → hash`.
140
+ * Single-process (the default-deps reference; a durable/file-backed impl mirrors `src/stores/file/`).
141
+ */
40
142
  export declare class InMemoryFileSnapshotStore implements FileSnapshotStore {
41
143
  private readonly blobs;
42
144
  private readonly manifests;
@@ -53,6 +155,8 @@ export declare class InMemoryFileSnapshotStore implements FileSnapshotStore {
53
155
  importManifest(scope: string, key: string, manifest: Map<string, string>, srcGetBlob: (hash: string) => Promise<Uint8Array | undefined>): Promise<FileSnapshotResult>;
54
156
  reap(scope: string, keepKeys: string[]): Promise<number>;
55
157
  }
158
+ /** Test-only window (REF-C2 class pins): pure path helpers whose family-awareness carries a fence/
159
+ * restore invariant. Not re-exported from src/index.ts. */
56
160
  export declare const __testables: {
57
161
  joinUnder: typeof joinUnder;
58
162
  relUnder: typeof relUnder;