@sema-agent/core 7.55.0 → 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 (418) hide show
  1. package/CHANGELOG.md +513 -0
  2. package/dist/agents/cascade.js +1 -1
  3. package/dist/agents/cc-peer-directory.js +1 -0
  4. package/dist/agents/child-model-seat.d.ts +0 -11
  5. package/dist/agents/child-model-seat.js +0 -3
  6. package/dist/agents/list-agents-tool.d.ts +3 -1
  7. package/dist/agents/list-agents-tool.js +7 -7
  8. package/dist/agents/peer-directory.d.ts +22 -4
  9. package/dist/agents/peer-directory.js +24 -2
  10. package/dist/agents/peer-session-drain.js +2 -2
  11. package/dist/agents/repair-loop.js +2 -2
  12. package/dist/agents/send-message-tool.js +4 -4
  13. package/dist/agents/subagent.d.ts +6 -4
  14. package/dist/agents/subagent.js +64 -60
  15. package/dist/agents/tool-filter.d.ts +7 -5
  16. package/dist/agents/tool-filter.js +12 -9
  17. package/dist/agents/verify.d.ts +3 -2
  18. package/dist/agents/verify.js +3 -3
  19. package/dist/brain/anthropic.js +30 -73
  20. package/dist/brain/media-degrade.d.ts +18 -7
  21. package/dist/brain/media-degrade.js +13 -2
  22. package/dist/brain/model-capability.d.ts +37 -0
  23. package/dist/brain/model-capability.js +34 -0
  24. package/dist/brain/model-presets.d.ts +2 -8
  25. package/dist/brain/model-presets.js +1 -6
  26. package/dist/brain/open-responses.js +13 -26
  27. package/dist/brain/openai.js +14 -87
  28. package/dist/brain/reasoning-request.d.ts +96 -0
  29. package/dist/brain/reasoning-request.js +174 -0
  30. package/dist/brain/reasoning.d.ts +11 -11
  31. package/dist/brain/reasoning.js +4 -3
  32. package/dist/brain/request-params.d.ts +7 -4
  33. package/dist/brain/request-params.js +7 -4
  34. package/dist/brain/status-sink.d.ts +20 -0
  35. package/dist/brain/status-sink.js +7 -0
  36. package/dist/core/a2a.d.ts +2 -1
  37. package/dist/core/a2a.js +19 -13
  38. package/dist/core/agent-definition.d.ts +10 -0
  39. package/dist/core/allow-entry.d.ts +20 -13
  40. package/dist/core/allow-entry.js +26 -22
  41. package/dist/core/allow-rule-shadow.d.ts +3 -3
  42. package/dist/core/ask-origin.d.ts +64 -18
  43. package/dist/core/ask-origin.js +63 -23
  44. package/dist/core/ask-question.d.ts +51 -8
  45. package/dist/core/ask-question.js +3 -4
  46. package/dist/core/ask-unresolvable-notice.d.ts +8 -3
  47. package/dist/core/ask-unresolvable-notice.js +16 -2
  48. package/dist/core/checkpoint-generation.d.ts +53 -0
  49. package/dist/core/checkpoint-generation.js +35 -0
  50. package/dist/core/checkpoint-queries.d.ts +180 -0
  51. package/dist/core/checkpoint-queries.js +272 -0
  52. package/dist/core/checkpoint-requirements.d.ts +13 -1
  53. package/dist/core/checkpoint-requirements.js +4 -0
  54. package/dist/core/checkpoint-store.d.ts +88 -24
  55. package/dist/core/checkpoint-store.js +24 -9
  56. package/dist/core/cross-boundary-taint.d.ts +6 -5
  57. package/dist/core/cross-boundary-taint.js +1 -3
  58. package/dist/core/decision-receipt.d.ts +37 -3
  59. package/dist/core/decision-receipt.js +17 -17
  60. package/dist/core/delegation-not-started.d.ts +6 -0
  61. package/dist/core/delegation-not-started.js +17 -0
  62. package/dist/core/engine-attestation.d.ts +93 -0
  63. package/dist/core/engine-attestation.js +70 -0
  64. package/dist/core/engine-capabilities.d.ts +4 -1
  65. package/dist/core/engine-capabilities.js +1 -1
  66. package/dist/core/engine-notice.d.ts +30 -11
  67. package/dist/core/file-history-store.d.ts +90 -14
  68. package/dist/core/file-history-store.js +23 -15
  69. package/dist/core/gate-fold.d.ts +1 -1
  70. package/dist/core/gate-fold.js +22 -10
  71. package/dist/core/gate-lanes.js +73 -64
  72. package/dist/core/gate-outcome.d.ts +26 -5
  73. package/dist/core/gate-outcome.js +26 -0
  74. package/dist/core/governance-codes.d.ts +5 -1
  75. package/dist/core/governance-codes.js +6 -0
  76. package/dist/core/hooks.d.ts +17 -16
  77. package/dist/core/hooks.js +3 -1
  78. package/dist/core/host-floor.d.ts +128 -0
  79. package/dist/core/host-floor.js +206 -0
  80. package/dist/core/host-target.d.ts +38 -3
  81. package/dist/core/host-target.js +38 -5
  82. package/dist/core/mcp.d.ts +5 -1
  83. package/dist/core/mcp.js +67 -41
  84. package/dist/core/memory-engine/delegation-settlement.js +15 -24
  85. package/dist/core/memory-engine/engine.js +4 -4
  86. package/dist/core/memory-engine/layout.d.ts +60 -8
  87. package/dist/core/memory-engine/layout.js +65 -6
  88. package/dist/core/model-seat.d.ts +10 -3
  89. package/dist/core/mods/classic-events.d.ts +67 -0
  90. package/dist/core/mods/classic-events.js +1 -0
  91. package/dist/core/mods/dollar.d.ts +13 -0
  92. package/dist/core/mods/extension-call.d.ts +31 -0
  93. package/dist/core/mods/extension-call.js +43 -0
  94. package/dist/core/mods/kernel/dispatch.d.ts +20 -3
  95. package/dist/core/mods/kernel/dispatch.js +140 -69
  96. package/dist/core/mods/kernel/events.d.ts +47 -11
  97. package/dist/core/mods/kernel/events.js +66 -42
  98. package/dist/core/mods/kernel/index.d.ts +4 -4
  99. package/dist/core/mods/kernel/index.js +2 -2
  100. package/dist/core/mods/kernel/receive.d.ts +39 -5
  101. package/dist/core/mods/kernel/receive.js +290 -17
  102. package/dist/core/mods/kernel/registration.d.ts +33 -2
  103. package/dist/core/mods/kernel/registration.js +6 -7
  104. package/dist/core/mods/kernel/site-rules.d.ts +44 -16
  105. package/dist/core/mods/kernel/site-rules.js +24 -42
  106. package/dist/core/mods/spec-seats.d.ts +69 -0
  107. package/dist/core/mods/spec-seats.js +114 -0
  108. package/dist/core/mods/stations.d.ts +28 -8
  109. package/dist/core/mods/stations.js +29 -13
  110. package/dist/core/mods/tool-call.d.ts +79 -0
  111. package/dist/core/mods/tool-call.js +152 -0
  112. package/dist/core/namespaced-rule-name.d.ts +32 -38
  113. package/dist/core/namespaced-rule-name.js +29 -36
  114. package/dist/core/parent-spec-seat.d.ts +6 -1
  115. package/dist/core/parent-spec-seat.js +2 -0
  116. package/dist/core/park-selfcheck.js +1 -0
  117. package/dist/core/permission-rule-consent.d.ts +19 -0
  118. package/dist/core/permission-rule-consent.js +116 -26
  119. package/dist/core/permission-rule-model.d.ts +14 -3
  120. package/dist/core/permission-rule-model.js +39 -24
  121. package/dist/core/permission-rule-org.d.ts +6 -2
  122. package/dist/core/permission-rule-org.js +7 -3
  123. package/dist/core/permission-rule-provider.d.ts +5 -2
  124. package/dist/core/permission-rule-provider.js +41 -11
  125. package/dist/core/permission-rule-store.d.ts +3 -2
  126. package/dist/core/permission-rule-store.js +11 -2
  127. package/dist/core/permission-rule-sync.js +3 -2
  128. package/dist/core/permission-rule-syntax.d.ts +5 -4
  129. package/dist/core/permission-rule-syntax.js +2 -2
  130. package/dist/core/permission-rules.d.ts +4 -4
  131. package/dist/core/permission-rules.js +11 -20
  132. package/dist/core/persisted-rule-arms.d.ts +2 -2
  133. package/dist/core/persisted-rule-arms.js +10 -12
  134. package/dist/core/principal-name.d.ts +20 -0
  135. package/dist/core/principal-name.js +22 -0
  136. package/dist/core/prompt-section-seat.js +4 -6
  137. package/dist/core/protocol-http-auth.d.ts +26 -5
  138. package/dist/core/protocol-http-auth.js +137 -4
  139. package/dist/core/retired-keys.d.ts +16 -0
  140. package/dist/core/retired-keys.js +16 -4
  141. package/dist/core/rewrite-rejudge.d.ts +60 -0
  142. package/dist/core/rewrite-rejudge.js +36 -0
  143. package/dist/core/roles.d.ts +28 -1
  144. package/dist/core/roles.js +31 -19
  145. package/dist/core/rule-lane-reads.d.ts +20 -15
  146. package/dist/core/rule-lane-reads.js +45 -17
  147. package/dist/core/rule-owner.d.ts +3 -3
  148. package/dist/core/rule-owner.js +3 -2
  149. package/dist/core/runner/announce-once-ledger.d.ts +14 -0
  150. package/dist/core/runner/announce-once-ledger.js +5 -0
  151. package/dist/core/runner/assemble-result.d.ts +1 -0
  152. package/dist/core/runner/assemble-result.js +1 -1
  153. package/dist/core/runner/call-hook-stations.d.ts +3 -2
  154. package/dist/core/runner/caller-roster.d.ts +16 -4
  155. package/dist/core/runner/caller-roster.js +33 -6
  156. package/dist/core/runner/capability-withheld-seat.d.ts +5 -0
  157. package/dist/core/runner/capability-withheld-seat.js +24 -0
  158. package/dist/core/runner/classifier-ladder.d.ts +7 -9
  159. package/dist/core/runner/classifier-ladder.js +3 -3
  160. package/dist/core/runner/construction-doors.js +3 -0
  161. package/dist/core/runner/contracts.d.ts +28 -25
  162. package/dist/core/runner/cross-boundary-lane.d.ts +17 -13
  163. package/dist/core/runner/cross-boundary-lane.js +40 -27
  164. package/dist/core/runner/denial-limit-arms.d.ts +2 -2
  165. package/dist/core/runner/denial-limit-arms.js +1 -1
  166. package/dist/core/runner/file-history-request.d.ts +18 -0
  167. package/dist/core/runner/file-history-request.js +21 -13
  168. package/dist/core/runner/file-history-restore.d.ts +45 -0
  169. package/dist/core/runner/file-history-restore.js +46 -0
  170. package/dist/core/runner/gate-exit.d.ts +3 -3
  171. package/dist/core/runner/gate-exit.js +4 -3
  172. package/dist/core/runner/image.d.ts +7 -17
  173. package/dist/core/runner/image.js +9 -60
  174. package/dist/core/runner/permission-rule-lanes.d.ts +4 -4
  175. package/dist/core/runner/permission-rule-lanes.js +26 -10
  176. package/dist/core/runner/person-path-rows.d.ts +12 -9
  177. package/dist/core/runner/person-path-rows.js +18 -7
  178. package/dist/core/runner/prepare-ask-lane.d.ts +2 -2
  179. package/dist/core/runner/prepare-ask-lane.js +5 -2
  180. package/dist/core/runner/prepare-caps-and-workflow.d.ts +4 -6
  181. package/dist/core/runner/prepare-caps-and-workflow.js +4 -3
  182. package/dist/core/runner/prepare-config-doors.d.ts +29 -38
  183. package/dist/core/runner/prepare-config-doors.js +42 -25
  184. package/dist/core/runner/prepare-defer-classify.d.ts +4 -3
  185. package/dist/core/runner/prepare-defer-classify.js +7 -8
  186. package/dist/core/runner/prepare-file-history.d.ts +48 -8
  187. package/dist/core/runner/prepare-file-history.js +7 -39
  188. package/dist/core/runner/prepare-gate-stations.d.ts +1 -1
  189. package/dist/core/runner/prepare-gate-stations.js +10 -1
  190. package/dist/core/runner/prepare-hands-readface.d.ts +2 -8
  191. package/dist/core/runner/prepare-hands-readface.js +15 -14
  192. package/dist/core/runner/prepare-inherited-gate.d.ts +6 -3
  193. package/dist/core/runner/prepare-inherited-gate.js +5 -3
  194. package/dist/core/runner/prepare-memory-engine-session.js +1 -1
  195. package/dist/core/runner/prepare-park-ask.js +5 -5
  196. package/dist/core/runner/prepare-policy-chain.d.ts +6 -3
  197. package/dist/core/runner/prepare-policy-chain.js +65 -72
  198. package/dist/core/runner/prepare-prompt-assembly.d.ts +5 -7
  199. package/dist/core/runner/prepare-prompt-assembly.js +10 -8
  200. package/dist/core/runner/prepare-prompt-inputs.d.ts +11 -9
  201. package/dist/core/runner/prepare-prompt-inputs.js +3 -5
  202. package/dist/core/runner/prepare-protocol-tools.d.ts +2 -0
  203. package/dist/core/runner/prepare-protocol-tools.js +3 -3
  204. package/dist/core/runner/prepare-safety-scan.d.ts +1 -1
  205. package/dist/core/runner/prepare-safety-scan.js +0 -17
  206. package/dist/core/runner/prepare-suspend-saga.d.ts +2 -0
  207. package/dist/core/runner/prepare-suspend-saga.js +5 -6
  208. package/dist/core/runner/prepare-task.d.ts +1 -1
  209. package/dist/core/runner/prepare-task.js +29 -20
  210. package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +7 -4
  211. package/dist/core/runner/prepare-tool-disclosure-mount.js +20 -16
  212. package/dist/core/runner/prepare-turn-wiring.d.ts +0 -4
  213. package/dist/core/runner/prepare-turn-wiring.js +2 -7
  214. package/dist/core/runner/prepare-wiring-manifest.d.ts +6 -2
  215. package/dist/core/runner/prepare-wiring-manifest.js +3 -3
  216. package/dist/core/runner/resume-admission.js +1 -1
  217. package/dist/core/runner/resume-apply.js +11 -12
  218. package/dist/core/runner/resume-checkpoint-screen.js +3 -0
  219. package/dist/core/runner/resume-claim.d.ts +4 -2
  220. package/dist/core/runner/resume-claim.js +15 -8
  221. package/dist/core/runner/retired-runner-deps.js +1 -0
  222. package/dist/core/runner/rewind-files.d.ts +15 -0
  223. package/dist/core/runner/rewind-files.js +132 -0
  224. package/dist/core/runner/run-attachment-seats.js +2 -1
  225. package/dist/core/runner/run-brain-sinks.d.ts +4 -1
  226. package/dist/core/runner/run-brain-sinks.js +4 -2
  227. package/dist/core/runner/run-harness-handlers.js +12 -4
  228. package/dist/core/runner/run-leg.d.ts +1 -1
  229. package/dist/core/runner/run-leg.js +30 -18
  230. package/dist/core/runner/run-settle-and-teardown.js +2 -1
  231. package/dist/core/runner/run-turn-boundary.js +1 -10
  232. package/dist/core/runner/runtask.d.ts +3 -0
  233. package/dist/core/runner/runtask.js +8 -9
  234. package/dist/core/runner/session-read-file-states.d.ts +15 -0
  235. package/dist/core/runner/session-read-file-states.js +28 -0
  236. package/dist/core/runner/session-rule-policy.js +4 -3
  237. package/dist/core/runner/shell-env-withheld.d.ts +33 -0
  238. package/dist/core/runner/shell-env-withheld.js +51 -0
  239. package/dist/core/runner/skills-seat.js +6 -2
  240. package/dist/core/runner/stream-settle-backstop.js +1 -1
  241. package/dist/core/runner/sub-agent-deny-lists.js +4 -7
  242. package/dist/core/runner/synthetic-tools.d.ts +6 -0
  243. package/dist/core/runner/synthetic-tools.js +4 -1
  244. package/dist/core/runner/tool-disclosure.d.ts +10 -12
  245. package/dist/core/runner/tool-disclosure.js +1 -3
  246. package/dist/core/runner/tool-end-body.d.ts +1 -1
  247. package/dist/core/runner/tool-end-body.js +10 -9
  248. package/dist/core/runner/tool-not-executed.d.ts +5 -0
  249. package/dist/core/runner/tool-not-executed.js +11 -0
  250. package/dist/core/runner/tool-occurrence.d.ts +8 -0
  251. package/dist/core/runner/tool-occurrence.js +7 -0
  252. package/dist/core/runner/turn-attachments.d.ts +33 -15
  253. package/dist/core/runner/turn-attachments.js +62 -37
  254. package/dist/core/runner-deps.d.ts +5 -5
  255. package/dist/core/safety-axis-vocab.d.ts +6 -4
  256. package/dist/core/safety-axis-vocab.js +6 -5
  257. package/dist/core/safety-merge-corpus.js +11 -3
  258. package/dist/core/secret-env.d.ts +26 -3
  259. package/dist/core/secret-env.js +44 -8
  260. package/dist/core/select-model.js +3 -3
  261. package/dist/core/session-policy-store.d.ts +27 -15
  262. package/dist/core/session-policy-store.js +156 -36
  263. package/dist/core/session-store.d.ts +29 -10
  264. package/dist/core/session-store.js +51 -19
  265. package/dist/core/session.d.ts +82 -16
  266. package/dist/core/session.js +53 -0
  267. package/dist/core/shell-read-silence.d.ts +11 -12
  268. package/dist/core/shell-read-silence.js +9 -5
  269. package/dist/core/shell-run-candidates.js +3 -1
  270. package/dist/core/shell-wrapper-projection.js +1 -1
  271. package/dist/core/shell-wrapper-table.d.ts +14 -7
  272. package/dist/core/shell-wrapper-table.js +5 -4
  273. package/dist/core/side-query.js +10 -1
  274. package/dist/core/skill-grant.d.ts +7 -2
  275. package/dist/core/skill-grant.js +5 -0
  276. package/dist/core/skills-directory.js +6 -2
  277. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +11 -1
  278. package/dist/core/store-contracts/checkpoint-store-contract.js +140 -2
  279. package/dist/core/store-contracts/file-history-store-contract.js +31 -1
  280. package/dist/core/store-contracts/peer-directory-contract.d.ts +7 -2
  281. package/dist/core/store-contracts/peer-directory-contract.js +14 -2
  282. package/dist/core/store-contracts/session-repo-contract.js +51 -0
  283. package/dist/core/store-contracts/session-store-contract.d.ts +2 -1
  284. package/dist/core/store-contracts/session-store-contract.js +150 -14
  285. package/dist/core/stub-env.d.ts +2 -0
  286. package/dist/core/stub-env.js +1 -0
  287. package/dist/core/synthetic-read-verdict.js +3 -3
  288. package/dist/core/task-event.d.ts +32 -4
  289. package/dist/core/task-notification.d.ts +16 -12
  290. package/dist/core/task-registry.d.ts +9 -0
  291. package/dist/core/task-registry.js +11 -1
  292. package/dist/core/task-result.d.ts +18 -0
  293. package/dist/core/task-spec.d.ts +18 -13
  294. package/dist/core/tighten-task-spec.js +2 -1
  295. package/dist/core/tool-catalog-entries.d.ts +17 -0
  296. package/dist/core/tool-catalog-entries.js +13 -2
  297. package/dist/core/tool-check-reading.d.ts +11 -0
  298. package/dist/core/tool-check-reading.js +11 -6
  299. package/dist/core/tool-model-gate.d.ts +2 -2
  300. package/dist/core/tool-name-aliases.d.ts +16 -16
  301. package/dist/core/tool-name-aliases.js +13 -19
  302. package/dist/core/tool-name-readings.d.ts +5 -35
  303. package/dist/core/tool-name-readings.js +1 -9
  304. package/dist/core/tool-policy.d.ts +68 -198
  305. package/dist/core/tool-policy.js +149 -198
  306. package/dist/core/tool-result-store.js +3 -0
  307. package/dist/core/tool-roster.d.ts +14 -19
  308. package/dist/core/tool-roster.js +11 -44
  309. package/dist/core/tool-spec-members.js +7 -2
  310. package/dist/core/tool-spec.d.ts +19 -11
  311. package/dist/core/tools.js +49 -9
  312. package/dist/core/trace.d.ts +2 -2
  313. package/dist/core/types.d.ts +1 -1
  314. package/dist/core/user-attachment.d.ts +8 -1
  315. package/dist/core/user-attachment.js +64 -4
  316. package/dist/core/wiring-manifest.d.ts +9 -0
  317. package/dist/core/wiring-manifest.js +1 -0
  318. package/dist/core/workflow-journal-store.js +1 -1
  319. package/dist/engine/compaction/compaction.js +3 -2
  320. package/dist/engine/execution-env/node-execution-env.d.ts +7 -3
  321. package/dist/engine/execution-env/node-execution-env.js +11 -2
  322. package/dist/engine/harness/agent-harness.d.ts +25 -1
  323. package/dist/engine/harness/agent-harness.js +54 -7
  324. package/dist/engine/harness/types.d.ts +29 -2
  325. package/dist/engine/llm/types.d.ts +28 -11
  326. package/dist/engine/loop/agent-loop.d.ts +22 -0
  327. package/dist/engine/loop/agent-loop.js +16 -26
  328. package/dist/engine/loop/types.d.ts +16 -6
  329. package/dist/engine/session/memory-repo.d.ts +9 -2
  330. package/dist/engine/session/memory-repo.js +11 -1
  331. package/dist/engine/session/repo-utils.d.ts +6 -5
  332. package/dist/engine/session/repo-utils.js +14 -6
  333. package/dist/index.d.ts +22 -10
  334. package/dist/index.js +15 -7
  335. package/dist/internal/harness-types.d.ts +1 -1
  336. package/dist/internal/llm.d.ts +1 -1
  337. package/dist/orchestration/run-workflow-tool.d.ts +6 -4
  338. package/dist/orchestration/run-workflow-tool.js +5 -3
  339. package/dist/orchestration/workflow.d.ts +3 -0
  340. package/dist/orchestration/workflow.js +36 -18
  341. package/dist/prompt-assembly/artifact.d.ts +2 -2
  342. package/dist/prompt-assembly/artifact.js +5 -3
  343. package/dist/prompt-assembly/assemble.d.ts +3 -2
  344. package/dist/prompt-assembly/assemble.js +1 -1
  345. package/dist/prompt-assembly/catalog/schema.d.ts +43 -12
  346. package/dist/prompt-assembly/catalog/schema.js +34 -2
  347. package/dist/prompt-assembly/catalog/sections.js +0 -1
  348. package/dist/prompt-assembly/composer.d.ts +3 -1
  349. package/dist/prompt-assembly/composer.js +1 -1
  350. package/dist/prompt-assembly/event-registry.js +1 -0
  351. package/dist/prompt-assembly/overlay.js +3 -3
  352. package/dist/prompt-assembly/renderers.d.ts +1 -1
  353. package/dist/prompt-assembly/renderers.js +0 -3
  354. package/dist/prompt-assembly/role-base.d.ts +15 -0
  355. package/dist/prompt-assembly/role-base.js +9 -0
  356. package/dist/prompt-assembly/select.d.ts +39 -14
  357. package/dist/prompt-assembly/select.js +47 -16
  358. package/dist/prompt-assembly/sugar.d.ts +17 -11
  359. package/dist/prompt-assembly/sugar.js +8 -3
  360. package/dist/prompt-assembly/tool-catalog.d.ts +37 -3
  361. package/dist/prompt-assembly/tool-catalog.js +114 -4
  362. package/dist/prompt-assembly/turn-snapshot.d.ts +4 -10
  363. package/dist/prompt-assembly/turn-snapshot.js +0 -3
  364. package/dist/prompt-assembly/types.d.ts +0 -7
  365. package/dist/scenarios/full-body.d.ts +11 -11
  366. package/dist/scenarios/full-body.js +4 -3
  367. package/dist/shell/lex.js +10 -1
  368. package/dist/stores/file/adoption/adopt.js +4 -3
  369. package/dist/stores/file/adoption/marker.js +3 -2
  370. package/dist/stores/file/checkpoint-store.d.ts +21 -0
  371. package/dist/stores/file/checkpoint-store.js +38 -6
  372. package/dist/stores/file/file-history-store.js +6 -7
  373. package/dist/stores/file/index.js +2 -1
  374. package/dist/stores/file/permission-rule-adopt.js +4 -3
  375. package/dist/stores/file/permission-rule-store.js +11 -5
  376. package/dist/stores/file/session-store.d.ts +29 -6
  377. package/dist/stores/file/session-store.js +42 -50
  378. package/dist/tools/artifact/artifact-tool.js +3 -2
  379. package/dist/tools/fs/bash-program-position.d.ts +19 -2
  380. package/dist/tools/fs/bash-program-position.js +56 -9
  381. package/dist/tools/fs/fs-bash.js +5 -5
  382. package/dist/tools/fs/fs-glob.d.ts +86 -0
  383. package/dist/tools/fs/fs-glob.js +226 -0
  384. package/dist/tools/fs/fs-read.js +14 -14
  385. package/dist/tools/fs/fs-search-tools.js +7 -7
  386. package/dist/tools/fs/pattern-kill-guard.d.ts +22 -0
  387. package/dist/tools/fs/pattern-kill-guard.js +397 -0
  388. package/dist/tools/fs/pdf.d.ts +9 -6
  389. package/dist/tools/fs/pdf.js +3 -3
  390. package/dist/tools/fs/program-read-model.d.ts +57 -7
  391. package/dist/tools/fs/program-read-model.js +11 -1
  392. package/dist/tools/fs/program-read-model.rows.js +78 -21
  393. package/dist/tools/fs/read-deny-home.js +3 -2
  394. package/dist/tools/fs/removal-targets.d.ts +17 -7
  395. package/dist/tools/fs/removal-targets.js +47 -20
  396. package/dist/tools/fs/search.d.ts +10 -0
  397. package/dist/tools/fs/search.js +20 -26
  398. package/dist/tools/fs/shell-read-argv.js +89 -12
  399. package/dist/tools/fs/shell-read-bindings.d.ts +31 -0
  400. package/dist/tools/fs/shell-read-bindings.js +41 -0
  401. package/dist/tools/fs/shell-read-check.js +6 -19
  402. package/dist/tools/fs/shell-read-environment.d.ts +5 -1
  403. package/dist/tools/fs/shell-read-environment.js +3 -2
  404. package/dist/tools/fs/shell-read-establish.d.ts +15 -0
  405. package/dist/tools/fs/shell-read-establish.js +19 -20
  406. package/dist/tools/fs/shell-read-plan.js +24 -16
  407. package/dist/tools/fs/shell-read-start.d.ts +6 -1
  408. package/dist/tools/fs/shell-read-write-targets.d.ts +5 -1
  409. package/dist/tools/fs/shell-read-write-targets.js +2 -3
  410. package/dist/tools/fs/shell-reentry-text.d.ts +9 -0
  411. package/dist/tools/fs/shell-reentry-text.js +40 -2
  412. package/dist/tools/todo.js +63 -63
  413. package/dist/tools/web.d.ts +19 -14
  414. package/dist/tools/web.js +38 -55
  415. package/package.json +1 -1
  416. package/test/export-surface.snapshot.json +143 -5
  417. package/wire-changes/core@7.56.0.json +3891 -0
  418. package/wire-changes/mods-kernel@7.56.0.json +303 -0
