@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
@@ -0,0 +1,93 @@
1
+ /**
2
+ * The engine's ATTESTATION record — the one carrier of what an engine station knows about a decision and a policy cannot
3
+ * state: WHO settled the call's wait and WHICH question that answered (the settlement, the ask's origin word and class set,
4
+ * the digest of the arguments the answer licenses), and the facts the classifier stations, the in-fold unresolvable arms,
5
+ * the integrity guards and the policy fold record. It rides the decision as its `attestation` member and is read through
6
+ * {@link attestationOf} alone; the decision object's identity carries nothing.
7
+ *
8
+ * Minted only by {@link mintAttestation} and combined only by {@link mergeAttestation}: both freeze the record and enter it
9
+ * in a module-private brand set, so a value a caller composed — a literal, a copy, a structured clone — is not a record, and
10
+ * the decision receipt refuses a decision carrying one. A record is bound to the call it was minted for (`toolCallId` +
11
+ * `toolName`): handed back for another call it reads as absent. A spread of a decision keeps its record, and the record still
12
+ * says only what the engine minted — a refusal record on an allow is a contradiction the gate's exit refuses, and a
13
+ * resolution's answer binds the arguments it licensed (`inputDigest`).
14
+ *
15
+ * A leaf (type-only imports): the decision module that receives a record and the class derivation that reads one for its call
16
+ * both depend on it, and neither depends on the other through it.
17
+ */
18
+ import type { AskClass, AskOrigin } from "./ask-origin.js";
19
+ import type { ClassifierDenyCause, Settlement } from "./gate-outcome.js";
20
+ import type { AutoModeClassifierRound } from "./auto-mode.js";
21
+ import type { AskUnresolvableCause } from "./ask-unresolvable-notice.js";
22
+ import type { PathDenialEvidence } from "../tools/fs/safety.js";
23
+ import type { AskGuard } from "./tool-policy.js";
24
+ export interface EngineAttestation {
25
+ readonly toolCallId: string;
26
+ readonly toolName: string;
27
+ /** What ended the call's wait. The answer group — `settlement`, `origin`, `classes`, `inputDigest` — travels as one. */
28
+ readonly settlement?: Settlement;
29
+ /** The settled ask's origin word. */
30
+ readonly origin?: AskOrigin;
31
+ /** The settled ask's class set (`ASK_CLASSES` order), when the minting station held one. */
32
+ readonly classes?: readonly AskClass[];
33
+ /** `exactBoundInputHashOf` of the arguments the settlement licenses (an approver's edit, the snapshot shown, or the asked
34
+ * args); absent when they have none (outside the bindable domain) — such a record licenses no bytes. */
35
+ readonly inputDigest?: string;
36
+ /** The FORM of a classifier round that did not rule (a classifier deny's cause). */
37
+ readonly classifierCause?: ClassifierDenyCause;
38
+ /** WHICH model answered a classification, on either arm. */
39
+ readonly classifierRound?: AutoModeClassifierRound;
40
+ /** Why an in-fold deny refused an ask nobody could resolve. */
41
+ readonly unresolvableCause?: AskUnresolvableCause;
42
+ /** The classes of the OTHER asks a policy fold collapsed into this one (each contributor's classes, unioned) — so a fact the
43
+ * fold does not copy (a guard, an unreadable-rule fact, a bare real-approval bit) is not lost behind the ask that won the
44
+ * slot. Written by the policy fold and by the gate's own writers of a standing ask's carried classes; the one carrier of
45
+ * those classes. */
46
+ readonly foldedClasses?: readonly AskClass[];
47
+ /** WHICH integrity guards stand behind this ask — a removal of a protected location, an unverifiable recursive delete, shell
48
+ * text the engine cannot read (or an environment that did not answer the read station), the session-transcript write,
49
+ * another person's shared artifact. Engine findings (the guard policies, the read station's silence, the artifact tool's
50
+ * consent): the class derivation reads them as classes and as explainers of the real-approval bit, so only a record carries
51
+ * them. Never copied onto the approval request or the park row. */
52
+ readonly guards?: readonly AskGuard[];
53
+ /** Where a path deny row refused the call — the row, the view of the target it met, the face the call is on. The gate's
54
+ * exit mints the refusal's card from it; the judge that found the row is its only writer. */
55
+ readonly pathDenial?: PathDenialEvidence;
56
+ /** A seat refused the call's arguments because no approval can be bound to them: the refusal's sentence, carried by the
57
+ * refusal itself — the gate's deny exit reads it (the remedy it gives) instead of judging again. */
58
+ readonly bindingRefusal?: string;
59
+ }
60
+ /** The members a station attests — everything but the call binding. */
61
+ export type AttestationMembers = Omit<EngineAttestation, "toolCallId" | "toolName">;
62
+ /** Mint a record for `call`. Engine stations only: not re-exported from `src/index.ts`. The values are DETACHED snapshots, so a
63
+ * caller that later mutates the settlement object it was handed cannot rewrite what the engine attests. */
64
+ export declare function mintAttestation(call: {
65
+ toolCallId: string;
66
+ toolName: string;
67
+ }, members: AttestationMembers): EngineAttestation;
68
+ /** Is `v` a record the engine minted (the brand alone — no binding)? The receipt's test. */
69
+ export declare function isEngineAttestation(v: unknown): v is EngineAttestation;
70
+ /** THE read: the record `d` carries FOR `call` — a branded record bound to that call, else `undefined` (a record bound to
71
+ * another call is a replayed one and reads as absent). Read off the own data member, never through an accessor. */
72
+ export declare function attestationOf(d: unknown, call: {
73
+ toolCallId: string;
74
+ toolName: string;
75
+ }): EngineAttestation | undefined;
76
+ /**
77
+ * Combine two records for `call`, member GROUP by group: the later record's group stands where it has one, the earlier's
78
+ * fills a group the later lacks. A record not bound to `call` contributes nothing. `answer` scope is the veto's merge: the
79
+ * earlier record contributes ONLY its answer, and only when the later carries none — a person's yes rides a later layer's
80
+ * deny (invariant I3) while the refusing station's own facts stay its own.
81
+ */
82
+ export declare function mergeAttestation(call: {
83
+ toolCallId: string;
84
+ toolName: string;
85
+ }, earlier: EngineAttestation | undefined, later: EngineAttestation | undefined, scope?: "all" | "answer"): EngineAttestation | undefined;
86
+ /** `d` with `members` attested for `call`, merged over the record it already carries for that call (the new members' groups
87
+ * win). Always a fresh object — the receipt hands out frozen ones. */
88
+ export declare function attest<T extends object>(d: T, call: {
89
+ toolCallId: string;
90
+ toolName: string;
91
+ }, members: AttestationMembers): T;
92
+ /** `d` carrying `record` (a fresh object), or `d` itself when there is no record to put on it. */
93
+ export declare function withAttestation<T extends object>(d: T, record: EngineAttestation | undefined): T;
@@ -0,0 +1,70 @@
1
+ const ATTESTATION_GROUP_OF = {
2
+ settlement: "answer",
3
+ origin: "answer",
4
+ classes: "answer",
5
+ inputDigest: "answer",
6
+ classifierCause: "classifierCause",
7
+ classifierRound: "classifierRound",
8
+ unresolvableCause: "unresolvableCause",
9
+ foldedClasses: "foldedClasses",
10
+ guards: "guards",
11
+ pathDenial: "pathDenial",
12
+ bindingRefusal: "bindingRefusal",
13
+ };
14
+ const ATTESTATION_MEMBERS = Object.keys(ATTESTATION_GROUP_OF);
15
+ const groupLead = (g) => ATTESTATION_MEMBERS.find((k) => ATTESTATION_GROUP_OF[k] === g);
16
+ const ENGINE_ATTESTATIONS = new WeakSet();
17
+ function detachedMember(v) {
18
+ if (Array.isArray(v))
19
+ return Object.freeze([...v]);
20
+ if (typeof v !== "object" || v === null)
21
+ return v;
22
+ return Object.freeze(Object.fromEntries(Object.entries(v).map(([k, x]) => [k, typeof x === "object" && x !== null ? Object.freeze(Array.isArray(x) ? [...x] : { ...x }) : x])));
23
+ }
24
+ export function mintAttestation(call, members) {
25
+ const record = { toolCallId: call.toolCallId, toolName: call.toolName };
26
+ for (const k of ATTESTATION_MEMBERS)
27
+ if (members[k] !== undefined)
28
+ record[k] = detachedMember(members[k]);
29
+ const minted = Object.freeze(record);
30
+ ENGINE_ATTESTATIONS.add(minted);
31
+ return minted;
32
+ }
33
+ export function isEngineAttestation(v) {
34
+ return typeof v === "object" && v !== null && ENGINE_ATTESTATIONS.has(v);
35
+ }
36
+ const boundTo = (r, call) => isEngineAttestation(r) && r.toolCallId === call.toolCallId && r.toolName === call.toolName ? r : undefined;
37
+ export function attestationOf(d, call) {
38
+ if (typeof d !== "object" || d === null)
39
+ return undefined;
40
+ return boundTo(Object.getOwnPropertyDescriptor(d, "attestation")?.value, call);
41
+ }
42
+ export function mergeAttestation(call, earlier, later, scope = "all") {
43
+ const a = boundTo(earlier, call);
44
+ const b = boundTo(later, call);
45
+ if (a === undefined)
46
+ return b;
47
+ const members = {};
48
+ if (b !== undefined)
49
+ for (const k of ATTESTATION_MEMBERS)
50
+ if (b[k] !== undefined)
51
+ members[k] = b[k];
52
+ let filled = false;
53
+ for (const g of new Set(Object.values(ATTESTATION_GROUP_OF))) {
54
+ if ((scope === "answer" && g !== "answer") || members[groupLead(g)] !== undefined || a[groupLead(g)] === undefined)
55
+ continue;
56
+ for (const k of ATTESTATION_MEMBERS)
57
+ if (ATTESTATION_GROUP_OF[k] === g && a[k] !== undefined)
58
+ members[k] = a[k];
59
+ filled = true;
60
+ }
61
+ if (!filled)
62
+ return b;
63
+ return mintAttestation(call, members);
64
+ }
65
+ export function attest(d, call, members) {
66
+ return withAttestation(d, mergeAttestation(call, attestationOf(d, call), mintAttestation(call, members)));
67
+ }
68
+ export function withAttestation(d, record) {
69
+ return record === undefined ? d : { ...d, attestation: record };
70
+ }
@@ -16,7 +16,10 @@
16
16
  * memory distiller's chat seat key), and `inheritedHostEnv` subtracts every entry whose value is one,
