@sema-agent/core 7.54.1 → 7.56.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 (621) hide show
  1. package/CHANGELOG.md +950 -0
  2. package/dist/agents/agent-transcript-tool.js +2 -1
  3. package/dist/agents/builtin-agents.d.ts +12 -14
  4. package/dist/agents/cascade.js +1 -1
  5. package/dist/agents/cc-peer-directory.d.ts +36 -0
  6. package/dist/agents/cc-peer-directory.js +139 -0
  7. package/dist/agents/cc-peer-wire.d.ts +105 -0
  8. package/dist/agents/cc-peer-wire.js +98 -0
  9. package/dist/agents/cc-uds-peer-channel.d.ts +40 -0
  10. package/dist/agents/cc-uds-peer-channel.js +457 -0
  11. package/dist/agents/child-model-seat.d.ts +0 -11
  12. package/dist/agents/child-model-seat.js +0 -3
  13. package/dist/agents/cross-session-envelope.d.ts +4 -1
  14. package/dist/agents/cross-session-envelope.js +8 -1
  15. package/dist/agents/cross-session-judge.d.ts +2 -2
  16. package/dist/agents/list-agents-tool.d.ts +3 -1
  17. package/dist/agents/list-agents-tool.js +9 -8
  18. package/dist/agents/observer.d.ts +4 -5
  19. package/dist/agents/observer.js +2 -1
  20. package/dist/agents/peer-admission.d.ts +6 -0
  21. package/dist/agents/peer-admission.js +4 -1
  22. package/dist/agents/peer-directory.d.ts +65 -13
  23. package/dist/agents/peer-directory.js +90 -25
  24. package/dist/agents/peer-notices.d.ts +1 -1
  25. package/dist/agents/peer-session-drain.d.ts +3 -1
  26. package/dist/agents/peer-session-drain.js +3 -2
  27. package/dist/agents/read-inbox-tool.js +2 -1
  28. package/dist/agents/repair-loop.js +2 -2
  29. package/dist/agents/retain-ledger.d.ts +1 -1
  30. package/dist/agents/roster-store.d.ts +1 -1
  31. package/dist/agents/send-message-tool.d.ts +10 -0
  32. package/dist/agents/send-message-tool.js +37 -8
  33. package/dist/agents/subagent.d.ts +39 -82
  34. package/dist/agents/subagent.js +109 -106
  35. package/dist/agents/tool-filter.d.ts +31 -46
  36. package/dist/agents/tool-filter.js +13 -33
  37. package/dist/agents/verify.d.ts +6 -5
  38. package/dist/agents/verify.js +3 -3
  39. package/dist/brain/anthropic.js +43 -81
  40. package/dist/brain/errors.d.ts +15 -0
  41. package/dist/brain/errors.js +10 -0
  42. package/dist/brain/media-degrade.d.ts +18 -7
  43. package/dist/brain/media-degrade.js +13 -2
  44. package/dist/brain/model-capability.d.ts +37 -0
  45. package/dist/brain/model-capability.js +34 -0
  46. package/dist/brain/model-presets.d.ts +6 -12
  47. package/dist/brain/model-presets.js +1 -6
  48. package/dist/brain/open-responses.js +27 -35
  49. package/dist/brain/openai.js +30 -98
  50. package/dist/brain/provider-dialect.d.ts +39 -3
  51. package/dist/brain/provider-dialect.js +28 -0
  52. package/dist/brain/reasoning-request.d.ts +96 -0
  53. package/dist/brain/reasoning-request.js +174 -0
  54. package/dist/brain/reasoning.d.ts +12 -12
  55. package/dist/brain/reasoning.js +4 -3
  56. package/dist/brain/request-params.d.ts +62 -9
  57. package/dist/brain/request-params.js +42 -7
  58. package/dist/brain/retry.d.ts +1 -1
  59. package/dist/brain/route-adjudicator.d.ts +15 -0
  60. package/dist/brain/route-adjudicator.js +15 -0
  61. package/dist/brain/status-sink.d.ts +20 -0
  62. package/dist/brain/status-sink.js +7 -0
  63. package/dist/brain/stream-engine.js +6 -5
  64. package/dist/brain/stream-shared.d.ts +1 -1
  65. package/dist/core/a2a.d.ts +2 -1
  66. package/dist/core/a2a.js +19 -13
  67. package/dist/core/advisor-verdict.d.ts +120 -0
  68. package/dist/core/advisor-verdict.js +92 -0
  69. package/dist/core/agent-definition.d.ts +17 -8
  70. package/dist/core/allow-entry.d.ts +69 -36
  71. package/dist/core/allow-entry.js +81 -52
  72. package/dist/core/allow-rule-shadow.d.ts +10 -3
  73. package/dist/core/approval-object.d.ts +2 -1
  74. package/dist/core/approval-object.js +6 -6
  75. package/dist/core/ask-origin.d.ts +127 -29
  76. package/dist/core/ask-origin.js +87 -25
  77. package/dist/core/ask-question.d.ts +51 -8
  78. package/dist/core/ask-question.js +12 -7
  79. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  80. package/dist/core/ask-unresolvable-notice.js +16 -2
  81. package/dist/core/auto-compaction.d.ts +11 -8
  82. package/dist/core/auto-compaction.js +4 -2
  83. package/dist/core/auto-mode-arming.d.ts +2 -2
  84. package/dist/core/auto-mode-defaults.d.ts +8 -8
  85. package/dist/core/auto-mode-prompt-assets.d.ts +3 -3
  86. package/dist/core/auto-mode-prompt.d.ts +1 -1
  87. package/dist/core/auto-mode.d.ts +17 -9
  88. package/dist/core/auto-mode.js +9 -6
  89. package/dist/core/background-agent-store.d.ts +3 -3
  90. package/dist/core/canonical-json.d.ts +1 -1
  91. package/dist/core/canonical-json.js +2 -2
  92. package/dist/core/checkpoint-generation.d.ts +53 -0
  93. package/dist/core/checkpoint-generation.js +35 -0
  94. package/dist/core/checkpoint-queries.d.ts +180 -0
  95. package/dist/core/checkpoint-queries.js +272 -0
  96. package/dist/core/checkpoint-requirements.d.ts +19 -4
  97. package/dist/core/checkpoint-requirements.js +8 -14
  98. package/dist/core/checkpoint-store.d.ts +165 -72
  99. package/dist/core/checkpoint-store.js +79 -82
  100. package/dist/core/child-clamp-seats.d.ts +6 -0
  101. package/dist/core/child-clamp-seats.js +3 -16
  102. package/dist/core/compliance.d.ts +2 -2
  103. package/dist/core/context-edit.d.ts +6 -7
  104. package/dist/core/cross-boundary-taint.d.ts +11 -4
  105. package/dist/core/cross-boundary-taint.js +3 -3
  106. package/dist/core/decision-receipt.d.ts +37 -3
  107. package/dist/core/decision-receipt.js +19 -19
  108. package/dist/core/delegation-not-started.d.ts +6 -0
  109. package/dist/core/delegation-not-started.js +17 -0
  110. package/dist/core/effective-path-target.d.ts +1 -1
  111. package/dist/core/engine-attestation.d.ts +93 -0
  112. package/dist/core/engine-attestation.js +70 -0
  113. package/dist/core/engine-capabilities.d.ts +4 -1
  114. package/dist/core/engine-capabilities.js +1 -1
  115. package/dist/core/engine-notice.d.ts +45 -12
  116. package/dist/core/exec-output-tail.d.ts +1 -1
  117. package/dist/core/file-history-retention.d.ts +1 -1
  118. package/dist/core/file-history-store.d.ts +147 -21
  119. package/dist/core/file-history-store.js +58 -32
  120. package/dist/core/gate-fold.d.ts +1 -1
  121. package/dist/core/gate-fold.js +24 -11
  122. package/dist/core/gate-lanes.js +81 -68
  123. package/dist/core/gate-outcome.d.ts +40 -6
  124. package/dist/core/gate-outcome.js +56 -0
  125. package/dist/core/governance-codes.d.ts +17 -3
  126. package/dist/core/governance-codes.js +16 -0
  127. package/dist/core/hands-band.d.ts +1 -1
  128. package/dist/core/hooks.d.ts +21 -20
  129. package/dist/core/hooks.js +3 -1
  130. package/dist/core/host-floor.d.ts +128 -0
  131. package/dist/core/host-floor.js +206 -0
  132. package/dist/core/host-target.d.ts +84 -0
  133. package/dist/core/host-target.js +92 -0
  134. package/dist/core/image-downsample.d.ts +1 -1
  135. package/dist/core/lsp-diagnostics.d.ts +4 -4
  136. package/dist/core/lsp.d.ts +3 -3
  137. package/dist/core/mailbox-store.d.ts +4 -0
  138. package/dist/core/mcp-connection-pool.d.ts +18 -2
  139. package/dist/core/mcp-connection-pool.js +53 -6
  140. package/dist/core/mcp-failure.d.ts +23 -4
  141. package/dist/core/mcp-failure.js +26 -11
  142. package/dist/core/mcp-listing-drift.d.ts +10 -0
  143. package/dist/core/mcp-listing-drift.js +6 -0
  144. package/dist/core/mcp-server-link.d.ts +173 -0
  145. package/dist/core/mcp-server-link.js +127 -0
  146. package/dist/core/mcp-server-spec.d.ts +4 -2
  147. package/dist/core/mcp-session-end.d.ts +26 -0
  148. package/dist/core/mcp-session-end.js +29 -0
  149. package/dist/core/mcp-startup-request.d.ts +17 -0
  150. package/dist/core/mcp-startup-request.js +17 -0
  151. package/dist/core/mcp.d.ts +17 -13
  152. package/dist/core/mcp.js +240 -189
  153. package/dist/core/media-byte-cap.d.ts +1 -1
  154. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  155. package/dist/core/memory-engine/engine.d.ts +9 -9
  156. package/dist/core/memory-engine/engine.js +4 -4
  157. package/dist/core/memory-engine/layout.d.ts +60 -8
  158. package/dist/core/memory-engine/layout.js +65 -6
  159. package/dist/core/memory-engine/provenance-wording.d.ts +1 -1
  160. package/dist/core/memory-engine/tools.js +4 -1
  161. package/dist/core/mode-policy.d.ts +1 -1
  162. package/dist/core/model-seat.d.ts +10 -3
  163. package/dist/core/mods/classic-events.d.ts +67 -0
  164. package/dist/core/mods/classic-events.js +1 -0
  165. package/dist/core/mods/dollar.d.ts +13 -0
  166. package/dist/core/mods/extension-call.d.ts +31 -0
  167. package/dist/core/mods/extension-call.js +43 -0
  168. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  169. package/dist/core/mods/kernel/dispatch.js +140 -69
  170. package/dist/core/mods/kernel/events.d.ts +47 -11
  171. package/dist/core/mods/kernel/events.js +66 -42
  172. package/dist/core/mods/kernel/index.d.ts +4 -4
  173. package/dist/core/mods/kernel/index.js +2 -2
  174. package/dist/core/mods/kernel/receive.d.ts +39 -5
  175. package/dist/core/mods/kernel/receive.js +290 -17
  176. package/dist/core/mods/kernel/registration.d.ts +33 -2
  177. package/dist/core/mods/kernel/registration.js +6 -7
  178. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  179. package/dist/core/mods/kernel/site-rules.js +24 -42
  180. package/dist/core/mods/spec-seats.d.ts +69 -0
  181. package/dist/core/mods/spec-seats.js +114 -0
  182. package/dist/core/mods/stations.d.ts +28 -8
  183. package/dist/core/mods/stations.js +29 -13
  184. package/dist/core/mods/tool-call.d.ts +79 -0
  185. package/dist/core/mods/tool-call.js +152 -0
  186. package/dist/core/namespaced-rule-name.d.ts +44 -24
  187. package/dist/core/namespaced-rule-name.js +50 -43
  188. package/dist/core/output-style.d.ts +1 -1
  189. package/dist/core/param-rule-reach.d.ts +15 -0
  190. package/dist/core/param-rule-reach.js +30 -0
  191. package/dist/core/parent-spec-seat.d.ts +13 -1
  192. package/dist/core/parent-spec-seat.js +6 -0
  193. package/dist/core/park-selfcheck.js +1 -0
  194. package/dist/core/pause-registry.d.ts +16 -5
  195. package/dist/core/pause-registry.js +6 -2
  196. package/dist/core/peer-channel.d.ts +70 -0
  197. package/dist/core/peer-channel.js +1 -0
  198. package/dist/core/permission-rule-consent.d.ts +30 -5
  199. package/dist/core/permission-rule-consent.js +147 -50
  200. package/dist/core/permission-rule-model.d.ts +245 -65
  201. package/dist/core/permission-rule-model.js +421 -107
  202. package/dist/core/permission-rule-org.d.ts +6 -2
  203. package/dist/core/permission-rule-org.js +7 -3
  204. package/dist/core/permission-rule-provider.d.ts +6 -2
  205. package/dist/core/permission-rule-provider.js +41 -11
  206. package/dist/core/permission-rule-store.d.ts +22 -26
  207. package/dist/core/permission-rule-store.js +12 -6
  208. package/dist/core/permission-rule-sync.d.ts +11 -2
  209. package/dist/core/permission-rule-sync.js +11 -3
  210. package/dist/core/permission-rule-syntax.d.ts +5 -4
  211. package/dist/core/permission-rule-syntax.js +2 -2
  212. package/dist/core/permission-rules.d.ts +53 -15
  213. package/dist/core/permission-rules.js +125 -100
  214. package/dist/core/persisted-rule-arms.d.ts +6 -4
  215. package/dist/core/persisted-rule-arms.js +10 -12
  216. package/dist/core/present-plan-tool.js +3 -1
  217. package/dist/core/principal-name.d.ts +20 -0
  218. package/dist/core/principal-name.js +22 -0
  219. package/dist/core/prompt-section-seat.js +4 -6
  220. package/dist/core/protocol-http-auth.d.ts +26 -5
  221. package/dist/core/protocol-http-auth.js +137 -4
  222. package/dist/core/protocol-naming.d.ts +2 -2
  223. package/dist/core/read-only-shell-table.d.ts +1 -1
  224. package/dist/core/read-only-shell.d.ts +1 -1
  225. package/dist/core/retired-keys.d.ts +16 -0
  226. package/dist/core/retired-keys.js +16 -4
  227. package/dist/core/rewrite-rejudge.d.ts +60 -0
  228. package/dist/core/rewrite-rejudge.js +36 -0
  229. package/dist/core/roles.d.ts +34 -3
  230. package/dist/core/roles.js +66 -53
  231. package/dist/core/rule-lane-reads.d.ts +20 -15
  232. package/dist/core/rule-lane-reads.js +45 -17
  233. package/dist/core/rule-offer-read.d.ts +53 -0
  234. package/dist/core/rule-offer-read.js +146 -0
  235. package/dist/core/rule-owner.d.ts +46 -0
  236. package/dist/core/rule-owner.js +29 -0
  237. package/dist/core/runner/advisor-instructions.d.ts +70 -0
  238. package/dist/core/runner/advisor-instructions.js +61 -0
  239. package/dist/core/runner/advisor-tool.d.ts +33 -0
  240. package/dist/core/runner/advisor-tool.js +112 -0
  241. package/dist/core/runner/announce-once-ledger.d.ts +18 -26
  242. package/dist/core/runner/announce-once-ledger.js +19 -46
  243. package/dist/core/runner/approval-feedback.js +6 -3
  244. package/dist/core/runner/assemble-result.d.ts +2 -1
  245. package/dist/core/runner/assemble-result.js +1 -1
  246. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  247. package/dist/core/runner/caller-roster.d.ts +21 -2
  248. package/dist/core/runner/caller-roster.js +38 -0
  249. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  250. package/dist/core/runner/capability-withheld-seat.js +24 -0
  251. package/dist/core/runner/classifier-ladder.d.ts +33 -13
  252. package/dist/core/runner/classifier-ladder.js +15 -14
  253. package/dist/core/runner/compaction-restate.d.ts +10 -6
  254. package/dist/core/runner/compaction-restate.js +9 -3
  255. package/dist/core/runner/construction-doors.js +3 -0
  256. package/dist/core/runner/contracts.d.ts +40 -33
  257. package/dist/core/runner/conversation-segment.d.ts +28 -0
  258. package/dist/core/runner/conversation-segment.js +42 -0
  259. package/dist/core/runner/cross-boundary-lane.d.ts +21 -16
  260. package/dist/core/runner/cross-boundary-lane.js +58 -34
  261. package/dist/core/runner/decide-continuation.d.ts +7 -4
  262. package/dist/core/runner/decide-continuation.js +2 -2
  263. package/dist/core/runner/denial-limit-arms.d.ts +4 -4
  264. package/dist/core/runner/denial-limit-arms.js +1 -1
  265. package/dist/core/runner/derived-route-fallback.d.ts +24 -24
  266. package/dist/core/runner/derived-route-fallback.js +9 -7
  267. package/dist/core/runner/file-history-request.d.ts +18 -0
  268. package/dist/core/runner/file-history-request.js +21 -13
  269. package/dist/core/runner/file-history-restore.d.ts +45 -0
  270. package/dist/core/runner/file-history-restore.js +46 -0
  271. package/dist/core/runner/gate-exit.d.ts +9 -3
  272. package/dist/core/runner/gate-exit.js +11 -5
  273. package/dist/core/runner/image.d.ts +7 -17
  274. package/dist/core/runner/image.js +9 -60
  275. package/dist/core/runner/initial-run-state.js +1 -1
  276. package/dist/core/runner/permission-rule-lanes.d.ts +6 -6
  277. package/dist/core/runner/permission-rule-lanes.js +38 -15
  278. package/dist/core/runner/person-path-rows.d.ts +12 -9
  279. package/dist/core/runner/person-path-rows.js +19 -8
  280. package/dist/core/runner/prepare-advisor.d.ts +63 -0
  281. package/dist/core/runner/prepare-advisor.js +77 -0
  282. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  283. package/dist/core/runner/prepare-ask-lane.js +5 -2
  284. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  285. package/dist/core/runner/prepare-caps-and-workflow.js +5 -4
  286. package/dist/core/runner/prepare-config-doors.d.ts +31 -38
  287. package/dist/core/runner/prepare-config-doors.js +57 -34
  288. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  289. package/dist/core/runner/prepare-defer-classify.js +7 -8
  290. package/dist/core/runner/prepare-delegation-surface.d.ts +2 -2
  291. package/dist/core/runner/prepare-delegation-surface.js +1 -1
  292. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  293. package/dist/core/runner/prepare-file-history.js +41 -73
  294. package/dist/core/runner/prepare-gate-stations.d.ts +2 -5
  295. package/dist/core/runner/prepare-gate-stations.js +12 -8
  296. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  297. package/dist/core/runner/prepare-hands-readface.js +15 -14
  298. package/dist/core/runner/prepare-inherited-gate.d.ts +11 -7
  299. package/dist/core/runner/prepare-inherited-gate.js +8 -6
  300. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  301. package/dist/core/runner/prepare-park-ask.js +12 -12
  302. package/dist/core/runner/prepare-policy-chain.d.ts +7 -4
  303. package/dist/core/runner/prepare-policy-chain.js +68 -81
  304. package/dist/core/runner/prepare-project-context.d.ts +5 -2
  305. package/dist/core/runner/prepare-project-context.js +6 -3
  306. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  307. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  308. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  309. package/dist/core/runner/prepare-prompt-inputs.js +4 -6
  310. package/dist/core/runner/prepare-protocol-tools.d.ts +4 -2
  311. package/dist/core/runner/prepare-protocol-tools.js +5 -4
  312. package/dist/core/runner/prepare-safety-scan.d.ts +9 -12
  313. package/dist/core/runner/prepare-safety-scan.js +8 -23
  314. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  315. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  316. package/dist/core/runner/prepare-task.d.ts +1 -1
  317. package/dist/core/runner/prepare-task.js +41 -35
  318. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  319. package/dist/core/runner/prepare-tool-disclosure-mount.js +24 -18
  320. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  321. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  322. package/dist/core/runner/prepare-wiring-manifest.d.ts +11 -4
  323. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  324. package/dist/core/runner/resume-admission.js +1 -1
  325. package/dist/core/runner/resume-apply.js +11 -12
  326. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  327. package/dist/core/runner/resume-claim.d.ts +4 -2
  328. package/dist/core/runner/resume-claim.js +15 -8
  329. package/dist/core/runner/resume-policy-outcome.js +1 -1
  330. package/dist/core/runner/retired-runner-deps.js +2 -1
  331. package/dist/core/runner/rewind-files.d.ts +15 -0
  332. package/dist/core/runner/rewind-files.js +132 -0
  333. package/dist/core/runner/run-attachment-seats.js +2 -2
  334. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  335. package/dist/core/runner/run-brain-sinks.js +4 -2
  336. package/dist/core/runner/run-compaction-machinery.d.ts +1 -1
  337. package/dist/core/runner/run-compaction-machinery.js +2 -12
  338. package/dist/core/runner/run-git-lane.d.ts +1 -0
  339. package/dist/core/runner/run-harness-handlers.js +14 -7
  340. package/dist/core/runner/run-leg.d.ts +1 -1
  341. package/dist/core/runner/run-leg.js +43 -18
  342. package/dist/core/runner/run-settle-and-teardown.js +3 -2
  343. package/dist/core/runner/run-telemetry-and-budget-seats.js +1 -1
  344. package/dist/core/runner/run-turn-boundary.d.ts +1 -0
  345. package/dist/core/runner/run-turn-boundary.js +15 -22
  346. package/dist/core/runner/runtask.d.ts +3 -0
  347. package/dist/core/runner/runtask.js +8 -9
  348. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  349. package/dist/core/runner/session-read-file-states.js +28 -0
  350. package/dist/core/runner/session-rule-policy.d.ts +22 -21
  351. package/dist/core/runner/session-rule-policy.js +17 -31
  352. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  353. package/dist/core/runner/shell-env-withheld.js +51 -0
  354. package/dist/core/runner/side-call-account.d.ts +32 -8
  355. package/dist/core/runner/side-call-account.js +23 -1
  356. package/dist/core/runner/skills-seat.js +6 -2
  357. package/dist/core/runner/stream-settle-backstop.js +1 -1
  358. package/dist/core/runner/strict-output-schema.d.ts +1 -1
  359. package/dist/core/runner/sub-agent-deny-lists.js +4 -6
  360. package/dist/core/runner/synthetic-tools.d.ts +16 -13
  361. package/dist/core/runner/synthetic-tools.js +8 -3
  362. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  363. package/dist/core/runner/tool-disclosure.js +3 -4
  364. package/dist/core/runner/tool-end-body.d.ts +1 -1
  365. package/dist/core/runner/tool-end-body.js +10 -9
  366. package/dist/core/runner/tool-face-overlay.d.ts +2 -1
  367. package/dist/core/runner/tool-face-overlay.js +17 -1
  368. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  369. package/dist/core/runner/tool-not-executed.js +11 -0
  370. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  371. package/dist/core/runner/tool-occurrence.js +7 -0
  372. package/dist/core/runner/tool-progress-lane.d.ts +2 -2
  373. package/dist/core/runner/tool-turn-repair-seat.d.ts +3 -2
  374. package/dist/core/runner/turn-attachments.d.ts +91 -80
  375. package/dist/core/runner/turn-attachments.js +62 -37
  376. package/dist/core/runner-deps.d.ts +42 -42
  377. package/dist/core/runtime-caps.d.ts +4 -4
  378. package/dist/core/safety-axis-vocab.d.ts +6 -4
  379. package/dist/core/safety-axis-vocab.js +6 -5
  380. package/dist/core/safety-merge-corpus.js +26 -2
  381. package/dist/core/same-plain-value.d.ts +40 -0
  382. package/dist/core/same-plain-value.js +49 -0
  383. package/dist/core/scheduler.d.ts +1 -1
  384. package/dist/core/secret-env.d.ts +26 -3
  385. package/dist/core/secret-env.js +44 -8
  386. package/dist/core/select-model.js +3 -3
  387. package/dist/core/sensitive-path-policy.d.ts +1 -1
  388. package/dist/core/sensitive-path-policy.js +1 -1
  389. package/dist/core/session-policy-store.d.ts +102 -35
  390. package/dist/core/session-policy-store.js +210 -48
  391. package/dist/core/session-reconcile.d.ts +2 -2
  392. package/dist/core/session-store.d.ts +106 -37
  393. package/dist/core/session-store.js +165 -91
  394. package/dist/core/session.d.ts +101 -57
  395. package/dist/core/session.js +53 -0
  396. package/dist/core/shared-memory/tools.js +3 -1
  397. package/dist/core/shared-memory/types.d.ts +1 -1
  398. package/dist/core/shell-read-silence.d.ts +11 -12
  399. package/dist/core/shell-read-silence.js +9 -5
  400. package/dist/core/shell-run-candidates.js +3 -1
  401. package/dist/core/shell-wrapper-projection.js +1 -1
  402. package/dist/core/shell-wrapper-table.d.ts +14 -7
  403. package/dist/core/shell-wrapper-table.js +5 -4
  404. package/dist/core/side-query.d.ts +10 -0
  405. package/dist/core/side-query.js +15 -1
  406. package/dist/core/skill-grant.d.ts +7 -2
  407. package/dist/core/skill-grant.js +5 -0
  408. package/dist/core/skills-directory.js +6 -2
  409. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  410. package/dist/core/store-contracts/checkpoint-store-contract.js +168 -3
  411. package/dist/core/store-contracts/file-history-store-contract.js +74 -4
  412. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  413. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  414. package/dist/core/store-contracts/session-policy-store-contract.d.ts +7 -0
  415. package/dist/core/store-contracts/session-policy-store-contract.js +130 -0
  416. package/dist/core/store-contracts/session-repo-contract.js +176 -0
  417. package/dist/core/store-contracts/session-store-contract.d.ts +6 -8
  418. package/dist/core/store-contracts/session-store-contract.js +361 -51
  419. package/dist/core/store-contracts/workflow-journal-store-contract.js +26 -1
  420. package/dist/core/stub-env.d.ts +2 -0
  421. package/dist/core/stub-env.js +1 -0
  422. package/dist/core/surrogate-safe-slice.d.ts +3 -3
  423. package/dist/core/synthetic-read-verdict.js +3 -3
  424. package/dist/core/task-event.d.ts +42 -8
  425. package/dist/core/task-notification.d.ts +19 -15
  426. package/dist/core/task-registry-agent.d.ts +4 -4
  427. package/dist/core/task-registry-shared.d.ts +4 -4
  428. package/dist/core/task-registry-shared.js +1 -0
  429. package/dist/core/task-registry.d.ts +13 -4
  430. package/dist/core/task-registry.js +14 -2
  431. package/dist/core/task-result.d.ts +21 -3
  432. package/dist/core/task-spec.d.ts +69 -64
  433. package/dist/core/task-stream.d.ts +6 -6
  434. package/dist/core/task-tool-shape.d.ts +4 -4
  435. package/dist/core/tighten-task-spec.d.ts +1 -1
  436. package/dist/core/tighten-task-spec.js +2 -1
  437. package/dist/core/tool-catalog-entries.d.ts +36 -2
  438. package/dist/core/tool-catalog-entries.js +69 -43
  439. package/dist/core/tool-check-reading.d.ts +11 -0
  440. package/dist/core/tool-check-reading.js +11 -6
  441. package/dist/core/tool-conformance.js +1 -0
  442. package/dist/core/tool-errors.d.ts +2 -2
  443. package/dist/core/tool-face-reader.js +5 -3
  444. package/dist/core/tool-face.d.ts +21 -2
  445. package/dist/core/tool-face.js +1 -1
  446. package/dist/core/tool-model-gate.d.ts +5 -5
  447. package/dist/core/tool-name-aliases.d.ts +29 -8
  448. package/dist/core/tool-name-aliases.js +22 -4
  449. package/dist/core/tool-name-readings.d.ts +10 -43
  450. package/dist/core/tool-name-readings.js +2 -11
  451. package/dist/core/tool-policy.d.ts +85 -196
  452. package/dist/core/tool-policy.js +150 -175
  453. package/dist/core/tool-registry.d.ts +14 -7
  454. package/dist/core/tool-registry.js +17 -7
  455. package/dist/core/tool-result-store.js +5 -1
  456. package/dist/core/tool-roster.d.ts +57 -33
  457. package/dist/core/tool-roster.js +56 -68
  458. package/dist/core/tool-spec-members.js +8 -3
  459. package/dist/core/tool-spec.d.ts +53 -31
  460. package/dist/core/tools.js +51 -10
  461. package/dist/core/trace.d.ts +6 -2
  462. package/dist/core/types.d.ts +1 -1
  463. package/dist/core/untrusted-egress.d.ts +1 -1
  464. package/dist/core/untrusted-text.d.ts +1 -1
  465. package/dist/core/user-attachment.d.ts +8 -1
  466. package/dist/core/user-attachment.js +64 -4
  467. package/dist/core/warm-resume.d.ts +1 -1
  468. package/dist/core/wiring-manifest.d.ts +58 -0
  469. package/dist/core/wiring-manifest.js +14 -5
  470. package/dist/core/workflow-journal-store.d.ts +62 -0
  471. package/dist/core/workflow-journal-store.js +78 -2
  472. package/dist/core/workflow-run-store.d.ts +6 -0
  473. package/dist/core/workflow-run-store.js +2 -0
  474. package/dist/engine/compaction/compaction.d.ts +9 -9
  475. package/dist/engine/compaction/compaction.js +3 -2
  476. package/dist/engine/execution-env/node-execution-env.d.ts +26 -8
  477. package/dist/engine/execution-env/node-execution-env.js +54 -24
  478. package/dist/engine/harness/agent-harness.d.ts +39 -9
  479. package/dist/engine/harness/agent-harness.js +87 -33
  480. package/dist/engine/harness/types.d.ts +58 -9
  481. package/dist/engine/harness/types.js +12 -1
  482. package/dist/engine/llm/types.d.ts +36 -19
  483. package/dist/engine/llm/validation.d.ts +4 -1
  484. package/dist/engine/llm/validation.js +13 -1
  485. package/dist/engine/loop/agent-loop.d.ts +23 -1
  486. package/dist/engine/loop/agent-loop.js +26 -34
  487. package/dist/engine/loop/types.d.ts +31 -19
  488. package/dist/engine/lsp/node-lsp-manager.d.ts +2 -2
  489. package/dist/engine/session/memory-repo.d.ts +18 -12
  490. package/dist/engine/session/memory-repo.js +24 -9
  491. package/dist/engine/session/parent-chain-guard.d.ts +3 -2
  492. package/dist/engine/session/parent-chain-guard.js +1 -1
  493. package/dist/engine/session/repo-utils.d.ts +32 -3
  494. package/dist/engine/session/repo-utils.js +50 -5
  495. package/dist/index.d.ts +47 -23
  496. package/dist/index.js +35 -17
  497. package/dist/internal/harness-types.d.ts +1 -1
  498. package/dist/internal/harness.d.ts +3 -3
  499. package/dist/internal/harness.js +2 -2
  500. package/dist/internal/llm.d.ts +2 -2
  501. package/dist/internal/llm.js +1 -1
  502. package/dist/orchestration/goal.js +2 -2
  503. package/dist/orchestration/run-workflow-tool.d.ts +8 -6
  504. package/dist/orchestration/run-workflow-tool.js +10 -6
  505. package/dist/orchestration/workflow-size-guideline.d.ts +4 -4
  506. package/dist/orchestration/workflow-types.d.ts +18 -0
  507. package/dist/orchestration/workflow-types.js +6 -0
  508. package/dist/orchestration/workflow.d.ts +5 -13
  509. package/dist/orchestration/workflow.js +57 -49
  510. package/dist/prompt-assembly/artifact.d.ts +2 -2
  511. package/dist/prompt-assembly/artifact.js +5 -3
  512. package/dist/prompt-assembly/assemble.d.ts +3 -2
  513. package/dist/prompt-assembly/assemble.js +1 -1
  514. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  515. package/dist/prompt-assembly/catalog/schema.js +34 -2
  516. package/dist/prompt-assembly/catalog/sections.js +0 -1
  517. package/dist/prompt-assembly/composer.d.ts +3 -1
  518. package/dist/prompt-assembly/composer.js +1 -1
  519. package/dist/prompt-assembly/event-registry.js +2 -0
  520. package/dist/prompt-assembly/overlay.js +3 -3
  521. package/dist/prompt-assembly/renderers.d.ts +1 -1
  522. package/dist/prompt-assembly/renderers.js +0 -3
  523. package/dist/prompt-assembly/role-base.d.ts +15 -0
  524. package/dist/prompt-assembly/role-base.js +9 -0
  525. package/dist/prompt-assembly/select.d.ts +39 -14
  526. package/dist/prompt-assembly/select.js +47 -16
  527. package/dist/prompt-assembly/sugar.d.ts +17 -11
  528. package/dist/prompt-assembly/sugar.js +8 -3
  529. package/dist/prompt-assembly/tool-catalog.d.ts +39 -2
  530. package/dist/prompt-assembly/tool-catalog.js +117 -4
  531. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  532. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  533. package/dist/prompt-assembly/types.d.ts +0 -7
  534. package/dist/prompts/default.d.ts +14 -14
  535. package/dist/scenarios/full-body.d.ts +15 -15
  536. package/dist/scenarios/full-body.js +4 -3
  537. package/dist/shell/lex.js +10 -1
  538. package/dist/stores/file/adoption/adopt.d.ts +4 -3
  539. package/dist/stores/file/adoption/adopt.js +27 -33
  540. package/dist/stores/file/adoption/marker.d.ts +6 -13
  541. package/dist/stores/file/adoption/marker.js +9 -17
  542. package/dist/stores/file/checkpoint-store.d.ts +24 -0
  543. package/dist/stores/file/checkpoint-store.js +45 -7
  544. package/dist/stores/file/file-history-store.d.ts +20 -19
  545. package/dist/stores/file/file-history-store.js +157 -141
  546. package/dist/stores/file/fs-atomic.d.ts +15 -0
  547. package/dist/stores/file/fs-atomic.js +89 -14
  548. package/dist/stores/file/index.d.ts +1 -1
  549. package/dist/stores/file/index.js +2 -1
  550. package/dist/stores/file/mailbox-store.d.ts +3 -0
  551. package/dist/stores/file/mailbox-store.js +3 -1
  552. package/dist/stores/file/permission-rule-adopt.d.ts +1 -1
  553. package/dist/stores/file/permission-rule-adopt.js +18 -18
  554. package/dist/stores/file/permission-rule-store.d.ts +18 -2
  555. package/dist/stores/file/permission-rule-store.js +31 -18
  556. package/dist/stores/file/session-policy-store.d.ts +3 -3
  557. package/dist/stores/file/session-store.d.ts +54 -16
  558. package/dist/stores/file/session-store.js +114 -85
  559. package/dist/stores/file/workflow-journal-store.d.ts +10 -4
  560. package/dist/stores/file/workflow-journal-store.js +28 -13
  561. package/dist/tools/artifact/artifact-text.d.ts +1 -1
  562. package/dist/tools/artifact/artifact-tool.js +5 -3
  563. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  564. package/dist/tools/fs/bash-program-position.js +56 -9
  565. package/dist/tools/fs/bash-readonly-classifier.d.ts +3 -3
  566. package/dist/tools/fs/fs-bash.d.ts +2 -2
  567. package/dist/tools/fs/fs-bash.js +8 -6
  568. package/dist/tools/fs/fs-glob.d.ts +86 -0
  569. package/dist/tools/fs/fs-glob.js +226 -0
  570. package/dist/tools/fs/fs-read.js +14 -14
  571. package/dist/tools/fs/fs-search-tools.js +7 -7
  572. package/dist/tools/fs/fs-shared.d.ts +8 -8
  573. package/dist/tools/fs/gh-rate-limit.d.ts +1 -1
  574. package/dist/tools/fs/notebook.d.ts +2 -2
  575. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  576. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  577. package/dist/tools/fs/pdf.d.ts +9 -6
  578. package/dist/tools/fs/pdf.js +3 -3
  579. package/dist/tools/fs/program-read-model.d.ts +57 -7
  580. package/dist/tools/fs/program-read-model.js +11 -1
  581. package/dist/tools/fs/program-read-model.rows.js +78 -21
  582. package/dist/tools/fs/read-deny-home.js +3 -2
  583. package/dist/tools/fs/read-deny.d.ts +29 -7
  584. package/dist/tools/fs/read-deny.js +63 -22
  585. package/dist/tools/fs/removal-targets.d.ts +18 -8
  586. package/dist/tools/fs/removal-targets.js +47 -20
  587. package/dist/tools/fs/safety.d.ts +9 -9
  588. package/dist/tools/fs/search.d.ts +16 -6
  589. package/dist/tools/fs/search.js +20 -26
  590. package/dist/tools/fs/shell-read-argv.js +89 -12
  591. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  592. package/dist/tools/fs/shell-read-bindings.js +41 -0
  593. package/dist/tools/fs/shell-read-check.js +12 -20
  594. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  595. package/dist/tools/fs/shell-read-environment.js +3 -2
  596. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  597. package/dist/tools/fs/shell-read-establish.js +19 -20
  598. package/dist/tools/fs/shell-read-judge.d.ts +4 -0
  599. package/dist/tools/fs/shell-read-judge.js +5 -2
  600. package/dist/tools/fs/shell-read-plan.js +24 -16
  601. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  602. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  603. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  604. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  605. package/dist/tools/fs/shell-reentry-text.js +40 -2
  606. package/dist/tools/loop-tick.d.ts +2 -2
  607. package/dist/tools/scheduler-tools.js +5 -1
  608. package/dist/tools/task-list.d.ts +7 -7
  609. package/dist/tools/task-list.js +5 -1
  610. package/dist/tools/todo.js +65 -64
  611. package/dist/tools/web.d.ts +20 -15
  612. package/dist/tools/web.js +55 -69
  613. package/dist/tools/worktree.d.ts +3 -3
  614. package/dist/tools/worktree.js +3 -1
  615. package/package.json +1 -1
  616. package/test/export-surface.snapshot.json +5894 -5638
  617. package/wire-changes/core@7.55.0.json +3318 -0
  618. package/wire-changes/core@7.56.0.json +3891 -0
  619. package/wire-changes/mods-kernel@7.56.0.json +303 -0
  620. package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +0 -39
  621. package/dist/core/store-contracts/session-store-incarnation-contract.js +0 -95