@@ -2,7 +2,7 @@ import { webFetchToolSpec, createWebSearchTool } from "../tools/web.js";
2
2
  import { createTodoWriteTool } from "../tools/todo.js";
3
3
  import { createTaskListTools } from "../tools/task-list.js";
4
4
  import { createSubagentTool } from "../agents/subagent.js";
5
- import { CODE_SYSTEM_PROMPT } from "../prompts/default.js";
5
+ import { namesRoleBase } from "../prompt-assembly/role-base.js";
6
6
  export function assembleCodeTools(cfg = {}) {
7
7
  const web = [webFetchToolSpec(cfg.webFetch ?? {})];
8
8
  if (cfg.webSearch)
@@ -19,13 +19,14 @@ export function assembleCodeTools(cfg = {}) {
19
19
  }
20
20
  const tools = [...web];
21
21
  if (cfg.subagent) {
22
+ const roleBase = namesRoleBase(cfg.subagent) ? {} : { promptRole: "code" };
22
23
  tools.push(createSubagentTool({
23
24
  ...cfg.subagent,
24
- systemPrompt: cfg.subagent.systemPrompt ?? CODE_SYSTEM_PROMPT,
25
+ ...roleBase,
25
26
  inheritedTools: cfg.subagent.inheritedTools ?? [...web, ...scaffolds],
26
27
  }));
27
28
  }
28
29
  tools.push(...scaffolds);
29
30
  return tools;
30
31
  }