17
17
  * compared whole, under every policy. A credential resolved per request (a per-model auth hook's answer) is not in
18
18
  * it: the host that resolves it declares it. The same inheritance-only reading as the word above.
19
+ * - `mods.skill_seat` — a skill carries its own hooks: `SkillSpec.mods` registrations are admitted on every leg that loads
20
+ * the skill and take part only while the skill is active there (from its activation to the run's end, a park and its
21
+ * resume included); they are the leg's own (no delegated child dispatches them or is screened by them).
19
22
  */
20
- export declare const ENGINE_CAPABILITIES: readonly ["inherit_env.own_credentials_withheld", "inherit_env.own_credential_values_withheld"];
23
+ export declare const ENGINE_CAPABILITIES: readonly ["inherit_env.own_credentials_withheld", "inherit_env.own_credential_values_withheld", "mods.skill_seat"];
21
24
  /** One word of {@link ENGINE_CAPABILITIES}. */
22
25
  export type EngineCapability = (typeof ENGINE_CAPABILITIES)[number];
@@ -1 +1 @@
1
- export const ENGINE_CAPABILITIES = Object.freeze(["inherit_env.own_credentials_withheld", "inherit_env.own_credential_values_withheld"]);
1
+ export const ENGINE_CAPABILITIES = Object.freeze(["inherit_env.own_credentials_withheld", "inherit_env.own_credential_values_withheld", "mods.skill_seat"]);
@@ -324,6 +324,14 @@ export interface EngineNotice {
324
324
  * runs. ONCE PER LEG PER (api, key set) — a deployment fact, not a request fact. Audience `operator`;
325
325
  * `detail: { keys, api, modelId, sessionId, runId }` — `keys` the key NAMES in `extraBody`'s order (never a
326
326
  * value), `api` the wire the adapter speaks, `modelId` the catalog id the request was sent as.
327
+ * - `"model.capability_downgraded"` (#1830) — a capability the session's requests used was withheld from the model
328
+ * they were sent to: today, images replaced by a one-line placeholder because the model's entry declares no image
329
+ * input (`Model.input` without `"image"`; `capabilityOf` in `brain/model-capability.ts` is the one reading, and an
330
+ * entry that does not declare `input` keeps its images). The message names the model and the way out (declare the
331
+ * image input, or switch models). Never minted for reasoning a model declares off — the reasoning resolution's
332
+ * drop arm (`TaskResult.effectiveReasoning.dropped`) is that fact's face. ONCE PER SESSION PER (model, capability)
333
+ * (the session's announced record); one report per request also becomes the operator trace `vision.placeholder`.
334
+ * Audience `user`; `detail: { model, capability: "image", status: "declared_off", sessionId, runId }`.
327
335
  * - `"context.tool_turn_repaired"` (#1224) — a provider request was built from a transcript that breaks the
328
336
  * tool-turn law, and the request view restored it (`engine/llm/tool-turns.ts`; the transcript is never
329
337
  * rewritten): a block after an assistant's tool calls moved ahead of them (`trailing_text`), a result recorded
@@ -393,15 +401,25 @@ export interface EngineNotice {
393
401
  * `detail: { problem, sessionId, runId }`.
394
402
  * - `"config.execution_env_capability_invalid"` — a remote env DECLARES a boolean capability key
395
403
  * (`isolation`, `suspendable`, `canonicalPathAuthoritative`) with a non-boolean value; ABSENCE is a
396
- * supported reading of each and stays silent. Once per key per run; `detail: { key, valueType }`.
404
+ * supported reading of each and stays silent. Once per key per run; `detail: { key, valueType }`. Also minted for
405
+ * `withheldEnv` (key `"withheldEnv"`) when it is neither a list of findings nor `"unknown"`, read at a shell call of
406
+ * a root leg (once per run).
397
407
  * - `"config.secret_env_scrubbed"` (#1081) — the D1 fail-closed `scrub` policy, or the deployment's
398
408
  * own credentials (`declareWithheldEnv`: a declared name, or a value equal to a declared or engine-held
399
409
  * credential value), withheld one or more keys from a spawned child's environment (a tool's shell, an
400
410
  * oracle gate, or a language server).
401
411
  * Once per PROCESS, shared by every scrub site ({@link import("./secret-env.js").announceSecretEnvScrub});
402
412
  * `detail: { names, ownCredentials? }` — every withheld key's name, never a value; `ownCredentials`, present
403
- * only when one was withheld, the subset withheld as own credentials, by name or by value (under any policy,
404
- * `"all"` included).
413
+ * only when one was withheld, the subset that is the deployment's own credential, by name or by value, whichever
414
+ * rule withheld it (withheld under any policy, `"all"` included).
415
+ * - `"inherit_env.names_withheld"` (#1963) — the same fact for the person whose run drives a tool shell: the variables
416
+ * of the engine's environment that shell does not receive (`ExecutionEnv.withheldEnv`), the scrub's half (the run's
417
+ * `inheritEnv` hands them on) and the deployment's own credentials (no policy does). Audience `user`. Read as each
418
+ * call to the engine's own shell tool starts on a root leg (the answer can grow during a run: a credential the engine
419
+ * takes in when it first routes a model is withheld from the next child); once per SESSION per name set (the
420
+ * session's announced record). `detail: { state, names?, ownCredentials?, sessionId, runId? }` — `state` `"withheld"`
421
+ * carries the operator row's split (names only, never a value); `"unknown"` (the environment answered `"unknown"`)
422
+ * carries no names and says the engine could not determine them.
405
423
  * - `"config.credential_not_withheld"` (#1816) — a credential value the engine was handed (a brain's key or credential
406
424
  * header, a model entry's or a peer's credential header, a consolidation seat's key) is no credential (a placeholder
407
425
  * such as `EMPTY`, fewer than eight characters, one character repeated): it is used as given, but a variable holding
@@ -416,10 +434,9 @@ export interface EngineNotice {
416
434
  * {@link import("./cross-boundary-taint.js").crossBoundaryPostureUndeclaredNotice}. Audience `operator`.
417
435
  * - `"config.cross_boundary_record_unwritten"` — a session's cross-boundary record the engine owed could not be written (the
418
436
  * store threw, or answered with no entry id) and refused nothing: on a tree that is not governed no judgment reads the record;
419
- * at a governed leg's prepare or settle the next leg reads the content after the newest record as off-target — except where an
420
- * earlier record of the same write landed and its catch-up did not: that catch-up record has not been written, and until #2160
421
- * lands the next leg may read the content before the earlier record as covered and may not route its device calls to a person
422
- * (KNOWN-LIMITS KL-469-c; the terminal shape is fail-closed), which the sentence says. Once per state a leg could not write;
437
+ * on a governed tree it stays owed — a prepare's by the leg's next write — and once none lands (a settle's failure is the leg's
438
+ * last write; a parked leg's suspend record landed before it) the next leg reads the content after the newest record as off-target,
439
+ * which the sentence says for the phase that failed. Once per state a leg could not write;
423
440
  * `detail: { sessionId, runId, phase, governed, cause }` (`phase`: `prepare` / `exit` / `suspend` / `settle`, where that state
424
441
  * first failed). Minted by
425
442
  * {@link import("./cross-boundary-taint.js").crossBoundaryRecordUnwrittenNotice}. Audience `operator`.
@@ -466,14 +483,16 @@ export interface EngineNotice {
466
483
  * the first eight `{ rule, scopeRoot }`, `count` all of them; `rule` is the rule text as the store served it, through the same reading
467
484
  * as `permission.allowed_tool_not_granted`'s `entries[].entry` (the original, not a spelling of it, when it is at most 1 024 code points;
468
485
  * a longer one is cut to 1 024 plus the truncation mark, 1 025 in all), `scopeRoot` neutralized and bounded. Audience `user`.
469
- * - `"config.session_rules_earlier_grammar"` — a session's stored permission rules (`RunnerDeps.sessionPolicyStore`) hold
470
- * entries the rule grammar they were written in reads as nothing: an allow entry admits nothing, and a `toolDeny` entry
471
- * this engine's grammar reads as no rule makes those rules refuse every call until they are rewritten. The message names
486
+ * - `"config.session_rules_earlier_grammar"` — a session's stored permission rules (`RunnerDeps.sessionPolicyStore`) were
487
+ * written in an earlier rule grammar and hold entries it reads otherwise than this engine's would: an entry that grammar
488
+ * reads as nothing (an allow admits nothing; a `toolDeny` entry this engine's grammar reads as no rule makes those rules
489
+ * refuse every call until they are rewritten), or one whose meaning a later grammar revised — the entry keeps its writer's
490
+ * meaning, or takes this grammar's when its writer's could not read it, and the message says which, with both. The message names
472
491
  * the session, the bucket, the entries (the first five, the rest counted), the reader's word and the way out. Audience
473
492
  * `user`. Once per distinct entry set per bucket per rule layer (the run's own rules, each ancestor's inherited ones).
474
493
  * `detail: { bucket, storedGrammar, entries: [{ entry, reader }], rewrite: { by, stampsGrammar }, rulesSessionId,
475
494
  * sessionId }` — `entries` every one, `entry` through the same reading as `permission.allowed_tool_not_granted`'s;
476
- * `reader` ∈ `no_rule` / `named_no_tool`; `rewrite.by` = `operator_write_without_rev`; `rulesSessionId` the session
495
+ * `reader` ∈ `no_rule` / `named_no_tool` / `grammar_revised`; `rewrite.by` = `operator_write_without_rev`; `rulesSessionId` the session
477
496
  * whose rules they are (an ancestor's on a delegated child), `sessionId` the run that read them.
478
497
  * - `"config.durable_gate_unavailable"` — a durable-approval MANDATE is in force on a leg with NO
479
498
  * checkpoint store: the per-principal `forceDurableGate` entitlement, or the task's own
@@ -11,14 +11,31 @@ declare function joinUnder(root: string, rel: string): string;
11
11
  declare function parentDirOf(absPath: string): string | undefined;
12
12
  /** The re-join verdict of {@link resolveTrackKey}: an absolute path to operate on, or a NAMED
13
13
  * refusal (the fail-closed arm — a recorded key that would escape `root` is never coerced into
14
- * something writable). A-082 idx5: named so the fence can be part of the public surface. */
14
+ * something writable) carrying the restore ledger's class for it. A-082 idx5: named so the fence can be part of the public surface. */
15
15
  export type FileHistoryTrackKeyResolution = {
16
16
  ok: true;
17
17
  abs: string;
18
18
  } | {
19
19
  ok: false;
20
20
  reason: string;
21
+ class: "key_unresolvable";
21
22
  };
23
+ /**
24
+ * Why a restore declined a file it could reach — the `class` of every {@link FileHistoryRestoreResult.refused}
25
+ * row, named by the arm that decided the refusal (the shared env half and key resolver below, or a backend's
26
+ * own base-unavailable arm) and copied by the backend, never re-derived from the reason text:
27
+ * · `link_safety` — the object at the path is not the regular file the record describes (a symlink, a
28
+ * directory or other kind), its parent chain no longer resolves to the recorded identity, or a guarded
29
+ * write found the path changed under it;
30
+ * · `base_unavailable` — the first touch recorded that the path's pre-edit bytes could not be read (DV-14),
31
+ * so there is no pristine version to write;
32
+ * · `key_unresolvable` — the recorded key cannot be re-joined against this root (it would escape it, or it
33
+ * came from another path family and is absolute or ambiguous here).
34
+ * Damage to the store's own records (a missing version record, a missing or corrupt blob) is not a refusal
35
+ * in any backend: it is a `failed` row.
36
+ */
37
+ export declare const FILE_HISTORY_REFUSAL_CLASSES: readonly ["link_safety", "base_unavailable", "key_unresolvable"];
38
+ export type FileHistoryRefusalClass = (typeof FILE_HISTORY_REFUSAL_CLASSES)[number];
22
39
  /** The path family a track key was MINTED under — the half a bare key string cannot carry. */
23
40
  export type FileHistoryKeyFamily = "posix" | "win";
24
41
  /**
@@ -83,12 +100,18 @@ export declare const FILE_HISTORY_ERROR_CODES: readonly ["track_failed", "snapsh
83
100
  export interface FileHistoryError {
84
101
  /** `not_found` = no boundary for that (scope, entryId) — an absence, never a fault (a boundary that is there
85
102
  * but cannot be read is the verb's `*_failed` with the fault); `aborted` = the signal fired (or the
86
- * fencing discarded a timed-out attempt); `conflict` = a non-destructive-target law refused
87
- * (adopt/import onto a scope with its own history) — and ONLY that, because a caller decides
88
- * whether to stay quiet on it: the engine's fork-carry seat treats `conflict` as "already carried,
89
- * or grown its own" and says nothing, so an adoption that failed for any OTHER reason (a corrupt
90
- * source graph, a blob it cannot reach, a consumed-id ledger it cannot carry, a target whose
91
- * history cannot be judged) must NOT wear this
103
+ * fencing discarded a timed-out attempt); `conflict` = a HISTORY-PRESERVATION law refused the call:
104
+ * doing it would discard or overwrite history that is not the caller's — `adoptScope` / `importHistory`
105
+ * onto a target that holds history of its own (the non-destructive-target law), or `annulTrack` of a
106
+ * record that is no longer just the caller's own mint (a boundary froze it, it grew past its first
107
+ * version, another edit was served it, or the proof read found the file moved or the base-unavailable
108
+ * marker standing). It is never a fault, and it is never "could not judge": a verb that cannot JUDGE its
109
+ * law (an unreadable graph, a listing that fails, a proof read that cannot re-read the path) answers its
110
+ * own `*_failed` (or `aborted`) with the fault. A caller reads `conflict` as "the law answered; the history
111
+ * stands" — the engine's fork-carry seat says nothing on it because the only verb that seat calls is
112
+ * `adoptScope`, whose `conflict` is the target law alone, so an adoption that failed for any OTHER
113
+ * reason (a corrupt source graph, a blob it cannot reach, a consumed-id ledger it cannot carry, a target
114
+ * whose history cannot be judged) must NOT wear this
92
115
  * code or the failure disappears into that silence — those are `adopt_failed`, which the
93
116
  * ADOPTION FAMILY shares: `importHistory` publishes under the same target law and answers the
94
117
  * same code for the same non-conflict failures, and `exportHistory` answers it for a history it cannot
@@ -172,10 +195,12 @@ export type FileHistoryRestoreResult = {
172
195
  filesChanged: string[];
173
196
  /** Track keys already equal to the target (untouched — content-hash proven, never mtime). */
174
197
  identicalSkipped: string[];
175
- /** Per-file security/consistency refusals (skipped, counted, never failing the whole restore). */
198
+ /** Per-file security/consistency refusals (skipped, counted, never failing the whole restore); `class` is
199
+ * the closed reading of why ({@link FileHistoryRefusalClass}), `reason` the sentence for a person. */
176
200
  refused: Array<{
177
201
  path: string;
178
202
  reason: string;
203
+ class: FileHistoryRefusalClass;
179
204
  }>;
180
205
  /** Per-file operational failures (env write/remove errors, aborts after k writes). */
181
206
  failed: Array<{
@@ -192,6 +217,34 @@ export interface FileHistoryDiffStats {
192
217
  insertions: number;
193
218
  deletions: number;
194
219
  }
220
+ /** `Runner.rewindFiles`' request — the out-of-run code-only rewind (the reference's `rewind_files` control request). */
221
+ export interface RewindFilesRequest {
222
+ /** The session whose history is converged. It must exist. */
223
+ sessionId: string;
224
+ /** The boundary key: the entry id of a turn's FIRST user entry — the id space `TaskSpec.rewindFilesTo`
225
+ * addresses ("the files as they were when that turn began"). An entry with no boundary of its own refuses. */
226
+ to: string;
227
+ /** Preview only: the working tree is not written (a fork whose history was never carried may have its carry
228
+ * completed — the same carry the session's next run performs). */
229
+ dryRun?: boolean;
230
+ /** Caller cancel for the restore. */
231
+ signal?: AbortSignal;
232
+ }
233
+ /** `Runner.rewindFiles`' answer. A refusal is a thrown `Error` carrying a `code`. */
234
+ export type RewindFilesResult =
235
+ /** `preview: null` = no preview for this request (the backend implements no `diffStats`, or answered none);
236
+ * an empty `filesChanged` with zero counts = a real "nothing would change". */
237
+ {
238
+ dryRun: true;
239
+ preview: FileHistoryDiffStats | null;
240
+ }
241
+ /** The store's ledger as it answered: `complete`, or `partial` with every refused / failed file on it. */
242
+ | {
243
+ dryRun: false;
244
+ restore: FileHistoryRestoreResult & {
245
+ outcome: "complete" | "partial";
246
+ };
247
+ };
195
248
  /** The line-diff bound (see {@link countRestoreLineDiff}): a pair whose edit distance exceeds this
196
249
  * is counted as a whole-file replacement. Public so a preview UI can state what it is showing. */
197
250
  export declare const FILE_HISTORY_DIFF_LINE_BUDGET = 2000;
@@ -345,7 +398,9 @@ export interface FileHistoryStore {
345
398
  * still matches what the mint recorded (bytes still absent for an existed-not mint, still the same
346
399
  * hash for a captured one). A file that changed keeps its record, because the alternative is
347
400
  * deleting the only baseline of a file the agent really did modify — damage rewind could no longer
348
- * reach, which is strictly worse than a stale record.
401
+ * reach, which is strictly worse than a stale record. Every refusal above is the history-preservation
402
+ * law (`conflict`, see {@link FileHistoryError.code}); a proof read that cannot re-read the path at all
403
+ * judged nothing, and keeps the record with `track_failed` (`aborted` when the signal fired) instead.
349
404
  */
350
405
  annulTrack(scope: string, absPath: string, root: string, verify?: {
351
406
  env: ExecutionEnv;
@@ -600,13 +655,30 @@ export declare function captureFileBackupViaEnv(env: ExecutionEnv, absPath: stri
600
655
  * refusal state that stops a later touch from minting already-modified bytes as pristine — erasing
601
656
  * it on an ambiguous failure re-opens exactly the DV-14 hole it exists to close. It stays
602
657
  * retractable through the `"proven"` path, which needs no evidence read at all.
658
+ *
659
+ * THREE verdicts, because a backend answers them three ways: `unchanged` retracts; `kept` is the
660
+ * history-preservation law keeping the record (`conflict`); `unjudged` is a read that never happened —
661
+ * the path could not be re-read, or the signal fired — so nothing was judged and the record stays with
662
+ * the verb's own failure (`track_failed`, or `aborted` when `aborted` is true), never with the law's word.
603
663
  */
604
- export declare function worldStillMatchesMint(env: ExecutionEnv, absPath: string, root: string, baseAvailable: boolean, mintedBlobHash: string | null, signal?: AbortSignal): Promise<{
605
- unchanged: true;
664
+ export type FileHistoryMintProof = {
665
+ verdict: "unchanged";
606
666
  } | {
607
- unchanged: false;
667
+ verdict: "kept";
608
668
  reason: string;
609
- }>;
669
+ } | {
670
+ verdict: "unjudged";
671
+ reason: string;
672
+ aborted: boolean;
673
+ };
674
+ export declare function worldStillMatchesMint(env: ExecutionEnv, absPath: string, root: string, baseAvailable: boolean, mintedBlobHash: string | null, signal?: AbortSignal): Promise<FileHistoryMintProof>;
675
+ /** A backend's ONE mapping of a proof that did not say `unchanged` onto the annul verb's failure — the two
676
+ * bundled backends call it, and an out-of-tree backend reuses it with the proof read itself. */
677
+ export declare function annulProofFailure(proof: Exclude<FileHistoryMintProof, {
678
+ verdict: "unchanged";
679
+ }>, absPath: string): FileHistoryResult & {
680
+ ok: false;
681
+ };
610
682
  /**
611
683
  * DV-13's metadata rule applied to the MODE axis (design/381 slice 3), and it is a rule about
612
684
  * EVIDENCE rather than about equality: metadata may prove two states DIFFERENT, never the same. Two
@@ -649,9 +721,13 @@ export type FileRestoreApplyOutcome =
649
721
  } | {
650
722
  outcome: "identical";
651
723
  modeNotPreserved?: true;
652
- } | {
724
+ }
725
+ /** Every refusal this half decides is about the object at the path (its kind, its parent chain, a guarded
726
+ * write's precondition), so its class is `link_safety`; a backend copies it into the ledger row. */
727
+ | {
653
728
  outcome: "refused";
654
729
  reason: string;
730
+ class: "link_safety";
655
731
  } | {
656
732
  outcome: "failed";
657
733
  reason: string;
@@ -32,6 +32,7 @@ function parentDirOf(absPath) {
32
32
  const parent = cut.slice(0, i);
33
33
  return win ? parent.replace(/\//g, "\\") : parent;
34
34
  }
35
+ export const FILE_HISTORY_REFUSAL_CLASSES = Object.freeze(["link_safety", "base_unavailable", "key_unresolvable"]);
35
36
  export function trackKeyFamilyOf(root) {
36
37
  return isWinFormPath(root) ? "win" : "posix";
37
38
  }
@@ -53,17 +54,17 @@ export function resolveTrackKey(root, key, minted) {
53
54
  const win = isWinFormPath(root);
54
55
  if (minted !== undefined && minted.family !== trackKeyFamilyOf(root)) {
55
56
  if (minted.kind === "absolute") {
56
- return { ok: false, reason: `foreign-family absolute key cannot be restored here (recorded under a ${minted.family} root, this root is ${trackKeyFamilyOf(root)}): ${key}` };
57
+ return { ok: false, reason: `foreign-family absolute key cannot be restored here (recorded under a ${minted.family} root, this root is ${trackKeyFamilyOf(root)}): ${key}`, class: "key_unresolvable" };
57
58
  }
58
59
  if (isUnsafeRelPathLike(normSlash(key)) || key.includes("\\")) {
59
- return { ok: false, reason: `foreign-family key is ambiguous across path families (recorded under a ${minted.family} root, this root is ${trackKeyFamilyOf(root)}): ${key}` };
60
+ return { ok: false, reason: `foreign-family key is ambiguous across path families (recorded under a ${minted.family} root, this root is ${trackKeyFamilyOf(root)}): ${key}`, class: "key_unresolvable" };
60
61
  }
61
62
  }
62
63
  const keyN = win ? normSlash(key) : key;
63
64
  if (isAbsoluteForFamily(pathFamilyOf({ root }), keyN) || (win && /^[A-Za-z]:/.test(keyN)))
64
65
  return { ok: true, abs: key };
65
66
  if (win ? isUnsafeRelPathLike(keyN) : keyN.split("/").includes(".."))
66
- return { ok: false, reason: `unsafe recorded key escapes root: ${key}` };
67
+ return { ok: false, reason: `unsafe recorded key escapes root: ${key}`, class: "key_unresolvable" };
67
68
  return { ok: true, abs: joinUnder(root, keyN) };
68
69
  }
69
70
  export const FILE_HISTORY_ERROR_CODES = Object.freeze(["track_failed", "snapshot_failed", "restore_failed", "adopt_failed", "not_found", "aborted", "unsupported_format", "conflict"]);
@@ -272,18 +273,24 @@ export async function captureFileBackupViaEnv(env, absPath, root, signal) {
272
273
  }
273
274
  export async function worldStillMatchesMint(env, absPath, root, baseAvailable, mintedBlobHash, signal) {
274
275
  if (!baseAvailable) {
275
- return { unchanged: false, reason: "the first touch recorded a base-UNAVAILABLE marker, whose whole purpose is to refuse a fake pristine later — an ambiguous failure may not erase it" };
276
+ return { verdict: "kept", reason: "the first touch recorded a base-UNAVAILABLE marker, whose whole purpose is to refuse a fake pristine later — an ambiguous failure may not erase it" };
276
277
  }
277
278
  const cap = await captureFileBackupViaEnv(env, absPath, root, signal);
278
279
  if (cap.state === "absent") {
279
- return mintedBlobHash === null ? { unchanged: true } : { unchanged: false, reason: "the file recorded at the first touch is gone now" };
280
+ return mintedBlobHash === null ? { verdict: "unchanged" } : { verdict: "kept", reason: "the file recorded at the first touch is gone now" };
280
281
  }
281
282
  if (cap.state === "file") {
282
283
  if (mintedBlobHash === null)
283
- return { unchanged: false, reason: "the path was recorded as NOT EXISTING at the first touch but holds bytes now" };
284
- return cap.hash === mintedBlobHash ? { unchanged: true } : { unchanged: false, reason: "the file's bytes differ from the ones recorded at the first touch" };
284
+ return { verdict: "kept", reason: "the path was recorded as NOT EXISTING at the first touch but holds bytes now" };
285
+ return cap.hash === mintedBlobHash ? { verdict: "unchanged" } : { verdict: "kept", reason: "the file's bytes differ from the ones recorded at the first touch" };
285
286
  }
286
- return { unchanged: false, reason: `the path could not be re-read to prove it is unchanged (${cap.state === "aborted" ? "aborted" : cap.cause})` };
287
+ return { verdict: "unjudged", reason: `the path could not be re-read to prove it is unchanged (${cap.state === "aborted" ? "aborted" : cap.cause})`, aborted: cap.state === "aborted" };
288
+ }
289
+ export function annulProofFailure(proof, absPath) {
290
+ if (proof.verdict === "kept") {
291
+ 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, and deleting the only baseline of a modified file is worse than keeping a stale record` } };
292
+ }
293
+ return { ok: false, error: { code: proof.aborted ? "aborted" : "track_failed", message: `first-touch record for ${absPath} was left in place: ${proof.reason}, so whether the write this retraction compensates for changed the file was not judged` } };
287
294
  }
288
295
  export function modeProvenDifferent(recorded, current) {
289
296
  return recorded !== undefined && current !== undefined && recorded !== current;
@@ -317,7 +324,7 @@ export async function applyFileRestoreViaEnv(env, absPath, target, opts) {
317
324
  }
318
325
  const w = await writeRestoredBytes(env, absPath, target.bytes, signal);
319
326
  if (!w.ok)
320
- return { outcome: w.refused ? "refused" : "failed", reason: `write: ${w.code}` };
327
+ return w.refused ? { outcome: "refused", reason: `write: ${w.code}`, class: "link_safety" } : { outcome: "failed", reason: `write: ${w.code}` };
321
328
  const modeAfter = await applyRecordedMode(env, absPath, opts, undefined);
322
329
  return { outcome: "applied", ...(modeAfter === "unpreserved" || modeAfter === "applied_unpreserved" ? { modeNotPreserved: true } : {}) };
323
330
  }
@@ -330,6 +337,7 @@ async function restorePreflight(env, absPath, opts) {
330
337
  reason: info.value.kind === "symlink"
331
338
  ? "restore target is a SYMLINK — the recorded bytes belong to the file that was edited, not to whatever the link now points at"
332
339
  : `restore target is a ${info.value.kind}, not a regular file — the recorded bytes are not this object's`,
340
+ class: "link_safety",
333
341
  },
334
342
  };
335
343
  }
@@ -345,6 +353,7 @@ async function restorePreflight(env, absPath, opts) {
345
353
  refused: {
346
354
  outcome: "refused",
347
355
  reason: `restore target's parent chain changed identity since it was recorded (recorded ${JSON.stringify(opts.parentIdent)}, now ${JSON.stringify(now)}) — writing here could land outside the task root`,
356
+ class: "link_safety",
348
357
  },
349
358
  };
350
359
  }
@@ -542,9 +551,8 @@ export class InMemoryFileHistoryStore {
542
551
  if (before !== undefined)
543
552
  return { ok: false, error: { code: "conflict", message: before } };
544
553
  const proof = verify === undefined ? undefined : await worldStillMatchesMint(verify.env, absPath, root, t.baseAvailable, t.versions[0]?.blobHash ?? null, verify.signal);
545
- if (proof !== undefined && !proof.unchanged) {
546
- 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, and deleting the only baseline of a modified file is worse than keeping a stale record` } };
547
- }
554
+ if (proof !== undefined && proof.verdict !== "unchanged")
555
+ return annulProofFailure(proof, absPath);
548
556
  const after = ineligible();
549
557
  if (after !== undefined)
550
558
  return { ok: false, error: { code: "conflict", message: after } };
@@ -655,7 +663,7 @@ export class InMemoryFileHistoryStore {
655
663
  let targetVersion = boundary.get(key);
656
664
  if (targetVersion === undefined) {
657
665
  if (!t.baseAvailable) {
658
- ledger.refused.push({ path: key, reason: "base_unavailable" });
666
+ ledger.refused.push({ path: key, reason: "base_unavailable", class: "base_unavailable" });
659
667
  continue;
660
668
  }
661
669
  targetVersion = 1;
@@ -667,7 +675,7 @@ export class InMemoryFileHistoryStore {
667
675
  }
668
676
  const resolved = resolveTrackKey(root, key, t.keyDesc);
669
677
  if (!resolved.ok) {
670
- ledger.refused.push({ path: key, reason: resolved.reason });
678
+ ledger.refused.push({ path: key, reason: resolved.reason, class: resolved.class });
671
679
  continue;
672
680
  }
673
681
  let target;
@@ -698,7 +706,7 @@ export class InMemoryFileHistoryStore {
698
706
  else if (applied.outcome === "identical")
699
707
  ledger.identicalSkipped.push(key);
700
708
  else if (applied.outcome === "refused")
701
- ledger.refused.push({ path: key, reason: applied.reason });
709
+ ledger.refused.push({ path: key, reason: applied.reason, class: applied.class });
702
710
  else
703
711
  ledger.failed.push({ path: key, reason: applied.reason });
704
712
  if ((applied.outcome === "applied" || applied.outcome === "identical") && applied.modeNotPreserved === true)
@@ -1,4 +1,4 @@
1
- import type { GatePass } from "./runner/gate-exit.js";
1
+ import { type GatePass } from "./runner/gate-exit.js";
2
2
  import type { ToolGateResult } from "./hooks.js";
3
3
  /**
4
4
  * Run the fold over the pass: adjudicate, fold the hook-ask, tighten. Writes `req` (re-minted over the FINAL