@@ -62,6 +62,18 @@ export interface JsonlRecordJudge {
62
62
  accepts(record: object): boolean;
63
63
  what: string;
64
64
  }
65
+ /**
66
+ * The FIRST record of an open JSONL file of `size` bytes — the record {@link readJsonlRecords} would return first — read forward one
67
+ * block at a time and stopping there: a read bounded by the lines before it, never by the file. Skipped lines are not disclosed (the
68
+ * whole-file read discloses them); `undefined` = the file holds no record.
69
+ */
70
+ export declare function firstJsonlRecord(fd: number, size: number, judge?: JsonlRecordJudge): object | undefined;
71
+ /**
72
+ * The LAST record of an open JSONL file of `size` bytes that `pick` accepts — the last such record {@link readJsonlRecords} would
73
+ * return — found by walking back from the end one block at a time: a read bounded by the lines after it, never by the file. The
74
+ * unterminated last segment is judged as the whole-file read judges it. Skipped lines are not disclosed; `undefined` = none.
75
+ */
76
+ export declare function lastJsonlRecord(fd: number, size: number, pick: (record: object) => boolean, judge?: JsonlRecordJudge): object | undefined;
65
77
  /**
66
78
  * An append-only JSONL log opened once with `O_APPEND` and held for the file's lifetime. One record =
67
79
  * one `JSON.stringify(...) + "\n"` written in a SINGLE `writeSync` call (never split across writes → the
@@ -162,6 +174,9 @@ export declare class AppendLog {
162
174
  */