31
- export const CODE_ROLE = { systemPrompt: CODE_SYSTEM_PROMPT, thinking: "high" };
32
+ export const CODE_ROLE = { promptRole: "code", thinking: "high" };
package/dist/shell/lex.js CHANGED
@@ -1169,6 +1169,7 @@ function scan(source, connectorsAreText, segments, level, list) {
1169
1169
  let assignmentSeen = false;
1170
1170
  let subscriptsClosed = false;
1171
1171
  let commandWord;
1172
+ let arithParens = 0;
1172
1173
  let w = new WordBuilder();
1173
1174
  const next = (j) => past(source, j + 1);
1174
1175
  const quotedBy = () => (inSingle || inDouble ? regionBy : undefined);
@@ -1503,7 +1504,7 @@ function scan(source, connectorsAreText, segments, level, list) {
1503
1504
  take(ch, i);
1504
1505
  continue;
1505
1506
  }
1506
- if (ch === "#" && !w.started) {
1507
+ if (ch === "#" && !w.started && arithParens === 0) {
1507
1508
  const nl = source.indexOf("\n", i);
1508
1509
  i = nl < 0 ? source.length : nl - 1;
1509
1510
  continue;
@@ -1531,6 +1532,14 @@ function scan(source, connectorsAreText, segments, level, list) {
1531
1532
  const r = endWord() ?? operandOwed(i);
1532
1533
  if (r !== undefined)
1533
1534
  return r;
1535
+ if (ch === "(") {
1536
+ if (arithParens > 0)
1537
+ arithParens++;
1538
+ else if (split && source[next(i)] === "(")
1539
+ arithParens = 1;
1540
+ }
1541
+ else if (arithParens > 0)
1542
+ arithParens--;
1534
1543
  current().tokens.push({ kind: "group", op: ch });
1535
1544
  resetPosition();
1536
1545
  continue;
@@ -8,6 +8,7 @@ import { SessionPolicyError } from "../../../core/session-policy-store.js";
8
8
  import { thrownText } from "../../../core/thrown-value.js";
9
9
  import { AdoptionError, NOT_MIGRATED_BY_DESIGN, readRootAdoptionFile, writeRootAdoptionFile, } from "./marker.js";
10
10
  import { readRuleOwner, ruleOwnerText, sameRuleOwner } from "../../../core/rule-owner.js";
11
+ import { principalNameOf } from "../../../core/principal-name.js";
11
12
  const CONFIG_ACCOUNT_FILE = "adoption-configs.json";
12
13
  function baselineConfigs(toPrincipal) {
13
14
  return [
@@ -333,12 +334,12 @@ function answerFromExisting(root, existing, from, toPrincipal) {
333
334
  return undefined;
334
335
  }
335
336
  export async function adoptLocalDataRoot(opts) {
336
- if (typeof opts.toPrincipal !== "string" || opts.toPrincipal === "") {
337
- throw new AdoptionError("adoption_bad_request", "adoptLocalDataRoot requires the adopting principal — adoption is the act of giving this data root an identity");
337
+ if (principalNameOf(opts.toPrincipal) === undefined) {
338
+ throw new AdoptionError("adoption_bad_request", "adoptLocalDataRoot requires the adopting principal, a principal name — adoption is the act of giving this data root an identity");
338
339
  }
339
340
  const from = readRuleOwner(opts.from);
340
341
  if (from === undefined) {
341
- throw new AdoptionError("adoption_bad_request", "the adoption source must be the local-owner kind or a principal with a non-blank name — local-single-user identity is the local-owner kind, never a blank string");
342
+ throw new AdoptionError("adoption_bad_request", "the adoption source must be the local-owner kind or a principal owner whose principal is a principal name — local-single-user identity is the local-owner kind, never a blank string");
342
343
  }
343
344
  if (from.kind === "principal" && from.principal === opts.toPrincipal) {
344
345
  throw new AdoptionError("adoption_bad_request", `the data root already belongs to "${opts.toPrincipal}" — there is nothing to adopt`);
@@ -1,6 +1,7 @@
1
1
  import { readFileSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { readRuleOwner, sameRuleOwner } from "../../../core/rule-owner.js";
4
+ import { principalNameOf } from "../../../core/principal-name.js";
4
5
  import { atomicWriteFile, ensureDir } from "../fs-atomic.js";
5
6
  export class AdoptionError extends Error {
6
7
  code;
@@ -39,7 +40,7 @@ function isRootAdoptionFileShape(v) {
39
40
  typeof m !== "object" ||
40
41
  typeof m.adoptionId !== "string" ||
41
42
  readRuleOwner(m.from) === undefined ||
42
- typeof m.toPrincipal !== "string" ||
43
+ principalNameOf(m.toPrincipal) === undefined ||
43
44
  typeof m.phase !== "number" ||
44
45
  ![2, 3, 4, 5].includes(m.phase)) {
45
46
  return false;
@@ -88,7 +89,7 @@ function isRootAdoptionFileShape(v) {
88
89
  if (a === null ||
89
90
  typeof a !== "object" ||
90
91
  from === undefined ||
91
- typeof a.toPrincipal !== "string" ||
92
+ principalNameOf(a.toPrincipal) === undefined ||
92
93
  typeof a.atMs !== "number" ||
93
94
  a.immutableReport === null ||
94
95
  typeof a.immutableReport !== "object") {
@@ -1,6 +1,8 @@
1
1
  import { type ExecutionOutcomeRecordWord } from "../../core/checkpoint-execution-record.js";
2
+ import { type HolderJudge } from "../../core/checkpoint-generation.js";
2
3
  import { type Checkpoint, type PendingSteerInput, type CheckpointFaultMode, type CheckpointStore, type CheckpointSummary, type CheckpointToken, type ReopenReason, type ResolveExpectation, type ResumeOutcome } from "../../core/checkpoint-store.js";
3
4
  import type { GateOutcome } from "../../core/gate-outcome.js";
5
+ import { type CheckpointDeleteGuard, type CheckpointOverdueCursor, type CheckpointOverdueQuery, type CheckpointPage, type CheckpointRowRead, type CheckpointSessionCursor, type CheckpointSessionQuery } from "../../core/checkpoint-queries.js";
4
6
  import { type CorruptReadInfo } from "./corrupt-read-sink.js";
5
7
  export interface FileCheckpointStoreOptions {
6
8
  /** This store's half of {@link import("./shared-ledger.js").LedgerPaths.onCorruptRead}. */
@@ -11,6 +13,13 @@ export interface FileCheckpointStoreOptions {
11
13
  fsync?: boolean;
12
14
  /** Compact the ledger into a snapshot once it exceeds this many events (then truncate). Default 1000. */
13
15
  compactEvery?: number;
16
+ /** The session head read (a session store's `headOf`) {@link FileCheckpointStore.deleteSessionCheckpoints} judges its guard by;
17
+ * without it the store has no `deleteSessionCheckpoints` member. */
18
+ sessionHeadOf?: (sessionId: string) => Promise<{
19
+ readonly owner: string | null;
20
+ } | undefined>;
21
+ /** The judge of a resolve's claim holder ({@link HolderJudge}); with it the store declares `fence = { holder: true }`. */
22
+ holderIsCurrent?: HolderJudge;
14
23
  }
15
24
  export declare class FileCheckpointStore implements CheckpointStore {
16
25
  /** design/173 §2.3 — honest declaration on the restart-survival axis the vocabulary claims: rows
@@ -34,6 +43,11 @@ export declare class FileCheckpointStore implements CheckpointStore {
34
43
  readonly execution: {
35
44
  readonly outcome: true;
36
45
  };
46
+ /** Declared exactly when the store was built with a `holderIsCurrent` judge. */
47
+ readonly fence?: {
48
+ readonly holder: true;
49
+ };
50
+ private readonly holderIsCurrent;
37
51
  private readonly fsyncEnabled;
38
52
  private readonly compactEvery;
39
53
  /** RB-134: the directory's ONE authority (map + token mutex + append log), joined not rebuilt. */
@@ -45,6 +59,8 @@ export declare class FileCheckpointStore implements CheckpointStore {
45
59
  /** The guarded {@link FileCheckpointStoreOptions.onCorruptRead} seat (the ledger's replay and this store's projection share it). */
46
60
  private readonly discloseCorrupt;
47
61
  private readonly ledgerPath;
62
+ /** Present exactly when the store was built with a session head read (`FileCheckpointStoreOptions.sessionHeadOf`). */
63
+ readonly deleteSessionCheckpoints?: (sessionId: string, guard: CheckpointDeleteGuard) => Promise<number>;
48
64
  constructor(root: string, opts?: FileCheckpointStoreOptions);
49
65
  /** Serialize an op behind any in-flight op on the same token (the in-process per-token async mutex). */
50
66
  private withLock;
@@ -69,6 +85,11 @@ export declare class FileCheckpointStore implements CheckpointStore {
69
85
  reap(scope: string, cutoff: number): Promise<number>;
70
86
  listByScope(scope: string): Promise<CheckpointSummary[]>;
71
87
  listScopes(): Promise<string[]>;
88
+ /** The listing faces' disclosure: a row read past a damage is reported through the corrupt-read seat, named by its non-secret
89
+ * identity (never its token). */
90
+ private listingDisclose;
91
+ listOverdue(query: CheckpointOverdueQuery): Promise<CheckpointPage<CheckpointSummary, CheckpointOverdueCursor>>;
92
+ listBySession(query: CheckpointSessionQuery): Promise<CheckpointPage<CheckpointRowRead, CheckpointSessionCursor>>;
72
93
  /** Force a compaction now (test/inspection). The snapshot rewrite + RB-167 closeForSwap swap that
73
94
  * makes `replay` read the full state from the snapshot alone is the base's {@link LedgerCore.compact}. */
74
95
  compactNow(): void;
@@ -1,7 +1,9 @@
1
1
  import { join } from "node:path";
2
2
  import { assertAdoptionBootGate } from "./adoption/marker.js";
3
3
  import { checkpointExecutionRecorded, executionRecordDisposition, ExecutionOutcomeConflictError, } from "../../core/checkpoint-execution-record.js";
4
- import { appendPendingSteer, CheckpointError, checkpointOccMatches, checkpointRowMatches, encodeAtFidelity, summarizeCheckpoint, validatePendingSteer, winnerFromOutcome, } from "../../core/checkpoint-store.js";
4
+ import { checkpointHolderMatches, checkpointOccMatches, checkpointRevOf } from "../../core/checkpoint-generation.js";
5
+ import { appendPendingSteer, CheckpointError, checkpointRowMatches, encodeAtFidelity, summarizeCheckpoint, validatePendingSteer, winnerFromOutcome, } from "../../core/checkpoint-store.js";
6
+ import { checkpointDeadlinePassed, deleteSessionRowsAtStart, readCheckpointOverdueQuery, readCheckpointSessionQuery, selectOverduePage, selectSessionPage, } from "../../core/checkpoint-queries.js";
5
7
  import { SharedLedgerTable } from "./shared-ledger.js";
6
8
  import { guardCorruptSink } from "./corrupt-read-sink.js";
7
9
  const CHECKPOINT_LEDGER_EVENT_REGISTRY = {
@@ -10,6 +12,7 @@ const CHECKPOINT_LEDGER_EVENT_REGISTRY = {
10
12
  reopen: true,
11
13
  execution: true,
12
14
  expire: true,
15
+ delete: true,
13
16
  steer_append: true,
14
17
  };
15
18
  const KNOWN_CHECKPOINT_LEDGER_EVENTS = new Set(Object.keys(CHECKPOINT_LEDGER_EVENT_REGISTRY));
@@ -45,6 +48,9 @@ function applyCheckpointEvent(cps, ev) {
45
48
  case "expire":
46
49
  cp.status = "expired";
47
50
  break;
51
+ case "delete":
52
+ cps.delete(ev.token);
53
+ break;
48
54
  case "steer_append": {
49
55
  const queue = cp.state.pendingSteerQueue ?? [];
50
56
  if (!queue.some((e) => e.inputId === ev.entry.inputId))
@@ -84,6 +90,7 @@ export class FileCheckpointStore {
84
90
  fidelity = "json";
85
91
  redecision = { reopen: true };
86
92
  execution = { outcome: true };
93
+ holderIsCurrent;
87
94
  fsyncEnabled;
88
95
  compactEvery;
89
96
  ledger;
@@ -97,6 +104,9 @@ export class FileCheckpointStore {
97
104
  constructor(root, opts = {}) {
98
105
  assertAdoptionBootGate(root, "FileCheckpointStore");
99
106
  this.fsyncEnabled = opts.fsync !== false;
107
+ this.holderIsCurrent = opts.holderIsCurrent;
108
+ if (opts.holderIsCurrent !== undefined)
109
+ this.fence = Object.freeze({ holder: true });
100
110
  this.compactEvery = opts.compactEvery ?? 1000;
101
111
  this.discloseCorrupt = guardCorruptSink(opts.onCorruptRead);
102
112
  const dir = join(root, "checkpoints");
@@ -108,6 +118,15 @@ export class FileCheckpointStore {
108
118
  ledgerPath: this.ledgerPath,
109
119
  snapshotPath: join(dir, "checkpoints.snapshot.jsonl"),
110
120
  });
121
+ const headOf = opts.sessionHeadOf;
122
+ if (headOf !== undefined) {
123
+ this.deleteSessionCheckpoints = (sessionId, guard) => deleteSessionRowsAtStart(this.cps, sessionId, guard, headOf, (token, row) => this.withLock(token, () => {
124
+ if (this.cps.get(token) !== row)
125
+ return false;
126
+ this.commit({ t: "delete", token }, true);
127
+ return true;
128
+ }));
129
+ }
111
130
  }
112
131
  withLock(token, fn) {
113
132
  return this.ledger.withLock(token, fn);
@@ -144,8 +163,11 @@ export class FileCheckpointStore {
144
163
  if (!checkpointOccMatches(cp, expect)) {
145
164
  return false;
146
165
  }
166
+ if (!checkpointHolderMatches(expect, this.holderIsCurrent)) {
167
+ return false;
168
+ }
147
169
  const winner = winnerFromOutcome(outcome);
148
- const rev = (cp.rev ?? 0) + 1;
170
+ const rev = checkpointRevOf(cp) + 1;
149
171
  this.commit({ t: "resolve", token, rev, resolvedOutcome: winner }, true);
150
172
  if (this.fault === "resolve-after-commit") {
151
173
  this.fault = null;
@@ -172,7 +194,7 @@ export class FileCheckpointStore {
172
194
  if (!checkpointRowMatches(cp, scope, "resolved") || checkpointExecutionRecorded(cp)) {
173
195
  return false;
174
196
  }
175
- const rev = (cp.rev ?? 0) + 1;
197
+ const rev = checkpointRevOf(cp) + 1;
176
198
  this.commit({ t: "reopen", token, rev, reason }, true);
177
199
  return true;
178
200
  });
@@ -204,7 +226,7 @@ export class FileCheckpointStore {
204
226
  }
205
227
  async reap(scope, cutoff) {
206
228
  let n = 0;
207
- const deadlinePassed = (deadline) => deadline !== undefined && (Number.isFinite(deadline) ? deadline <= cutoff : true);
229
+ const deadlinePassed = (deadline) => checkpointDeadlinePassed(deadline, cutoff);
208
230
  const candidates = [...this.cps.values()].filter((cp) => cp.scope === scope && cp.status === "pending" && deadlinePassed(cp.deadline));
209
231
  for (const cp of candidates) {
210
232
  const won = await this.withLock(cp.token, () => {
@@ -222,8 +244,7 @@ export class FileCheckpointStore {
222
244
  return n;
223
245
  }
224
246
  async listByScope(scope) {
225
- const sink = this.discloseCorrupt;
226
- const disclose = sink === undefined ? undefined : (sentence) => sink({ kind: "file", path: this.ledgerPath, reason: sentence });
247
+ const disclose = this.listingDisclose();
227
248
  const out = [];
228
249
  for (const cp of this.cps.values()) {
229
250
  if (cp.scope === scope && cp.status === "pending")
@@ -238,6 +259,17 @@ export class FileCheckpointStore {
238
259
  out.add(cp.scope);
239
260
  return [...out];
240
261
  }
262
+ listingDisclose() {
263
+ const sink = this.discloseCorrupt;
264
+ return sink === undefined ? undefined : (sentence) => sink({ kind: "file", path: this.ledgerPath, reason: sentence });
265
+ }
266
+ async listOverdue(query) {
267
+ const disclose = this.listingDisclose();
268
+ return selectOverduePage(this.cps.entries(), readCheckpointOverdueQuery(query), (cp) => summarizeCheckpoint(cp, disclose), disclose);
269
+ }
270
+ async listBySession(query) {
271
+ return selectSessionPage(this.cps.entries(), readCheckpointSessionQuery(query), (cp) => structuredClone(cp), this.listingDisclose());
272
+ }
241
273
  compactNow() {
242
274
  this.ledger.compact();
243
275
  }
@@ -2,7 +2,7 @@ import { createHash, randomBytes } from "node:crypto";
2
2
  import { appendFileSync, closeSync, existsSync, fsyncSync, openSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import { thrownText } from "../../core/thrown-value.js";
5
- import { applyFileRestoreViaEnv, boundaryPublishVerdict, worldStillMatchesMint, captureFileBackupViaEnv, modeProvenDifferent, previewFileDelta, describeTrackKey, fileHistoryExportDigest, caughtFault, DAMAGED_RECORD, resolveTrackKey, trackKeyOf, validateFileHistoryExport, } from "../../core/file-history-store.js";
5
+ import { applyFileRestoreViaEnv, boundaryPublishVerdict, worldStillMatchesMint, annulProofFailure, captureFileBackupViaEnv, modeProvenDifferent, previewFileDelta, describeTrackKey, fileHistoryExportDigest, caughtFault, DAMAGED_RECORD, resolveTrackKey, trackKeyOf, validateFileHistoryExport, } from "../../core/file-history-store.js";
6
6
  import { fileHistoryBoundariesToKeep, resolveFileHistoryRetention } from "../../core/file-history-retention.js";
7
7
  import { atomicWriteFile, ensureDir, sanitizePathComponent, sanitizeScope, writeThenLink } from "./fs-atomic.js";
8
8
  import { guardCorruptSink } from "./corrupt-read-sink.js";
@@ -481,9 +481,8 @@ export class FileFileHistoryStore {
481
481
  return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} has since been served to another edit of the same path — it is that edit's baseline now, not a retractable mint` } };
482
482
  }
483
483
  const proof = verify === undefined ? undefined : await worldStillMatchesMint(verify.env, absPath, root, rec.baseAvailable, rec.versions[0]?.blobHash ?? null, verify.signal);
484
- if (proof !== undefined && !proof.unchanged) {
485
- return { ok: false, error: { code: "conflict", message: `first-touch record for ${absPath} is NOT retractable: ${proof.reason} — the write this retraction compensates for may have changed the file` } };
486
- }
484
+ if (proof !== undefined && proof.verdict !== "unchanged")
485
+ return annulProofFailure(proof, absPath);
487
486
  const fresh = this.readTrackedState(scope);
488
487
  if (fresh.corrupt)
489
488
  return { ok: false, error: { code: "track_failed", message: `file history for scope "${scope}" became unreadable — the record was left in place`, ...fresh.fault } };
@@ -723,7 +722,7 @@ export class FileFileHistoryStore {
723
722
  let targetVersion = boundary.get(key);
724
723
  if (targetVersion === undefined) {
725
724
  if (!rec.baseAvailable) {
726
- ledger.refused.push({ path: key, reason: "base_unavailable" });
725
+ ledger.refused.push({ path: key, reason: "base_unavailable", class: "base_unavailable" });
727
726
  continue;
728
727
  }
729
728
  targetVersion = 1;
@@ -735,7 +734,7 @@ export class FileFileHistoryStore {
735
734
  }
736
735
  const resolved = resolveTrackKey(root, key, descriptorOf(rec));
737
736
  if (!resolved.ok) {
738
- ledger.refused.push({ path: key, reason: resolved.reason });
737
+ ledger.refused.push({ path: key, reason: resolved.reason, class: resolved.class });
739
738
  continue;
740
739
  }
741
740
  let target;
@@ -777,7 +776,7 @@ export class FileFileHistoryStore {
777
776
  else if (applied.outcome === "identical")
778
777
  ledger.identicalSkipped.push(key);
779
778
  else if (applied.outcome === "refused")
780
- ledger.refused.push({ path: key, reason: applied.reason });
779
+ ledger.refused.push({ path: key, reason: applied.reason, class: applied.class });
781
780
  else
782
781
  ledger.failed.push({ path: key, reason: applied.reason });
783
782
  if ((applied.outcome === "applied" || applied.outcome === "identical") && applied.modeNotPreserved === true)
@@ -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 } : {});
@@ -2,18 +2,19 @@ import { existsSync, renameSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { writerOf } from "../../core/permission-rule-store.js";
4
4
  import { readRuleOwner, ruleOwnerText, sameRuleOwner } from "../../core/rule-owner.js";
5
+ import { principalNameOf } from "../../core/principal-name.js";
5
6
  import { createPermissionRuleStoreProvider } from "../../core/permission-rule-provider.js";
6
7
  import { syncPermissionRules } from "../../core/permission-rule-sync.js";
7
8
  import { thrownText } from "../../core/thrown-value.js";
8
9
  import { FileStoreLockError } from "./fs-atomic.js";
9
10
  import { FileDurableRulePartitionProvider, LOCAL_OWNER_FILE, principalRuleFileName, readRuleAdoptionFile, writeRuleAdoptionFile, } from "./permission-rule-store.js";
10
11
  export async function adoptFilePermissionRuleStore(opts) {
11
- if (typeof opts.toPrincipal !== "string" || opts.toPrincipal === "") {
12
- 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");
13
14
  }
14
15
  const from = readRuleOwner(opts.from);
15
16
  if (from === undefined) {
16
- throw new Error("adoptFilePermissionRuleStore requires a source owner — a principal with a non-blank name, or the local owner");
17
+ throw new Error("adoptFilePermissionRuleStore requires a source owner — a principal owner whose principal is a principal name, or the local owner");
17
18
  }
18
19
  if (from.kind === "principal" && from.principal === opts.toPrincipal) {
19
20
  throw new Error(`the bucket already belongs to "${opts.toPrincipal}" — there is nothing to adopt`);
@@ -4,6 +4,7 @@ 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
6
  import { readRuleOwner } from "../../core/rule-owner.js";
7
+ import { principalNameOf, readPrincipal } from "../../core/principal-name.js";
7
8
  import { PERMISSION_RULES_LATER_GRAMMAR_CODE, PERMISSION_RULE_WRITER, applySyncJoin, applyTombstones, assertDeleteDeltaCarriesNoAdd, assertRedemptionNotQuarantined, assertWriteDeltaScopeDurable, foldDelta, unknownRuleWriteDeltaError, } from "../../core/permission-rule-store.js";
8
9
  import { sameOrgPolicyContent } from "../../core/permission-rule-org.js";
9
10
  import { SESSION_RULES_GRAMMAR, readRuleGrammarStamp } from "../../core/session-policy-store.js";
@@ -66,7 +67,7 @@ function isRuleAdoptionFileShape(v) {
66
67
  const rec = (hasMarker ? v.marker : v.adopted);
67
68
  if (rec === null || typeof rec !== "object")
68
69
  return false;
69
- if (readRuleOwner(rec.from) === undefined || typeof rec.toPrincipal !== "string" || rec.toPrincipal === "")
70
+ if (readRuleOwner(rec.from) === undefined || principalNameOf(rec.toPrincipal) === undefined)
70
71
  return false;
71
72
  return hasMarker ? rec.phase === 2 || rec.phase === 3 || rec.phase === 4 || rec.phase === 5 : typeof rec.atMs === "number" && Number.isFinite(rec.atMs);
72
73
  }
@@ -452,17 +453,22 @@ export class FileDurableRulePartitionProvider {
452
453
  this.lock = lock;
453
454
  };
454
455
  forPrincipal(principal) {
455
- 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") {
456
461
  return { list: async () => ({ ...EMPTY_READ }), durability: "process-local" };
457
462
  }
463
+ const name = reading.name;
458
464
  const adoption = this.adoptionMarker();
459
465
  if (adoption !== undefined) {
460
466
  const rec = "adopted" in adoption ? adoption.adopted : adoption.marker;
461
- if (rec.from.kind === "principal" && rec.from.principal === principal) {
462
- 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);
463
469
  }
464
470
  }
465
- 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);
466
472
  }
467
473
  readOnlySourceView(sourceName, targetName, flipped) {
468
474
  const pick = flipped ? targetName : existsSync(join(this.dir, sourceName)) ? sourceName : targetName;
@@ -1,4 +1,4 @@
1
- import type { Session, SessionCreateOptions, SessionForkOptions, SessionHead, 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).
@@ -59,6 +60,15 @@ export declare class FileSessionRepo implements SessionRepo {
59
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).
60
61
  */
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;
62
72
  private storage;
63
73
  /**
64
74
  * RB-437 — release every shared authority this repo joined (LAST holder ⇒ evict + close the append fd).
@@ -75,12 +85,25 @@ export declare class FileSessionRepo implements SessionRepo {
75
85
  dispose(): Promise<void>;
76
86
  create(options?: SessionCreateOptions): Promise<Session>;
77
87
  open(metadata: SessionMetadata): Promise<Session>;
78
- 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;
79
102
  /**
80
103
  * Subagent transcript persistence — the PLACED partition's own enumeration (the joint reap's
81
104
  * partition-leg input; `TtlSessionStore` re-exposes it verbatim). Age (`olderThanMs`) is judged on
82
- * the session FILE's mtime — the transcript's last append — falling back to `placedAt` when the
83
- * 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).
84
107
  * Rows missing either `(scope, handle)` join half return the honest `tupleIncomplete` variant
85
108
  * (consumers fail closed on it — never age-reaped, see the SessionStore contract).
86
109
  */
@@ -1,4 +1,4 @@
1
- import { closeSync, existsSync, fstatSync, openSync, readdirSync, rmSync, statSync } from "node:fs";
1
+ import { closeSync, existsSync, fstatSync, openSync, readdirSync, rmSync, utimesSync } from "node:fs";
2
2
  import { join } from "node:path";
3
3
  import { BaseSessionStorage, StoredSession, SessionError, assertForkTarget, compareOccupants, forkRowCells, frozenRow, getEntriesToFork, importRowCells, incarnationCell, leafIdAfterEntry, ownerCell, readIncarnationCell, readOwnerCell, uuidv7, validateEntriesForImport, } from "../../internal/harness.js";
4
4
  import { canonicalStoreKey, AppendLog, atomicWriteFile, ensureDir, firstJsonlRecord, lastJsonlRecord, readJsonlRecords, sanitizePathComponent, writeThenLink } from "./fs-atomic.js";
@@ -125,6 +125,15 @@ export class FileSessionRepo {
125
125
  };
126
126
  }
127
127
  async headOf(sessionId) {
128
+ return this.atRow(sessionId, (fd, size, meta) => {
129
+ const last = lastJsonlRecord(fd, size, (r) => r.kind === "entry", SESSION_LINE_JUDGE);
130
+ return { owner: meta.owner ?? null, incarnation: meta.incarnation, leafId: last === undefined ? null : leafIdAfterEntry(last.entry) };
131
+ });
132
+ }
133
+ rowOf(sessionId) {
134
+ return this.atRow(sessionId, (_fd, _size, meta, mtimeMs) => ({ ...meta, lastActiveAt: Math.trunc(mtimeMs) }));
135
+ }
136
+ atRow(sessionId, read) {
128
137
  const path = this.pathFor(sessionId);
129
138
  let fd;
130
139
  try {
@@ -136,10 +145,8 @@ export class FileSessionRepo {
136
145
  throw err;
137
146
  }
138
147
  try {
139
- const size = fstatSync(fd).size;
140
- const meta = this.headerOf(sessionId, path, firstJsonlRecord(fd, size, SESSION_LINE_JUDGE));
141
- const last = lastJsonlRecord(fd, size, (r) => r.kind === "entry", SESSION_LINE_JUDGE);
142
- return { owner: meta.owner ?? null, incarnation: meta.incarnation, leafId: last === undefined ? null : leafIdAfterEntry(last.entry) };
148
+ const { size, mtimeMs } = fstatSync(fd);
149
+ return read(fd, size, this.headerOf(sessionId, path, firstJsonlRecord(fd, size, SESSION_LINE_JUDGE)), mtimeMs);
143
150
  }
144
151
  finally {
145
152
  closeSync(fd);
@@ -201,80 +208,65 @@ export class FileSessionRepo {
201
208
  const { meta, entries } = this.read(metadata.id);
202
209
  return new StoredSession(this.storage(meta, entries));
203
210
  }
204
- async list() {
205
- let names;
211
+ async touch(sessionId) {
212
+ const now = new Date();
206
213
  try {
207
- names = readdirSync(this.dir);
214
+ utimesSync(this.pathFor(sessionId), now, now);
208
215
  }
209
216
  catch (err) {
210
- if (err.code !== "ENOENT") {
211
- this.disclose(this.dir, `session directory unreadable (${err.code ?? "unknown"}) — listed as empty`);
212
- }
213
- return [];
214
- }
215
- const out = [];
216
- for (const name of names) {
217
- if (!name.endsWith(SUFFIX))
218
- continue;
219
- const id = name.slice(0, -SUFFIX.length);
220
- try {
221
- const { createdAt, forkedFrom, placement } = this.read(id).meta;
222
- if (placement !== undefined)
223
- continue;
224
- out.push({ id, createdAt, ...(forkedFrom !== undefined ? { forkedFrom } : {}) });
225
- }
226
- catch (err) {
227
- if (!(err instanceof SessionError && err.code === "not_found")) {
228
- this.disclose(this.pathFor(id), `session log unreadable (${thrownText(err)}) — skipped from the listing`, id);
229
- }
230
- }
217
+ if (err.code === "ENOENT")
218
+ return;
219
+ throw new SessionError("storage", `session ${sessionId}'s activity could not be recorded: ${thrownText(err)}`, err instanceof Error ? err : undefined);
231
220
  }
232
- return out.sort((a, b) => a.createdAt.localeCompare(b.createdAt));
233
221
  }
234
- async listPlaced(kind, opts) {
222
+ async list() {
223
+ return this.rows("the listing")
224
+ .filter((row) => row.placement === undefined)
225
+ .sort((a, b) => a.createdAt.localeCompare(b.createdAt));
226
+ }
227
+ rows(listing) {
235
228
  let names;
236
229
  try {
237
230
  names = readdirSync(this.dir);
238
231
  }
239
232
  catch (err) {
240
233
  if (err.code !== "ENOENT") {
241
- this.disclose(this.dir, `session directory unreadable (${err.code ?? "unknown"}) — placed listing degraded to empty`);
234
+ this.disclose(this.dir, `session directory unreadable (${err.code ?? "unknown"}) — ${listing} degraded to empty`);
242
235
  }
243
236
  return [];
244
237
  }
245
- const now = Date.now();
246
238
  const out = [];
247
239
  for (const name of names) {
248
240
  if (!name.endsWith(SUFFIX))
249
241
  continue;
250
242
  const id = name.slice(0, -SUFFIX.length);
251
- let placement;
243
+ let row;
252
244
  try {
253
- placement = this.read(id).meta.placement;
245
+ row = this.rowOf(id);
254
246
  }
255
247
  catch (err) {
256
- if (!(err instanceof SessionError && err.code === "not_found")) {
257
- this.disclose(this.pathFor(id), `session log unreadable (${thrownText(err)}) — skipped from the placed listing`, id);
258
- }
248
+ this.disclose(this.pathFor(id), `session log unreadable (${thrownText(err)}) — skipped from ${listing}`, id);
259
249
  continue;
260
250
  }
251
+ if (row !== undefined)
252
+ out.push(row);
253
+ }
254
+ return out;
255
+ }
256
+ async listPlaced(kind, opts) {
257
+ const now = Date.now();
258
+ const out = [];
259
+ for (const row of this.rows("the placed listing")) {
260
+ const placement = row.placement;
261
261
  if (placement === undefined || placement.kind !== kind)
262
262
  continue;
263
263
  if (opts?.scope !== undefined && placement.scope !== opts.scope)
264
264
  continue;
265
- if (opts?.olderThanMs !== undefined) {
266
- let ageAnchor = placement.placedAt;
267
- try {
268
- ageAnchor = statSync(this.pathFor(id)).mtimeMs;
269
- }
270
- catch {
271
- }
272
- if (now - ageAnchor <= opts.olderThanMs)
273
- continue;
274
- }
265
+ if (opts?.olderThanMs !== undefined && now - row.lastActiveAt <= opts.olderThanMs)
266
+ continue;
275
267
  out.push(placement.scope !== undefined && placement.handle !== undefined
276
- ? { sessionId: id, placedAt: placement.placedAt, scope: placement.scope, handle: placement.handle }
277
- : { sessionId: id, placedAt: placement.placedAt, tupleIncomplete: true });
268
+ ? { sessionId: row.id, placedAt: placement.placedAt, scope: placement.scope, handle: placement.handle }
269
+ : { sessionId: row.id, placedAt: placement.placedAt, tupleIncomplete: true });
278
270
  }
279
271
  return out;
280
272
  }