163
175
  private rollBackFailedWrite;
164
176
  close(): void;
177
+ /** Whether this log's open descriptor is the file its path names now (same device and inode). A file removed or replaced under it
178
+ * is not — its writes land on an inode no reader of the path sees — and neither is a log with no open descriptor. */
179
+ isFileAtPath(): boolean;
165
180
  /**
166
181
  * RB-167 — release the descriptor for a compaction SWAP. The next write reopens it lazily.
167
182
  *
@@ -1,4 +1,4 @@
1
- import { appendFileSync, closeSync, constants as FS, existsSync, fstatSync, ftruncateSync, linkSync, mkdirSync, openSync, readFileSync, readSync, renameSync, truncateSync, unlinkSync, writeFileSync, writeSync, fsyncSync, } from "node:fs";
1
+ import { appendFileSync, closeSync, constants as FS, existsSync, fstatSync, ftruncateSync, linkSync, mkdirSync, openSync, readFileSync, readSync, renameSync, statSync, truncateSync, unlinkSync, writeFileSync, writeSync, fsyncSync, } from "node:fs";
2
2
  import { constants as bufferConstants } from "node:buffer";
3
3
  import { homedir, hostname, uptime } from "node:os";
4
4
  import { hrtime } from "node:process";
@@ -142,19 +142,11 @@ export function readJsonlRecords(path, onCorrupt, judge) {
142
142
  const line = parts[i];
143
143
  if (line === "")
144
144
  continue;
145
- const read = jsonlTextFormOf(line);
146
- if (read.form === "unparseable") {
147
- if (i === parts.length - 1)
148
- break;
149
- discloseSkip("torn-json", i + 1, "unparseable jsonl record");
150
- continue;
151
- }
152
- if (read.form === "not-an-object") {
153
- discloseSkip("not-an-object", i + 1, `jsonl record is ${jsonTypeName(read.value)}, not an object`);
154
- continue;
155
- }
156
- if (judge !== undefined && !judge.accepts(read.record)) {
157
- discloseSkip("missing-required", i + 1, judge.what);
145
+ const read = readJsonlLine(line, i === parts.length - 1, judge);
146
+ if (read.verdict === "partial-tail")
147
+ break;
148
+ if (read.verdict === "skip") {
149
+ discloseSkip(read.form, i + 1, read.what);
158
150
  continue;
159
151
  }
160
152
  out.push(read.record);
@@ -166,6 +158,77 @@ export function readJsonlRecords(path, onCorrupt, judge) {
166
158
  }
167
159
  return out;
168
160
  }
161
+ function readJsonlLine(line, unterminated, judge) {
162
+ const read = jsonlTextFormOf(line);
163
+ if (read.form === "unparseable")
164
+ return unterminated ? { verdict: "partial-tail" } : { verdict: "skip", form: "torn-json", what: "unparseable jsonl record" };
165
+ if (read.form === "not-an-object")
166
+ return { verdict: "skip", form: "not-an-object", what: `jsonl record is ${jsonTypeName(read.value)}, not an object` };
167
+ if (judge !== undefined && !judge.accepts(read.record))
168
+ return { verdict: "skip", form: "missing-required", what: judge.what };
169
+ return { verdict: "record", record: read.record };
170
+ }
171
+ function assertJudgeableLine(length) {
172
+ if (length > JSONL_TAIL_SEGMENT_LIMIT)
173
+ throw new Error(`jsonl record cursor: a line of ${length} bytes is past the judgeable bound (${JSONL_TAIL_SEGMENT_LIMIT})`);
174
+ }
175
+ function jsonlLineText(bytes) {
176
+ assertJudgeableLine(bytes.length);
177
+ return bytes.toString("utf8");
178
+ }
179
+ export function firstJsonlRecord(fd, size, judge) {
180
+ let carry = Buffer.alloc(0);
181
+ for (let from = 0; from < size;) {
182
+ const block = Buffer.allocUnsafe(Math.min(JSONL_TAIL_READ_BLOCK, size - from));
183
+ readExactly(fd, block, block.length, from);
184
+ from += block.length;
185
+ let data = carry.length > 0 ? Buffer.concat([carry, block]) : block;
186
+ for (let nl = data.indexOf(0x0a); nl >= 0; nl = data.indexOf(0x0a)) {
187
+ const text = jsonlLineText(data.subarray(0, nl));
188
+ data = data.subarray(nl + 1);
189
+ if (text === "")
190
+ continue;
191
+ const read = readJsonlLine(text, false, judge);
192
+ if (read.verdict === "record")
193
+ return read.record;
194
+ }
195
+ carry = Buffer.from(data);
196
+ assertJudgeableLine(carry.length);
197
+ }
198
+ if (carry.length === 0)
199
+ return undefined;
200
+ const read = readJsonlLine(jsonlLineText(carry), true, judge);
201
+ return read.verdict === "record" ? read.record : undefined;
202
+ }
203
+ export function lastJsonlRecord(fd, size, pick, judge) {
204
+ let carry = Buffer.alloc(0);
205
+ let segmentEndsFile = true;
206
+ const visit = (bytes) => {
207
+ const unterminated = segmentEndsFile;
208
+ segmentEndsFile = false;
209
+ if (bytes.length === 0)
210
+ return undefined;
211
+ const read = readJsonlLine(jsonlLineText(bytes), unterminated, judge);
212
+ return read.verdict === "record" && pick(read.record) ? read.record : undefined;
213
+ };
214
+ for (let end = size; end > 0;) {
215
+ const from = Math.max(0, end - JSONL_TAIL_READ_BLOCK);
216
+ const block = Buffer.allocUnsafe(end - from);
217
+ readExactly(fd, block, block.length, from);
218
+ end = from;
219
+ const data = carry.length > 0 ? Buffer.concat([block, carry]) : block;
220
+ let segEnd = data.length;
221
+ for (let nl = segEnd > 0 ? data.lastIndexOf(0x0a, segEnd - 1) : -1; nl >= 0; nl = segEnd > 0 ? data.lastIndexOf(0x0a, segEnd - 1) : -1) {
222
+ const hit = visit(data.subarray(nl + 1, segEnd));
223
+ if (hit !== undefined)
224
+ return hit;
225
+ segEnd = nl;
226
+ }
227
+ carry = Buffer.from(data.subarray(0, segEnd));
228
+ assertJudgeableLine(carry.length);
229
+ }
230
+ return visit(carry);
231
+ }
169
232
  function jsonTypeName(value) {
170
233
  if (value === null)
171
234
  return "null";
@@ -271,6 +334,18 @@ export class AppendLog {
271
334
  this.disposed = true;
272
335
  this.releaseFd();
273
336
  }
337
+ isFileAtPath() {
338
+ if (this.fd < 0)
339
+ return false;
340
+ try {
341
+ const open = fstatSync(this.fd, { bigint: true });
342
+ const named = statSync(this.path, { bigint: true });
343
+ return open.dev === named.dev && open.ino === named.ino;
344
+ }
345
+ catch {
346
+ return false;
347
+ }
348
+ }
274
349
  closeForSwap() {
275
350
  this.releaseFd();
276
351
  }
@@ -27,7 +27,7 @@ export { resolveDataRoot, sanitizeScope, sanitizePathComponent, createFileConsol
27
27
  export { FileStoreLockError, type FileStoreLockErrorCode } from "./fs-atomic.js";
28
28
  export { atomicWriteFile, writeThenLink, ensureDir, readJsonlRecords, AppendLog } from "./fs-atomic.js";
29
29
  export { processFingerprint, isProcessLive, type ProcessFingerprint } from "./fs-atomic.js";
30
- export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootAdoptionFile, ROOT_ADOPTION_FILE, type AdoptionErrorCode, type AdoptionSource, type AdoptionReport, type AdoptionReceipt, type AdoptionLegReport, type AffectedDeploymentConfig, type RootAdoptionFile, } from "./adoption/marker.js";
30
+ export { AdoptionError, assertAdoptionBootGate, readRootAdoptionFile, writeRootAdoptionFile, ROOT_ADOPTION_FILE, type AdoptionErrorCode, type AdoptionReport, type AdoptionReceipt, type AdoptionLegReport, type AffectedDeploymentConfig, type RootAdoptionFile, } from "./adoption/marker.js";
31
31
  export { adoptLocalDataRoot, ackAdoptionConfig, witnessAdoptionConfig, listAdoptionQuarantine, readAdoptionStatus, type AdoptionStatus, type AdoptLocalDataRootOptions, type AdoptLocalDataRootResult, type AdoptionCarriageLeg, type AdoptionCarriageLegContext, type AdoptionConfigWitnessReceipt, } from "./adoption/adopt.js";
32
32
  /**
33
33
  * design/80 — the file-backed {@link EngineStorageBackend} for the local (TOC) single-user binary, selected
@@ -62,7 +62,8 @@ export class FileStorageBackend {
62
62
  this.fileSessions = repo;
63
63
  this.ttl = new TtlSessionStore({ repo, evict: opts.evict ?? "forget", durability: "durable", placements: { subagent: { durability: "durable" } } });
64
64
  this.sessionStore = this.ttl;
65
- this.fileCheckpoints = new FileCheckpointStore(this.root, { ...opts.checkpoint, ...corruptRead });
65
+ const sessionHeadOf = this.ttl.headOf;
66
+ this.fileCheckpoints = new FileCheckpointStore(this.root, { ...opts.checkpoint, ...corruptRead, ...(sessionHeadOf !== undefined ? { sessionHeadOf } : {}) });
66
67
  built.push(() => this.fileCheckpoints.close());
67
68
  this.checkpointStore = this.fileCheckpoints;
68
69
  this.fileMemory = new FileMemoryStore(this.root, opts.embedder ? { embedder: opts.embedder } : {});
@@ -52,6 +52,9 @@ export declare class FileMailboxStore implements MailboxStore {
52
52
  /** design/385 — the whole cross-process set (box lock + fresh re-read + descriptor reopen +
53
53
  * compaction under the lock) is in place and accepted by `mailboxCrossProcessContract`. */
54
54
  readonly crossProcessSafe = true;
55
+ /** The sha-256 of the PHYSICAL path of the boxes directory: every instance over one directory — whatever
56
+ * spelling of the root it was built from, in any process — answers the same identity. */
57
+ readonly identity: string;
55
58
  private readonly dir;
56
59
  private readonly tmpDir;
57
60
  private readonly fsyncEnabled;
@@ -1,5 +1,5 @@
1
1
  import { join, resolve, sep } from "node:path";
2
- import { randomBytes } from "node:crypto";
2
+ import { createHash, randomBytes } from "node:crypto";
3
3
  import { assertRetentionPolicy } from "../../core/retention-policy.js";
4
4
  import { existsSync, linkSync, readdirSync, readFileSync, renameSync, statSync, unlinkSync, writeFileSync } from "node:fs";
5
5
  import { detachMailboxMessage, newestSentAt, readMailboxPeerMeta, } from "../../core/mailbox-store.js";
@@ -324,6 +324,7 @@ function sweepLockResidue(dir, lockName) {
324
324
  }
325
325
  export class FileMailboxStore {
326
326
  crossProcessSafe = true;
327
+ identity;
327
328
  dir;
328
329
  tmpDir;
329
330
  fsyncEnabled;
@@ -347,6 +348,7 @@ export class FileMailboxStore {
347
348
  ensureDir(lexicalTmp);
348
349
  this.dir = physicalPathOf(lexicalDir);
349
350
  this.tmpDir = physicalPathOf(lexicalTmp);
351
+ this.identity = createHash("sha256").update(this.dir).digest("hex");
350
352
  }
351
353
  boxPath(scope, handle) {
352
354
  return join(this.dir, sanitizeScope(scope), `${sanitizePathComponent(handle).toLowerCase()}.jsonl`);
@@ -24,7 +24,7 @@
24
24
  * join, deliberately not a rename. Rows the far side refuses during ⑤ move to the local quarantine
25
25
  * area — preserved and disclosed, never deleted (the F-011 "nothing is lost" floor).
26
26
  */
27
- import type { RuleOwner } from "../../core/permission-rule-store.js";
27
+ import { type RuleOwner } from "../../core/rule-owner.js";
28
28
  import { type PermissionRuleSyncResult, type PermissionRuleSyncTransport } from "../../core/permission-rule-sync.js";
29
29
  export type AdoptFileRuleStoreResult =
30
30
  /** The full arc completed (this call, or an earlier one — the terminal marker makes it idempotent). */
@@ -1,28 +1,34 @@
1
1
  import { existsSync, renameSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { writerOf } from "../../core/permission-rule-store.js";
4
+ import { readRuleOwner, ruleOwnerText, sameRuleOwner } from "../../core/rule-owner.js";
5
+ import { principalNameOf } from "../../core/principal-name.js";
4
6
  import { createPermissionRuleStoreProvider } from "../../core/permission-rule-provider.js";
5
7
  import { syncPermissionRules } from "../../core/permission-rule-sync.js";
6
8
  import { thrownText } from "../../core/thrown-value.js";
7
9
  import { FileStoreLockError } from "./fs-atomic.js";
8
10
  import { FileDurableRulePartitionProvider, LOCAL_OWNER_FILE, principalRuleFileName, readRuleAdoptionFile, writeRuleAdoptionFile, } from "./permission-rule-store.js";
9
11
  export async function adoptFilePermissionRuleStore(opts) {
10
- if (typeof opts.toPrincipal !== "string" || opts.toPrincipal === "") {
11
- throw new Error("adoptFilePermissionRuleStore requires the adopting principal — adoption is the act of giving this bucket an identity");
12
+ if (principalNameOf(opts.toPrincipal) === undefined) {
13
+ throw new Error("adoptFilePermissionRuleStore requires the adopting principal, a principal name — adoption is the act of giving this bucket an identity");
12
14
  }
13
- if (opts.from.kind === "principal" && opts.from.principal === opts.toPrincipal) {
15
+ const from = readRuleOwner(opts.from);
16
+ if (from === undefined) {
17
+ throw new Error("adoptFilePermissionRuleStore requires a source owner — a principal owner whose principal is a principal name, or the local owner");
18
+ }
19
+ if (from.kind === "principal" && from.principal === opts.toPrincipal) {
14
20
  throw new Error(`the bucket already belongs to "${opts.toPrincipal}" — there is nothing to adopt`);
15
21
  }
16
- const sourceFile = join(opts.dir, opts.from.kind === "local-owner" ? LOCAL_OWNER_FILE : principalRuleFileName(opts.from.principal));
22
+ const sourceFile = join(opts.dir, from.kind === "local-owner" ? LOCAL_OWNER_FILE : principalRuleFileName(from.principal));
17
23
  const targetFile = join(opts.dir, principalRuleFileName(opts.toPrincipal));
18
24
  const existing = readRuleAdoptionFile(opts.dir);
19
25
  if (existing !== undefined) {
20
26
  if ("adopted" in existing) {
21
- if (existing.adopted.toPrincipal === opts.toPrincipal && sameOwner(existing.adopted.from, opts.from))
27
+ if (existing.adopted.toPrincipal === opts.toPrincipal && sameRuleOwner(existing.adopted.from, from))
22
28
  return { status: "adopted" };
23
- throw new Error(`this directory already carries a completed adoption (${ownerText(existing.adopted.from)} → "${existing.adopted.toPrincipal}") — a second adoption of the same directory is not a shape this helper supports`);
29
+ throw new Error(`this directory already carries a completed adoption (${ruleOwnerText(existing.adopted.from)} → "${existing.adopted.toPrincipal}") — a second adoption of the same directory is not a shape this helper supports`);
24
30
  }
25
- if (existing.marker.toPrincipal !== opts.toPrincipal || !sameOwner(existing.marker.from, opts.from)) {
31
+ if (existing.marker.toPrincipal !== opts.toPrincipal || !sameRuleOwner(existing.marker.from, from)) {
26
32
  throw new Error(`an adoption toward "${existing.marker.toPrincipal}" is already in flight in this directory — refusing to start a different one (resume the original, or repair the marker by hand)`);
27
33
  }
28
34
  }
@@ -44,7 +50,7 @@ export async function adoptFilePermissionRuleStore(opts) {
44
50
  throw new Error("the target store refused a write face");
45
51
  let phase = existing !== undefined && "marker" in existing ? existing.marker.phase : 2;
46
52
  if (existing === undefined) {
47
- writeRuleAdoptionFile(opts.dir, marker(opts.from, opts.toPrincipal, 2));
53
+ writeRuleAdoptionFile(opts.dir, marker(from, opts.toPrincipal, 2));
48
54
  phase = 2;
49
55
  }
50
56
  if (phase < 3) {
@@ -55,11 +61,11 @@ export async function adoptFilePermissionRuleStore(opts) {
55
61
  }
56
62
  if (sourcePresent)
57
63
  renameSync(sourceFile, targetFile);
58
- writeRuleAdoptionFile(opts.dir, marker(opts.from, opts.toPrincipal, 3));
64
+ writeRuleAdoptionFile(opts.dir, marker(from, opts.toPrincipal, 3));
59
65
  phase = 3;
60
66
  }
61
67
  if (phase < 4) {
62
- writeRuleAdoptionFile(opts.dir, marker(opts.from, opts.toPrincipal, 4));
68
+ writeRuleAdoptionFile(opts.dir, marker(from, opts.toPrincipal, 4));
63
69
  phase = 4;
64
70
  }
65
71
  let syncResult;
@@ -82,12 +88,12 @@ export async function adoptFilePermissionRuleStore(opts) {
82
88
  error: `the first sync round did not land clean (${(syncResult.warnings ?? []).join("; ") || `${syncResult.dropped.length} drop(s)`}) — resume when the endpoint is healthy`,
83
89
  };
84
90
  }
85
- writeRuleAdoptionFile(opts.dir, marker(opts.from, opts.toPrincipal, 5));
91
+ writeRuleAdoptionFile(opts.dir, marker(from, opts.toPrincipal, 5));
86
92
  phase = 5;
87
93
  }
88
94
  writeRuleAdoptionFile(opts.dir, {
89
95
  schemaVersion: 1,
90
- adopted: { from: opts.from, toPrincipal: opts.toPrincipal, atMs: (opts.now ?? Date.now)() },
96
+ adopted: { from, toPrincipal: opts.toPrincipal, atMs: (opts.now ?? Date.now)() },
91
97
  });
92
98
  return { status: "adopted", ...(syncResult !== undefined ? { syncResult } : {}) };
93
99
  }
@@ -98,9 +104,3 @@ export async function adoptFilePermissionRuleStore(opts) {
98
104
  function marker(from, toPrincipal, phase) {
99
105
  return { schemaVersion: 1, marker: { from, toPrincipal, phase } };
100
106
  }
101
- function sameOwner(a, b) {
102
- return a.kind === "principal" ? b.kind === "principal" && a.principal === b.principal : b.kind === "local-owner";
103
- }
104
- function ownerText(o) {
105
- return o.kind === "principal" ? `principal "${o.principal}"` : "the local owner";
106
- }
@@ -8,6 +8,16 @@
8
8
  * reader accepts schema 4 ONLY: any other schema word is refused whole, loudly, bytes left untouched —
9
9
  * this engine performs no migration of an older engine's buckets.
10
10
  *
11
+ * ## A bucket carries its rule grammar
12
+ *
13
+ * Every write stamps the bucket with this engine's rule grammar (`grammar`, the number the session rules
14
+ * store stamps too); every read judges it through the one stamp judge (`readRuleGrammarStamp`). A bucket
15
+ * stamped with a later grammar was written by a newer engine whose rows this one may read as nothing — a
16
+ * deny it cannot parse refuses nothing — so it is refused WHOLE, like any bucket this engine cannot read,
17
+ * with its own code (`PERMISSION_RULES_LATER_GRAMMAR_CODE`): reads answer zero rules and say so, writes
18
+ * refuse, the bytes stay as they are. A bucket without the member was written before the stamp and reads
19
+ * in this engine's grammar; the next write stamps it.
20
+ *
11
21
  * ## Why this store builds its own symlink refusal
12
22
  *
13
23
  * The other file stores canonicalize with `realpath`, which RESOLVES a symlink rather than refusing one —
@@ -50,7 +60,8 @@
50
60
  * For this backend the trust is host = user, exactly as for the settings file it mirrors.
51
61
  */
52
62
  import type { PersistedRule, RuleTombstone } from "../../core/permission-rule-model.js";
53
- import type { DurableRulePartition, DurableRulePartitionProvider, PermissionRuleWriter, QuarantinedRuleAdd, RuleOwner, RuleSyncFrontier, StoredRules, WritableDurableRulePartition } from "../../core/permission-rule-store.js";
63
+ import type { DurableRulePartition, DurableRulePartitionProvider, PermissionRuleWriter, QuarantinedRuleAdd, RuleSyncFrontier, StoredRules, WritableDurableRulePartition } from "../../core/permission-rule-store.js";
64
+ import { type RuleOwner } from "../../core/rule-owner.js";
54
65
  import { PERMISSION_RULE_WRITER } from "../../core/permission-rule-store.js";
55
66
  import { type OrgRuleStatePersistence, type PersistedOrgRuleState } from "../../core/permission-rule-org.js";
56
67
  import type { StoreDurability, StoreFidelity } from "../../core/checkpoint-store.js";
@@ -72,6 +83,9 @@ interface RuleFile {
72
83
  lastRoundAtMs?: number;
73
84
  };
74
85
  quarantined?: QuarantinedRuleAdd[];
86
+ /** The rule grammar the rows were written in: stamped by every write, judged by every read (see the module note).
87
+ * Absent on a bucket written before the stamp. */
88
+ grammar?: number;
75
89
  checksum: string;
76
90
  }
77
91
  /** The deployment-wide org state file: last-known-good snapshot + anti-rollback high-water, one blob. */
@@ -145,6 +159,7 @@ declare class FileDurableRulePartition implements WritableDurableRulePartition {
145
159
  * sync wire (`readRaw`) or adjudication.
146
160
  */
147
161
  private screenDurableRows;
162
+ /** Publish `next` stamped with this engine's rule grammar — the stamp's one mint — and answer the checksum written. */
148
163
  private write;
149
164
  list(): Promise<StoredRules>;
150
165
  /** The quarantine area (design/182 §5.2/§8.3): introspection only — never part of `list()`. Its posture
@@ -162,7 +177,8 @@ declare class FileDurableRulePartition implements WritableDurableRulePartition {
162
177
  * unrecoverable one: the next redemption would write a fresh file over the damaged one, discarding every
163
178
  * standing rule, every tombstone, the revision and the replica identity, along with the evidence of what
164
179
  * went wrong. Reads already answer zero rules for the same condition, so the lane stays fail-closed
165
- * while a person looks at the file.
180
+ * while a person looks at the file. A bucket a newer engine wrote is one of these: writing it in this
181
+ * engine's grammar would stamp rows this engine cannot read with a grammar that claims it can.
166
182
  */
167
183
  private current;
168
184
  /**
@@ -3,8 +3,11 @@ import { join } from "node:path";
3
3
  import { createHash, randomBytes } from "node:crypto";
4
4
  import { isRuleBehavior } from "../../core/permission-rule-model.js";
5
5
  import { posixModeBitsMeaningful } from "../../core/posix-mode-face.js";
6
- import { PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, unknownRuleWriteDeltaError, } from "../../core/permission-rule-store.js";
6
+ import { readRuleOwner } from "../../core/rule-owner.js";
7
+ import { principalNameOf, readPrincipal } from "../../core/principal-name.js";
8
+ import { PERMISSION_RULES_LATER_GRAMMAR_CODE, PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, unknownRuleWriteDeltaError, } from "../../core/permission-rule-store.js";
7
9
  import { sameOrgPolicyContent } from "../../core/permission-rule-org.js";
10
+ import { SESSION_RULES_GRAMMAR, readRuleGrammarStamp } from "../../core/session-policy-store.js";
8
11
  import { canonicalize } from "../../core/canonical-json.js";
9
12
  import { BootLock, FileStoreLockError } from "./fs-atomic.js";
10
13
  import { assertAdoptionBootGate } from "./adoption/marker.js";
@@ -54,12 +57,6 @@ export function readRuleAdoptionFile(dir) {
54
57
  }
55
58
  return judged.marker;
56
59
  }
57
- function isRuleOwnerShape(v) {
58
- if (v === null || typeof v !== "object")
59
- return false;
60
- const owner = v;
61
- return owner.kind === "local-owner" || (owner.kind === "principal" && typeof owner.principal === "string");
62
- }
63
60
  function isRuleAdoptionFileShape(v) {
64
61
  if (v === null || typeof v !== "object" || v.schemaVersion !== 1)
65
62
  return false;
@@ -70,7 +67,7 @@ function isRuleAdoptionFileShape(v) {
70
67
  const rec = (hasMarker ? v.marker : v.adopted);
71
68
  if (rec === null || typeof rec !== "object")
72
69
  return false;
73
- if (!isRuleOwnerShape(rec.from) || typeof rec.toPrincipal !== "string" || rec.toPrincipal === "")
70
+ if (readRuleOwner(rec.from) === undefined || principalNameOf(rec.toPrincipal) === undefined)
74
71
  return false;
75
72
  return hasMarker ? rec.phase === 2 || rec.phase === 3 || rec.phase === 4 || rec.phase === 5 : typeof rec.atMs === "number" && Number.isFinite(rec.atMs);
76
73
  }
@@ -144,6 +141,9 @@ function refusalText(onError, sentence, location) {
144
141
  discloseTo(onError, `${sentence} (at ${location})`);
145
142
  return `${sentence}. The location is reported to the store's error disclosure (onError), not in this message.`;
146
143
  }
144
+ function unreadableError(r, sentence = r.unreadable) {
145
+ return r.code !== undefined ? Object.assign(new Error(sentence), { code: r.code }) : new Error(sentence);
146
+ }
147
147
  function discloseTo(onError, message) {
148
148
  try {
149
149
  onError?.(message);
@@ -226,6 +226,12 @@ class FileDurableRulePartition {
226
226
  const { checksum, ...body } = parsed;
227
227
  if (checksum !== checksumOf(body))
228
228
  return unreadable(`${bucket} failed its integrity check; ${whole}`);
229
+ const grammar = readRuleGrammarStamp(parsed.grammar, SESSION_RULES_GRAMMAR, { rules: `the rules in ${bucket}`, held: "rows" });
230
+ if ("got" in grammar) {
231
+ return grammar.later === true
232
+ ? { ...unreadable(`${grammar.sentence} — loading zero rules and refusing every write until then; the file is left as it is`), code: PERMISSION_RULES_LATER_GRAMMAR_CODE }
233
+ : unreadable(`${grammar.sentence}; ${whole}`);
234
+ }
229
235
  const rowKinds = [
230
236
  ["rule", parsed.rules],
231
237
  ["tombstone", parsed.tombstones],
@@ -254,12 +260,15 @@ class FileDurableRulePartition {
254
260
  }
255
261
  write(next) {
256
262
  assertSafeDirAtRequest(this.dir, this.onError, "write through", this.vetting);
257
- atomicPublish(this.dir, this.file, JSON.stringify({ ...next, checksum: checksumOf(next) }, null, 2));
263
+ const body = { ...next, grammar: SESSION_RULES_GRAMMAR };
264
+ const checksum = checksumOf(body);
265
+ atomicPublish(this.dir, this.file, JSON.stringify({ ...body, checksum }, null, 2));
266
+ return checksum;
258
267
  }
259
268
  async list() {
260
269
  const r = this.read();
261
270
  if ("unreadable" in r)
262
- throw new Error(r.unreadable);
271
+ throw unreadableError(r);
263
272
  if (!("file" in r))
264
273
  return { ...EMPTY_READ };
265
274
  const screened = this.screenDurableRows(r.file);
@@ -273,13 +282,13 @@ class FileDurableRulePartition {
273
282
  async quarantined() {
274
283
  const r = this.read();
275
284
  if ("unreadable" in r)
276
- throw new Error(r.unreadable);
285
+ throw unreadableError(r);
277
286
  return "file" in r ? this.screenDurableRows(r.file).quarantined : [];
278
287
  }
279
288
  current() {
280
289
  const r = this.read();
281
290
  if ("unreadable" in r) {
282
- throw new Error(`refusing to write the permission-rule store while it cannot be read: ${r.unreadable}`);
291
+ throw unreadableError(r, `refusing to write the permission-rule store while it cannot be read: ${r.unreadable}`);
283
292
  }
284
293
  if ("absent" in r) {
285
294
  return { schemaVersion: 4, actor: `file-${randomBytes(6).toString("hex")}`, counter: 0, rev: 0, rules: [], tombstones: [] };
@@ -296,8 +305,7 @@ class FileDurableRulePartition {
296
305
  };
297
306
  }
298
307
  writeAndVerify(next) {
299
- const expected = checksumOf(next);
300
- this.write(next);
308
+ const expected = this.write(next);
301
309
  const after = this.read();
302
310
  return "file" in after && after.file.checksum === expected;
303
311
  }
@@ -445,17 +453,22 @@ export class FileDurableRulePartitionProvider {
445
453
  this.lock = lock;
446
454
  };
447
455
  forPrincipal(principal) {
448
- if (typeof principal !== "string" || principal === "") {
456
+ const reading = readPrincipal(principal);
457
+ if (reading.kind === "invalid") {
458
+ throw new Error(`the principal given is not a principal name (got ${reading.fault}) — refusing to resolve a bucket for it; a provided value that names nobody is not "no principal"`);
459
+ }
460
+ if (reading.kind === "absent") {
449
461
  return { list: async () => ({ ...EMPTY_READ }), durability: "process-local" };
450
462
  }
463
+ const name = reading.name;
451
464
  const adoption = this.adoptionMarker();
452
465
  if (adoption !== undefined) {
453
466
  const rec = "adopted" in adoption ? adoption.adopted : adoption.marker;
454
- if (rec.from.kind === "principal" && rec.from.principal === principal) {
455
- return this.readOnlySourceView(principalRuleFileName(principal), principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
467
+ if (rec.from.kind === "principal" && rec.from.principal === name) {
468
+ return this.readOnlySourceView(principalRuleFileName(name), principalRuleFileName(rec.toPrincipal), "adopted" in adoption || adoption.marker.phase >= 4);
456
469
  }
457
470
  }
458
- return new FileDurableRulePartition(this.dir, join(this.dir, principalRuleFileName(principal)), this.acquireWriteLock, this.onError, this.vetting);
471
+ return new FileDurableRulePartition(this.dir, join(this.dir, principalRuleFileName(name)), this.acquireWriteLock, this.onError, this.vetting);
459
472
  }
460
473
  readOnlySourceView(sourceName, targetName, flipped) {
461
474
  const pick = flipped ? targetName : existsSync(join(this.dir, sourceName)) ? sourceName : targetName;
@@ -151,9 +151,9 @@ export declare class FileSessionPolicyStore implements SessionPolicyStore {
151
151
  private disclose;
152
152
  /** The ONE refusal for a rules file that is PRESENT but cannot be served as rules — every damage grade lands
153
153
  * here (`unreadable` bytes, `unparseable` JSON, a `malformed` row), so the keyed read and the write that reads
154
- * before it answer with one voice. Session rules only TIGHTEN: a row is the restriction an operator put on the
155
- * session, so reading a damaged one as "no rules" would drop the restriction itself — the wrong direction for a
156
- * store whose every other face refuses a loosening. ABSENCE (ENOENT) is the only "no rules"; it never reaches
154
+ * before it answer with one voice. Session rules only TIGHTEN: a row is a restriction on the session's calls, so
155
+ * reading a damaged one as "no rules" would drop the restriction itself — a loosening no write made, which the
156
+ * write judge would refuse below the row's operator part. ABSENCE (ENOENT) is the only "no rules"; it never reaches
157
157
  * here. The disclosure sink fires with the refusal (swallow-guarded: a throwing sink cannot turn it back into an
158
158
  * answer) and is the ONLY carrier of the file's path: the thrown message reaches end users through a host's error
159
159
  * body, so it names no on-disk location. Two ways out, both the operator's: fix the file, or delete it — deleting is an explicit "no rules" and
@@ -1,4 +1,4 @@
1
- import type { Session, SessionCreateOptions, SessionForkOptions, SessionMetadata, SessionPlacementRecord, SessionRepo, SessionTreeEntry } from "../../internal/harness.js";
1
+ import type { Session, SessionCreateOptions, SessionForkOptions, SessionHead, SessionMetadata, SessionPlacementRecord, SessionRepo, SessionRow, SessionTreeEntry } from "../../internal/harness.js";
2
2
  import type { PlacedSessionRow } from "../../core/session.js";
3
3
  import { type CorruptReadInfo } from "./corrupt-read-sink.js";
4
4
  export interface FileSessionRepoOptions {
@@ -8,8 +8,9 @@ export interface FileSessionRepoOptions {
8
8
  * "corrupt read as missing" are one failure grammar, so they get one seat name.
9
9
  *
10
10
  * Fires for: an unreadable sessions DIRECTORY (the listing degrades to "no sessions"), a session log
11
- * that could not be replayed during a listing (skipped from the result), and each corrupt interior JSONL
12
- * record dropped on replay plus that replay's tally (turns missing from an otherwise healthy session).
11
+ * whose header could not be read during a listing (skipped from the result — a listing reads headers,
12
+ * it never replays a log), and each corrupt interior JSONL record dropped on replay plus that replay's
13
+ * tally (turns missing from an otherwise healthy session).
13
14
  *
14
15
  * Never fires on plain ENOENT / `not_found` — that is honest absence, and the torn TAIL stays silent
15
16
  * too (dying mid-write is the append log's documented crash-recovery shape, not corruption).
@@ -37,12 +38,37 @@ export declare class FileSessionRepo implements SessionRepo {
37
38
  private pathFor;
38
39
  /**
39
40
  * Read + torn-tail-recover a session file into (meta, entries). Three answers: no file → `not_found`; a
40
- * file with no meta header → `corrupt_session`, even when every other record is intact (every write path
41
- * here lays the header down first and the header alone carries `createdAt` / fork / placement, so the file
42
- * is not a session this store wrote, or its header line is damaged); otherwise the session, each skipped
43
- * record disclosed.
41
+ * file whose first record is not a meta header → `corrupt_session`, even when every other record is intact
42
+ * (every write path here lays the header down first and the header alone carries `createdAt` / fork /
43
+ * placement / owner, so the file is not a session this store wrote, or its header line is damaged);
44
+ * otherwise the session, each skipped record disclosed.
44
45
  */
45
46
  private read;
47
+ /**
48
+ * The row's cells from its FIRST record — the one header every write path lays down before any entry; a later meta record is
49
+ * never read as the header. Each occupant cell goes through the one incarnation decoding (an unknown occupant, said here when the
50
+ * cell is there but names nobody) and the owner cell through its decoding (a cell that is neither an owner nor anonymous refuses
51
+ * the row). `skipped` words the corrupt-header refusal's reading of the records around it, where the caller has one.
52
+ */
53
+ private headerOf;
54
+ /**
55
+ * The row's head in one read, without replaying the log: ONE descriptor on the session file, its first record for the owner and
56
+ * occupant cells, and walking back from its end to the last entry record for the leaf. The three come from one inode — a file
57
+ * replaced (fork / import) or removed (delete) while this reads is still the inode this descriptor opened — so they answer for one
58
+ * row generation. The leaf is what a replay computes (the leaf after the last entry the whole-file read keeps, judged by the same
59
+ * per-line rule, a torn tail dropped alike): the log is the only carrier, so no state exists in which the log holds an entry the
60
+ * head does not see. A leaf entry naming an id the log does not hold is not checked here (a replay refuses that log on open).
61
+ */
62
+ headOf(sessionId: string): Promise<SessionHead | undefined>;
63
+ /**
64
+ * The row's {@link SessionRow} — its header cells and the newest write it holds, the log's modification time (every write to a row
65
+ * is an append to its log; the placed listing's age reads the same time) — in one read of the header, never a replay of the log.
66
+ * `undefined` = no row; a row whose header cannot be read rejects (`corrupt_session`).
67
+ */
68
+ private rowOf;
69
+ /** The one descriptor a by-id read of the row takes: its size and modification time and its header, from one inode (a file replaced
70
+ * or removed while this reads is still the inode this descriptor opened); `undefined` = no file. */
71
+ private atRow;
46
72
  private storage;
47
73
  /**
48
74
  * RB-437 — release every shared authority this repo joined (LAST holder ⇒ evict + close the append fd).
@@ -59,12 +85,25 @@ export declare class FileSessionRepo implements SessionRepo {
59
85
  dispose(): Promise<void>;
60
86
  create(options?: SessionCreateOptions): Promise<Session>;
61
87
  open(metadata: SessionMetadata): Promise<Session>;
62
- list(): Promise<SessionMetadata[]>;
88
+ /** Record activity on the row now: its log's modification time — the one time a listing reads, which every append moves too — is
89
+ * set to now, the log's bytes untouched. A missing file is nothing to record; any other fault rejects. */
90
+ touch(sessionId: string): Promise<void>;
91
+ /** Every ordinary row with the newest write its log holds ({@link rowOf}): one header read per session file, no replay — what a
92
+ * listing costs grows with the number of sessions, never with their history. Placed rows are the placed listing's. */
93
+ list(): Promise<SessionRow[]>;
94
+ /**
95
+ * Every row of the sessions directory, each read by {@link rowOf}. The listing degrades to "no sessions" so a
96
+ * browse face never throws — but "I could not read the directory" and "there are none" are different facts, and only the sink can
97
+ * tell them apart (ENOENT is honest absence: the constructor creates the directory, so it was removed underneath us). A session
98
+ * whose header cannot be read is skipped and disclosed — it exists and is missing from the listing — while a file that vanished
99
+ * between the directory read and its own is honest absence.
100
+ */
101
+ private rows;
63
102
  /**
64
103
  * Subagent transcript persistence — the PLACED partition's own enumeration (the joint reap's
65
104
  * partition-leg input; `TtlSessionStore` re-exposes it verbatim). Age (`olderThanMs`) is judged on
66
- * the session FILE's mtime — the transcript's last append — falling back to `placedAt` when the
67
- * stat fails (mtime is also the CC orphan-adoption window's basis, so the two age reads agree).
105
+ * the session FILE's mtime — the transcript's last append, the time the host listing reads too
106
+ * (mtime is also the CC orphan-adoption window's basis, so the age reads agree).
68
107
  * Rows missing either `(scope, handle)` join half return the honest `tupleIncomplete` variant
69
108
  * (consumers fail closed on it — never age-reaped, see the SessionStore contract).
70
109
  */
@@ -73,21 +112,20 @@ export declare class FileSessionRepo implements SessionRepo {
73
112
  scope?: string;
74
113
  }): Promise<PlacedSessionRow[]>;
75
114
  /** The row as it stands before a file-replacing write: `undefined` ⇔ there is no row (no file); a row
76
- * whose header cannot be read answers an empty header (it exists, its cells are unknown). */
115
+ * whose header cannot be read rejects (it exists, and nobody can name its cells). */
77
116
  private priorHeader;
78
117
  /** Cheap placement probe for one id (the TtlSessionStore's cold-cache release consults it so the
79
- * placed real-deletion obligation holds after a restart). `undefined` = missing file OR unplaced. */
118
+ * placed real-deletion obligation holds after a restart). `undefined` = missing file OR unplaced; a row that cannot be read rejects. */
80
119
  placementOf(sessionId: string): Promise<SessionPlacementRecord | undefined>;
81
120
  delete(metadata: SessionMetadata): Promise<void>;
82
- fork(sourceMetadata: SessionMetadata, options?: SessionForkOptions): Promise<Session>;
121
+ fork(sourceMetadata: SessionMetadata, options?: SessionForkOptions & SessionCreateOptions): Promise<Session>;
83
122
  /** 2c session-sync (the FILE half): the FULL oldest-first log for export. The file backend
84
123
  * has NO F3 floor — `read` returns EVERY persisted entry (`id`/`parentId` verbatim) — so this is the complete
85
124
  * log, BYPASSing any bounded tail (matches `InMemorySessionRepo.exportEntries`). Missing file → not_found. */
86
125
  exportEntries(sessionId: string): Promise<SessionTreeEntry[]>;
87
126
  /** 2c session-sync: import a verbatim log into `sessionId`. The single fail-closed invariant gate runs
88
- * FIRST ({@link validateEntriesForImport}); `owner` is a durable multi-tenant concept the local file backend
89
- * has no field for (accepted, unused — same as `InMemorySessionRepo`). Writes the WHOLE file (meta + entries)
90
- * atomically via tmp→fsync→rename — the rename is the commit point, so a crash leaves either nothing or an
127
+ * FIRST ({@link validateEntriesForImport}); a new row's header records `owner`, an existing row's is laid down again whole. Writes the WHOLE file
128
+ * (meta + entries) atomically via tmp→fsync→rename — the rename is the commit point, so a crash leaves either nothing or an
91
129
  * orphan temp, never a partially-imported session (mirrors `fork`). An existing session is REPLACED (the
92
130
  * orchestrator's importSession owns the already-exists policy, same as InMemory's overwrite). */
93
131
  importEntries(sessionId: string, owner: string | undefined, entries: SessionTreeEntry[], options?: {