wingfoil 0.2.2 → 0.3.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 (454) hide show
  1. package/README.md +83 -43
  2. package/dist/agent/discovery.d.ts +72 -0
  3. package/dist/agent/discovery.d.ts.map +1 -0
  4. package/dist/agent/discovery.js +210 -0
  5. package/dist/agent/discovery.js.map +1 -0
  6. package/dist/agent/execute.d.ts +206 -0
  7. package/dist/agent/execute.d.ts.map +1 -0
  8. package/dist/agent/execute.js +581 -0
  9. package/dist/agent/execute.js.map +1 -0
  10. package/dist/agent/index.d.ts +23 -0
  11. package/dist/agent/index.d.ts.map +1 -0
  12. package/dist/agent/index.js +85 -0
  13. package/dist/agent/index.js.map +1 -0
  14. package/dist/agent/launch.d.ts +133 -0
  15. package/dist/agent/launch.d.ts.map +1 -0
  16. package/dist/agent/launch.js +380 -0
  17. package/dist/agent/launch.js.map +1 -0
  18. package/dist/agent/manifest.d.ts +30 -0
  19. package/dist/agent/manifest.d.ts.map +1 -0
  20. package/dist/agent/manifest.js +93 -0
  21. package/dist/agent/manifest.js.map +1 -0
  22. package/dist/agent/placeholders.d.ts +49 -0
  23. package/dist/agent/placeholders.d.ts.map +1 -0
  24. package/dist/agent/placeholders.js +177 -0
  25. package/dist/agent/placeholders.js.map +1 -0
  26. package/dist/agent/run-log.d.ts +254 -0
  27. package/dist/agent/run-log.d.ts.map +1 -0
  28. package/dist/agent/run-log.js +612 -0
  29. package/dist/agent/run-log.js.map +1 -0
  30. package/dist/agent/schema.d.ts +100 -0
  31. package/dist/agent/schema.d.ts.map +1 -0
  32. package/dist/agent/schema.js +89 -0
  33. package/dist/agent/schema.js.map +1 -0
  34. package/dist/agent/step.d.ts +41 -0
  35. package/dist/agent/step.d.ts.map +1 -0
  36. package/dist/agent/step.js +95 -0
  37. package/dist/agent/step.js.map +1 -0
  38. package/dist/build-info.json +4 -0
  39. package/dist/cli/error.d.ts +11 -2
  40. package/dist/cli/error.d.ts.map +1 -1
  41. package/dist/cli/error.js +27 -6
  42. package/dist/cli/error.js.map +1 -1
  43. package/dist/cli/exit.d.ts +33 -3
  44. package/dist/cli/exit.d.ts.map +1 -1
  45. package/dist/cli/exit.js +54 -3
  46. package/dist/cli/exit.js.map +1 -1
  47. package/dist/cli/index.d.ts +1 -1
  48. package/dist/cli/index.d.ts.map +1 -1
  49. package/dist/cli/index.js +2 -1
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/cli/init-command.d.ts.map +1 -1
  52. package/dist/cli/init-command.js +4 -2
  53. package/dist/cli/init-command.js.map +1 -1
  54. package/dist/cli/mcp-command.d.ts +13 -4
  55. package/dist/cli/mcp-command.d.ts.map +1 -1
  56. package/dist/cli/mcp-command.js +25 -8
  57. package/dist/cli/mcp-command.js.map +1 -1
  58. package/dist/cli/output.d.ts +12 -4
  59. package/dist/cli/output.d.ts.map +1 -1
  60. package/dist/cli/output.js +15 -4
  61. package/dist/cli/output.js.map +1 -1
  62. package/dist/cli/program.d.ts +1 -1
  63. package/dist/cli/program.d.ts.map +1 -1
  64. package/dist/cli/program.js +162 -40
  65. package/dist/cli/program.js.map +1 -1
  66. package/dist/cli/registrar.d.ts +1 -1
  67. package/dist/cli/registrar.d.ts.map +1 -1
  68. package/dist/cli/registrar.js +67 -6
  69. package/dist/cli/registrar.js.map +1 -1
  70. package/dist/cli/suggest.d.ts +20 -0
  71. package/dist/cli/suggest.d.ts.map +1 -0
  72. package/dist/cli/suggest.js +49 -0
  73. package/dist/cli/suggest.js.map +1 -0
  74. package/dist/cli/warning.d.ts +26 -0
  75. package/dist/cli/warning.d.ts.map +1 -0
  76. package/dist/cli/warning.js +66 -0
  77. package/dist/cli/warning.js.map +1 -0
  78. package/dist/cli.js +11 -2
  79. package/dist/cli.js.map +1 -1
  80. package/dist/core/agent-execute.d.ts +44 -0
  81. package/dist/core/agent-execute.d.ts.map +1 -0
  82. package/dist/core/agent-execute.js +71 -0
  83. package/dist/core/agent-execute.js.map +1 -0
  84. package/dist/core/agent-list.d.ts +95 -0
  85. package/dist/core/agent-list.d.ts.map +1 -0
  86. package/dist/core/agent-list.js +207 -0
  87. package/dist/core/agent-list.js.map +1 -0
  88. package/dist/core/agent-show.d.ts +44 -0
  89. package/dist/core/agent-show.d.ts.map +1 -0
  90. package/dist/core/agent-show.js +188 -0
  91. package/dist/core/agent-show.js.map +1 -0
  92. package/dist/core/approval-authority.d.ts +17 -14
  93. package/dist/core/approval-authority.d.ts.map +1 -1
  94. package/dist/core/approval-authority.js +9 -9
  95. package/dist/core/approval-authority.js.map +1 -1
  96. package/dist/core/builtin-asset.d.ts +18 -15
  97. package/dist/core/builtin-asset.d.ts.map +1 -1
  98. package/dist/core/builtin-asset.js +17 -14
  99. package/dist/core/builtin-asset.js.map +1 -1
  100. package/dist/core/builtin-integrity.d.ts +12 -2
  101. package/dist/core/builtin-integrity.d.ts.map +1 -1
  102. package/dist/core/builtin-integrity.js +85 -9
  103. package/dist/core/builtin-integrity.js.map +1 -1
  104. package/dist/core/confinement.d.ts +3 -1
  105. package/dist/core/confinement.d.ts.map +1 -1
  106. package/dist/core/confinement.js +7 -4
  107. package/dist/core/confinement.js.map +1 -1
  108. package/dist/core/context.d.ts +150 -98
  109. package/dist/core/context.d.ts.map +1 -1
  110. package/dist/core/context.js +602 -66
  111. package/dist/core/context.js.map +1 -1
  112. package/dist/core/directive-assign.d.ts +33 -7
  113. package/dist/core/directive-assign.d.ts.map +1 -1
  114. package/dist/core/directive-assign.js +67 -27
  115. package/dist/core/directive-assign.js.map +1 -1
  116. package/dist/core/directive-scope.d.ts +36 -0
  117. package/dist/core/directive-scope.d.ts.map +1 -0
  118. package/dist/core/directive-scope.js +34 -0
  119. package/dist/core/directive-scope.js.map +1 -0
  120. package/dist/core/directives-list.d.ts +13 -3
  121. package/dist/core/directives-list.d.ts.map +1 -1
  122. package/dist/core/directives-list.js +18 -6
  123. package/dist/core/directives-list.js.map +1 -1
  124. package/dist/core/dry-run.d.ts +33 -0
  125. package/dist/core/dry-run.d.ts.map +1 -0
  126. package/dist/core/dry-run.js +45 -0
  127. package/dist/core/dry-run.js.map +1 -0
  128. package/dist/core/element-ref.d.ts +23 -0
  129. package/dist/core/element-ref.d.ts.map +1 -0
  130. package/dist/core/element-ref.js +24 -0
  131. package/dist/core/element-ref.js.map +1 -0
  132. package/dist/core/error-details.d.ts +20 -0
  133. package/dist/core/error-details.d.ts.map +1 -0
  134. package/dist/core/error-details.js +65 -0
  135. package/dist/core/error-details.js.map +1 -0
  136. package/dist/core/exit-code.d.ts.map +1 -1
  137. package/dist/core/exit-code.js +6 -7
  138. package/dist/core/exit-code.js.map +1 -1
  139. package/dist/core/git-identity.d.ts +46 -11
  140. package/dist/core/git-identity.d.ts.map +1 -1
  141. package/dist/core/git-identity.js +140 -27
  142. package/dist/core/git-identity.js.map +1 -1
  143. package/dist/core/index.d.ts +184 -10
  144. package/dist/core/index.d.ts.map +1 -1
  145. package/dist/core/index.js +1045 -185
  146. package/dist/core/index.js.map +1 -1
  147. package/dist/core/init.d.ts +45 -5
  148. package/dist/core/init.d.ts.map +1 -1
  149. package/dist/core/init.js +134 -24
  150. package/dist/core/init.js.map +1 -1
  151. package/dist/core/loaders.d.ts +170 -14
  152. package/dist/core/loaders.d.ts.map +1 -1
  153. package/dist/core/loaders.js +570 -89
  154. package/dist/core/loaders.js.map +1 -1
  155. package/dist/core/memory-add-link.d.ts +28 -0
  156. package/dist/core/memory-add-link.d.ts.map +1 -0
  157. package/dist/core/memory-add-link.js +67 -0
  158. package/dist/core/memory-add-link.js.map +1 -0
  159. package/dist/core/memory-add-type.d.ts +25 -1
  160. package/dist/core/memory-add-type.d.ts.map +1 -1
  161. package/dist/core/memory-add-type.js +59 -1
  162. package/dist/core/memory-add-type.js.map +1 -1
  163. package/dist/core/memory-amend.d.ts +80 -0
  164. package/dist/core/memory-amend.d.ts.map +1 -0
  165. package/dist/core/memory-amend.js +160 -0
  166. package/dist/core/memory-amend.js.map +1 -0
  167. package/dist/core/memory-supersede.d.ts +28 -0
  168. package/dist/core/memory-supersede.d.ts.map +1 -0
  169. package/dist/core/memory-supersede.js +79 -0
  170. package/dist/core/memory-supersede.js.map +1 -0
  171. package/dist/core/memory-transition.d.ts +190 -30
  172. package/dist/core/memory-transition.d.ts.map +1 -1
  173. package/dist/core/memory-transition.js +480 -59
  174. package/dist/core/memory-transition.js.map +1 -1
  175. package/dist/core/registry.d.ts +82 -10
  176. package/dist/core/registry.d.ts.map +1 -1
  177. package/dist/core/registry.js +50 -0
  178. package/dist/core/registry.js.map +1 -1
  179. package/dist/core/relevance.d.ts +74 -12
  180. package/dist/core/relevance.d.ts.map +1 -1
  181. package/dist/core/relevance.js +45 -27
  182. package/dist/core/relevance.js.map +1 -1
  183. package/dist/core/require-reason.d.ts.map +1 -1
  184. package/dist/core/require-reason.js +6 -5
  185. package/dist/core/require-reason.js.map +1 -1
  186. package/dist/core/required-fields.d.ts +28 -0
  187. package/dist/core/required-fields.d.ts.map +1 -0
  188. package/dist/core/required-fields.js +60 -0
  189. package/dist/core/required-fields.js.map +1 -0
  190. package/dist/core/revision.d.ts +82 -0
  191. package/dist/core/revision.d.ts.map +1 -0
  192. package/dist/core/revision.js +144 -0
  193. package/dist/core/revision.js.map +1 -0
  194. package/dist/core/types.d.ts +28 -2
  195. package/dist/core/types.d.ts.map +1 -1
  196. package/dist/core/types.js +12 -3
  197. package/dist/core/types.js.map +1 -1
  198. package/dist/core/workflow-core-checks.d.ts +34 -0
  199. package/dist/core/workflow-core-checks.d.ts.map +1 -0
  200. package/dist/core/workflow-core-checks.js +403 -0
  201. package/dist/core/workflow-core-checks.js.map +1 -0
  202. package/dist/core/workflow-create-remove.d.ts +65 -0
  203. package/dist/core/workflow-create-remove.d.ts.map +1 -0
  204. package/dist/core/workflow-create-remove.js +277 -0
  205. package/dist/core/workflow-create-remove.js.map +1 -0
  206. package/dist/core/workflow-deduction.d.ts +48 -0
  207. package/dist/core/workflow-deduction.d.ts.map +1 -0
  208. package/dist/core/workflow-deduction.js +523 -0
  209. package/dist/core/workflow-deduction.js.map +1 -0
  210. package/dist/core/workflow-diagnostics.d.ts +83 -0
  211. package/dist/core/workflow-diagnostics.d.ts.map +1 -0
  212. package/dist/core/workflow-diagnostics.js +375 -0
  213. package/dist/core/workflow-diagnostics.js.map +1 -0
  214. package/dist/core/workflow-exit-state.d.ts +125 -0
  215. package/dist/core/workflow-exit-state.d.ts.map +1 -0
  216. package/dist/core/workflow-exit-state.js +243 -0
  217. package/dist/core/workflow-exit-state.js.map +1 -0
  218. package/dist/core/workflow-finalize.d.ts +37 -0
  219. package/dist/core/workflow-finalize.d.ts.map +1 -0
  220. package/dist/core/workflow-finalize.js +153 -0
  221. package/dist/core/workflow-finalize.js.map +1 -0
  222. package/dist/core/workflow-list-show.d.ts +176 -0
  223. package/dist/core/workflow-list-show.d.ts.map +1 -0
  224. package/dist/core/workflow-list-show.js +268 -0
  225. package/dist/core/workflow-list-show.js.map +1 -0
  226. package/dist/core/workflow-next.d.ts +268 -0
  227. package/dist/core/workflow-next.d.ts.map +1 -0
  228. package/dist/core/workflow-next.js +503 -0
  229. package/dist/core/workflow-next.js.map +1 -0
  230. package/dist/core/workflow-registry.d.ts +52 -0
  231. package/dist/core/workflow-registry.d.ts.map +1 -0
  232. package/dist/core/workflow-registry.js +158 -0
  233. package/dist/core/workflow-registry.js.map +1 -0
  234. package/dist/core/workflow-start-end.d.ts +71 -0
  235. package/dist/core/workflow-start-end.d.ts.map +1 -0
  236. package/dist/core/workflow-start-end.js +298 -0
  237. package/dist/core/workflow-start-end.js.map +1 -0
  238. package/dist/core/workflow-status.d.ts +83 -0
  239. package/dist/core/workflow-status.d.ts.map +1 -0
  240. package/dist/core/workflow-status.js +125 -0
  241. package/dist/core/workflow-status.js.map +1 -0
  242. package/dist/core/write-guard.d.ts +51 -8
  243. package/dist/core/write-guard.d.ts.map +1 -1
  244. package/dist/core/write-guard.js +139 -9
  245. package/dist/core/write-guard.js.map +1 -1
  246. package/dist/directives/index.d.ts +3 -2
  247. package/dist/directives/index.d.ts.map +1 -1
  248. package/dist/directives/index.js +5 -3
  249. package/dist/directives/index.js.map +1 -1
  250. package/dist/directives/schema.d.ts +34 -29
  251. package/dist/directives/schema.d.ts.map +1 -1
  252. package/dist/directives/schema.js +35 -29
  253. package/dist/directives/schema.js.map +1 -1
  254. package/dist/directives/version.d.ts +28 -0
  255. package/dist/directives/version.d.ts.map +1 -0
  256. package/dist/directives/version.js +51 -0
  257. package/dist/directives/version.js.map +1 -0
  258. package/dist/dna/edit.d.ts +7 -6
  259. package/dist/dna/edit.d.ts.map +1 -1
  260. package/dist/dna/edit.js +96 -41
  261. package/dist/dna/edit.js.map +1 -1
  262. package/dist/dna/mutate.js +18 -3
  263. package/dist/dna/mutate.js.map +1 -1
  264. package/dist/dna/path.d.ts +2 -2
  265. package/dist/dna/roles.d.ts +1 -1
  266. package/dist/dna/schema.d.ts +61 -3
  267. package/dist/dna/schema.d.ts.map +1 -1
  268. package/dist/dna/schema.js +121 -6
  269. package/dist/dna/schema.js.map +1 -1
  270. package/dist/mcp/dna-resource.d.ts.map +1 -1
  271. package/dist/mcp/dna-resource.js +4 -4
  272. package/dist/mcp/dna-resource.js.map +1 -1
  273. package/dist/mcp/index.d.ts +8 -4
  274. package/dist/mcp/index.d.ts.map +1 -1
  275. package/dist/mcp/index.js +13 -2
  276. package/dist/mcp/index.js.map +1 -1
  277. package/dist/mcp/memory-resource.d.ts.map +1 -1
  278. package/dist/mcp/memory-resource.js +30 -19
  279. package/dist/mcp/memory-resource.js.map +1 -1
  280. package/dist/mcp/prompt.d.ts +61 -24
  281. package/dist/mcp/prompt.d.ts.map +1 -1
  282. package/dist/mcp/prompt.js +176 -47
  283. package/dist/mcp/prompt.js.map +1 -1
  284. package/dist/mcp/read-only.d.ts +39 -0
  285. package/dist/mcp/read-only.d.ts.map +1 -1
  286. package/dist/mcp/read-only.js +61 -0
  287. package/dist/mcp/read-only.js.map +1 -1
  288. package/dist/mcp/registrar.d.ts +10 -0
  289. package/dist/mcp/registrar.d.ts.map +1 -1
  290. package/dist/mcp/registrar.js +48 -12
  291. package/dist/mcp/registrar.js.map +1 -1
  292. package/dist/mcp/server.d.ts +21 -14
  293. package/dist/mcp/server.d.ts.map +1 -1
  294. package/dist/mcp/server.js +41 -15
  295. package/dist/mcp/server.js.map +1 -1
  296. package/dist/mcp/session-resource.d.ts +13 -0
  297. package/dist/mcp/session-resource.d.ts.map +1 -0
  298. package/dist/mcp/session-resource.js +65 -0
  299. package/dist/mcp/session-resource.js.map +1 -0
  300. package/dist/mcp/workflow-resource.d.ts +18 -0
  301. package/dist/mcp/workflow-resource.d.ts.map +1 -1
  302. package/dist/mcp/workflow-resource.js +37 -8
  303. package/dist/mcp/workflow-resource.js.map +1 -1
  304. package/dist/memory/add.d.ts +110 -24
  305. package/dist/memory/add.d.ts.map +1 -1
  306. package/dist/memory/add.js +251 -64
  307. package/dist/memory/add.js.map +1 -1
  308. package/dist/memory/audit.d.ts +152 -39
  309. package/dist/memory/audit.d.ts.map +1 -1
  310. package/dist/memory/audit.js +257 -103
  311. package/dist/memory/audit.js.map +1 -1
  312. package/dist/memory/commit-message.d.ts +60 -38
  313. package/dist/memory/commit-message.d.ts.map +1 -1
  314. package/dist/memory/commit-message.js +167 -21
  315. package/dist/memory/commit-message.js.map +1 -1
  316. package/dist/memory/entry.d.ts.map +1 -1
  317. package/dist/memory/entry.js +1 -2
  318. package/dist/memory/entry.js.map +1 -1
  319. package/dist/memory/frontmatter-edit.d.ts +16 -4
  320. package/dist/memory/frontmatter-edit.d.ts.map +1 -1
  321. package/dist/memory/frontmatter-edit.js +13 -1
  322. package/dist/memory/frontmatter-edit.js.map +1 -1
  323. package/dist/memory/git-log.d.ts +18 -6
  324. package/dist/memory/git-log.d.ts.map +1 -1
  325. package/dist/memory/git-log.js +40 -13
  326. package/dist/memory/git-log.js.map +1 -1
  327. package/dist/memory/history.d.ts +73 -12
  328. package/dist/memory/history.d.ts.map +1 -1
  329. package/dist/memory/history.js +128 -44
  330. package/dist/memory/history.js.map +1 -1
  331. package/dist/memory/index.d.ts +13 -11
  332. package/dist/memory/index.d.ts.map +1 -1
  333. package/dist/memory/index.js +34 -3
  334. package/dist/memory/index.js.map +1 -1
  335. package/dist/memory/query.d.ts +161 -19
  336. package/dist/memory/query.d.ts.map +1 -1
  337. package/dist/memory/query.js +435 -55
  338. package/dist/memory/query.js.map +1 -1
  339. package/dist/memory/schema.d.ts +52 -3
  340. package/dist/memory/schema.d.ts.map +1 -1
  341. package/dist/memory/schema.js +132 -8
  342. package/dist/memory/schema.js.map +1 -1
  343. package/dist/memory/state-machine.d.ts +65 -10
  344. package/dist/memory/state-machine.d.ts.map +1 -1
  345. package/dist/memory/state-machine.js +134 -46
  346. package/dist/memory/state-machine.js.map +1 -1
  347. package/dist/memory/submit.d.ts +52 -3
  348. package/dist/memory/submit.d.ts.map +1 -1
  349. package/dist/memory/submit.js +118 -11
  350. package/dist/memory/submit.js.map +1 -1
  351. package/dist/storage/build-stamp.d.ts +18 -0
  352. package/dist/storage/build-stamp.d.ts.map +1 -0
  353. package/dist/storage/build-stamp.js +68 -0
  354. package/dist/storage/build-stamp.js.map +1 -0
  355. package/dist/storage/builtin-adapters.d.ts +32 -0
  356. package/dist/storage/builtin-adapters.d.ts.map +1 -0
  357. package/dist/storage/builtin-adapters.js +100 -0
  358. package/dist/storage/builtin-adapters.js.map +1 -0
  359. package/dist/storage/builtin-directives.d.ts +0 -29
  360. package/dist/storage/builtin-directives.d.ts.map +1 -1
  361. package/dist/storage/builtin-directives.js +9 -4
  362. package/dist/storage/builtin-directives.js.map +1 -1
  363. package/dist/storage/commit.d.ts +310 -3
  364. package/dist/storage/commit.d.ts.map +1 -1
  365. package/dist/storage/commit.js +807 -33
  366. package/dist/storage/commit.js.map +1 -1
  367. package/dist/storage/document.d.ts +6 -0
  368. package/dist/storage/document.d.ts.map +1 -1
  369. package/dist/storage/document.js +10 -1
  370. package/dist/storage/document.js.map +1 -1
  371. package/dist/storage/dry-run.d.ts +65 -0
  372. package/dist/storage/dry-run.d.ts.map +1 -0
  373. package/dist/storage/dry-run.js +150 -0
  374. package/dist/storage/dry-run.js.map +1 -0
  375. package/dist/storage/errors.d.ts +26 -0
  376. package/dist/storage/errors.d.ts.map +1 -1
  377. package/dist/storage/errors.js +27 -1
  378. package/dist/storage/errors.js.map +1 -1
  379. package/dist/storage/frontmatter.d.ts +1 -1
  380. package/dist/storage/frontmatter.js +1 -1
  381. package/dist/storage/git-read.d.ts +64 -0
  382. package/dist/storage/git-read.d.ts.map +1 -0
  383. package/dist/storage/git-read.js +107 -0
  384. package/dist/storage/git-read.js.map +1 -0
  385. package/dist/storage/index.d.ts +13 -5
  386. package/dist/storage/index.d.ts.map +1 -1
  387. package/dist/storage/index.js +39 -2
  388. package/dist/storage/index.js.map +1 -1
  389. package/dist/storage/layout.d.ts +2 -2
  390. package/dist/storage/layout.d.ts.map +1 -1
  391. package/dist/storage/layout.js +2 -7
  392. package/dist/storage/layout.js.map +1 -1
  393. package/dist/storage/memory-path.d.ts +18 -5
  394. package/dist/storage/memory-path.d.ts.map +1 -1
  395. package/dist/storage/memory-path.js +41 -5
  396. package/dist/storage/memory-path.js.map +1 -1
  397. package/dist/storage/snapshot.js +1 -1
  398. package/dist/storage/templates.d.ts +33 -6
  399. package/dist/storage/templates.d.ts.map +1 -1
  400. package/dist/storage/templates.js +170 -16
  401. package/dist/storage/templates.js.map +1 -1
  402. package/dist/validation/config-version.d.ts +19 -0
  403. package/dist/validation/config-version.d.ts.map +1 -0
  404. package/dist/validation/config-version.js +53 -0
  405. package/dist/validation/config-version.js.map +1 -0
  406. package/dist/validation/diagnostic.d.ts +40 -0
  407. package/dist/validation/diagnostic.d.ts.map +1 -0
  408. package/dist/validation/diagnostic.js +41 -0
  409. package/dist/validation/diagnostic.js.map +1 -0
  410. package/dist/validation/format.d.ts +74 -0
  411. package/dist/validation/format.d.ts.map +1 -0
  412. package/dist/validation/format.js +104 -0
  413. package/dist/validation/format.js.map +1 -0
  414. package/dist/validation/id.d.ts +14 -0
  415. package/dist/validation/id.d.ts.map +1 -1
  416. package/dist/validation/id.js +35 -11
  417. package/dist/validation/id.js.map +1 -1
  418. package/dist/validation/identity.d.ts +40 -0
  419. package/dist/validation/identity.d.ts.map +1 -0
  420. package/dist/validation/identity.js +78 -0
  421. package/dist/validation/identity.js.map +1 -0
  422. package/dist/validation/index.d.ts +9 -3
  423. package/dist/validation/index.d.ts.map +1 -1
  424. package/dist/validation/index.js +30 -1
  425. package/dist/validation/index.js.map +1 -1
  426. package/dist/validation/secret-scan.d.ts +3 -2
  427. package/dist/validation/secret-scan.d.ts.map +1 -1
  428. package/dist/validation/secret-scan.js +32 -11
  429. package/dist/validation/secret-scan.js.map +1 -1
  430. package/dist/validation/warning.d.ts +30 -16
  431. package/dist/validation/warning.d.ts.map +1 -1
  432. package/dist/validation/warning.js +74 -7
  433. package/dist/validation/warning.js.map +1 -1
  434. package/dist/workflow/bindings.d.ts +152 -0
  435. package/dist/workflow/bindings.d.ts.map +1 -0
  436. package/dist/workflow/bindings.js +249 -0
  437. package/dist/workflow/bindings.js.map +1 -0
  438. package/dist/workflow/create.d.ts +13 -0
  439. package/dist/workflow/create.d.ts.map +1 -0
  440. package/dist/workflow/create.js +41 -0
  441. package/dist/workflow/create.js.map +1 -0
  442. package/dist/workflow/deduce.d.ts +400 -0
  443. package/dist/workflow/deduce.d.ts.map +1 -0
  444. package/dist/workflow/deduce.js +1109 -0
  445. package/dist/workflow/deduce.js.map +1 -0
  446. package/dist/workflow/manifest-edit.d.ts +19 -0
  447. package/dist/workflow/manifest-edit.d.ts.map +1 -0
  448. package/dist/workflow/manifest-edit.js +124 -0
  449. package/dist/workflow/manifest-edit.js.map +1 -0
  450. package/dist/workflow/schema.d.ts +158 -19
  451. package/dist/workflow/schema.d.ts.map +1 -1
  452. package/dist/workflow/schema.js +163 -15
  453. package/dist/workflow/schema.js.map +1 -1
  454. package/package.json +18 -8
@@ -1,31 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WIP_REFS_SENTENCE = void 0;
3
4
  exports.prepareMemoryTransition = prepareMemoryTransition;
5
+ exports.prepareMemoryTransitionAtRev = prepareMemoryTransitionAtRev;
6
+ exports.requireWipSlot = requireWipSlot;
7
+ exports.isMoreAdvancedState = isMoreAdvancedState;
8
+ exports.beginMemoryTransition = beginMemoryTransition;
4
9
  exports.verifyCommittedScope = verifyCommittedScope;
10
+ exports.checkMemoryTransition = checkMemoryTransition;
5
11
  exports.commitMemoryTransition = commitMemoryTransition;
6
12
  /**
7
13
  * The shared skeleton of every Memory state-transition verb (task-045-memory-submit; reused by
8
- * `memory approve`/`reject`/`deprecate`, task-046/047/048).
14
+ * `memory approve`/`reject`/`deprecate`, task-046/047/048, by `memory amend`, task-127, whose
15
+ * edge is the self-loop of the current state, and by `memory park`, task-180, which takes a declared
16
+ * `returns` edge).
9
17
  *
10
18
  * A transition verb always does the same two things around its own verb-specific rules:
11
19
  *
12
20
  * 1. {@link prepareMemoryTransition} — find the document by its bare id (spec-008-cli-grammar §7), read
13
- * its declared `type` and current `status`, and resolve the legal target for the verb **against the
14
- * `memory.yaml` committed at `HEAD`** (task-091, `bug-081`, `dl-080` (B)). Every expected
21
+ * its declared `type` and current `status`, and resolve the legal target for the verb, **all at
22
+ * `HEAD`**: the committed `memory.yaml` (task-091, `bug-081`, `dl-080` (B)) and the committed
23
+ * document (task-247, `bug-187`); the working tree supplies the content to commit and is checked to
24
+ * be the same element `HEAD` records. Every expected
15
25
  * refusal is returned as a `CoreResult.error` (exit `1`), **before anything is written**, so "the
16
26
  * state is unchanged" (P1.6 sc.2, REQ-STATE-01) holds by construction.
17
27
  * 2. {@link commitMemoryTransition} — write the new bytes and turn them into exactly one commit scoped
18
28
  * to that one document.
19
29
  *
20
30
  * What happens in between (required-field checks, which fields change, the commit message) is the
21
- * verb's own business; see `memorySubmitFn` in `./index.ts`.
31
+ * verb's own business; see `memorySubmitFn` in `./index.ts`. One verb makes a second commit: an
32
+ * approve that fires the `supersedes:` trigger (task-162, `./memory-supersede.ts`) prepares the
33
+ * superseded element with {@link prepareMemoryTransitionAtRev} at the approve's own sha and runs
34
+ * {@link checkMemoryTransition} on both documents before either commit.
22
35
  */
36
+ const fs_1 = require("fs");
23
37
  const path_1 = require("path");
24
38
  const memory_1 = require("../memory");
25
39
  const storage_1 = require("../storage");
26
40
  const validation_1 = require("../validation");
27
41
  const confinement_1 = require("./confinement");
42
+ const git_identity_1 = require("./git-identity");
28
43
  const loaders_1 = require("./loaders");
44
+ const revision_1 = require("./revision");
29
45
  const types_1 = require("./types");
30
46
  const write_guard_1 = require("./write-guard");
31
47
  /**
@@ -51,36 +67,137 @@ function uncommittedMachineNote(root) {
51
67
  `committed copy (dl-080); commit '${loaders_1.MEMORY_YAML_PATH}' first if this transition depends on that change`);
52
68
  }
53
69
  /**
54
- * Locate document `id` and resolve verb `op` on it, **against the `memory.yaml` committed at
55
- * `HEAD`** (`loadMemoryYamlAtHead`).
70
+ * A second sentence for `document not found` when the lookup at `HEAD` skipped documents it could not
71
+ * read (task-171): the id may be in one of them, so they are named as `HEAD:<path>`. Empty otherwise,
72
+ * so the pinned first sentence (P1.6 sc.3) is unchanged.
73
+ */
74
+ function unreadableNote(unreadable) {
75
+ if (unreadable.length === 0)
76
+ return '';
77
+ const named = unreadable.map((diagnostic) => `HEAD:${diagnostic.file} (${diagnostic.message.slice(diagnostic.message.indexOf(': ') + 2)})`);
78
+ return ` — it may be in a Memory document committed at HEAD that could not be read: ${named.join('; ')}`;
79
+ }
80
+ /**
81
+ * The refusal of a transition whose element is written in a `format` newer than this build reads
82
+ * (`dl-149`, task-257, `bug-241`): `VALIDATION`, exit `1`, before anything is written, carrying the
83
+ * loader's own `E_INVALID_FORMAT format (<file>): … upgrade WingFoil` text and naming which copy said so —
84
+ * `HEAD`'s, which decides, or the working tree's, which the verb would commit. Anything other than that
85
+ * refusal is rethrown.
86
+ */
87
+ function newerFormatRefusal(op, id, where, error) {
88
+ if (!(0, validation_1.isNewerFormatError)(error))
89
+ throw error;
90
+ return (0, types_1.coreErr)({
91
+ code: 'VALIDATION',
92
+ message: `refusing to ${op} ${id}: its document, as ${where} holds it, is written in a newer format: ${error.message}`,
93
+ details: { issues: error.issues },
94
+ });
95
+ }
96
+ /** Whether `full` names a directory entry at all — `lstat`, so a link is present even when dangling. */
97
+ function isPresent(full) {
98
+ try {
99
+ (0, fs_1.lstatSync)(full);
100
+ return true;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ /**
107
+ * The working-tree path of a document carrying frontmatter `id`, or `undefined` — read only to
108
+ * **explain** a refusal already decided at `HEAD`, never to decide one (the `command-baseline`
109
+ * directive: "the working tree may be read to explain a refusal, never to decide one"). A document
110
+ * elsewhere whose frontmatter does not parse is skipped by the scan (task-171), and any failure to
111
+ * walk the working tree yields `undefined`, so the refusal keeps its plain wording and no branch of
112
+ * this read can change an outcome.
113
+ */
114
+ function uncommittedDocumentPath(root, memoryYaml, id) {
115
+ // `followSymlinks`: this read only words a refusal, so it may follow a link the deciding scan skips
116
+ // (task-171, `bug-189`), and the confinement guards then refuse the link by name.
117
+ try {
118
+ return (0, memory_1.findMemoryDocumentById)(root, memoryYaml, id, { followSymlinks: true })?.path;
119
+ }
120
+ catch {
121
+ // Explain-only: a working tree the walk cannot read (an unreadable directory, `EACCES`) leaves
122
+ // the refusal its plain wording rather than becoming the outcome (task-171 re-review A).
123
+ return undefined;
124
+ }
125
+ }
126
+ /**
127
+ * The frontmatter `id` commit `sha` records for `path`, or `undefined` when the commit does not hold
128
+ * the path, or holds it with frontmatter that does not parse (the scan at the same sha skipped it,
129
+ * task-171). Like {@link uncommittedDocumentPath}, it only words a refusal, so no branch of it can
130
+ * change an outcome.
131
+ */
132
+ function recordedIdAt(root, sha, path) {
133
+ let id;
134
+ try {
135
+ id = (0, memory_1.loadMemoryDocumentSummaryAtRev)(root, sha, path)?.frontmatter.id;
136
+ }
137
+ catch {
138
+ // Explain-only: a document HEAD holds but cannot be read records no id to name.
139
+ return undefined;
140
+ }
141
+ return id === undefined ? undefined : String(id);
142
+ }
143
+ /**
144
+ * Locate document `id` and resolve verb `op` on it, **at `HEAD`**: the `memory.yaml`, the document
145
+ * the id names and its current `status` are all read from the one commit `HEAD` resolves to, once
146
+ * (`resolveRevision`, then `loadMemoryYamlAtRev` and `findMemoryDocumentByIdAtRev` at that sha).
147
+ *
148
+ * The baseline is the point (`spec-006-core-domain-api` §6 item 1, `dl-080` option (B)). This
149
+ * function takes no `MemoryYaml` and no document: a caller cannot hand it a working-tree machine or a
150
+ * working-tree `status` even by accident. Two defects motivated it. An uncommitted edit to a type's
151
+ * `sequence` used to decide the transition a verb performed (task-091, `bug-081`); and until task-247
152
+ * (`bug-187`) the id was looked up by scanning the working tree and `from` was the working-tree
153
+ * frontmatter's `status`, so an element already past `draft` at `HEAD` but edited back to `draft` on
154
+ * disk was submitted again, and a hand-made document no commit holds was transitioned as if `memory
155
+ * add` had registered it.
56
156
  *
57
- * The baseline is the point (task-091, `bug-081`, `dl-080` option (B)). This function takes no
58
- * `MemoryYaml`: a caller cannot hand it a working-tree machine even by accident, which is what makes
59
- * the committed baseline a property of the read itself rather than of a precondition someone must
60
- * remember to run. An uncommitted edit to a type's `sequence` used to decide both the transition a
61
- * verb performed and the `status` it committed — through `memory submit`, which requires no
62
- * authority — and stranded the element in a state the committed machine rejects.
157
+ * **Content from the working tree, state from `HEAD`.** The `content` and `frontmatter` this returns
158
+ * are the working tree's, because that is what `memory submit` and `memory amend` commit; `from`, the
159
+ * `type` and the target are `HEAD`'s. The working tree must still carry the same `id` and `type` the
160
+ * commit records — a verb decides on one element and writes that element.
63
161
  *
64
162
  * Refusals, all returned (never thrown) and all exit `1`:
65
163
  *
66
- * - `HEAD` holds no `memory.yaml` → `VALIDATION`, fail-closed: with no committed machine there is no
67
- * `from → to` to record, and the only fail-open available is the working tree, which is the defect.
68
- * `wingfoil init` commits the scaffold, so no legitimate flow reaches this;
164
+ * - `HEAD` holds no `memory.yaml` (or there is no commit) → `VALIDATION`, fail-closed: with no
165
+ * committed machine there is no `from → to` to record, and the only fail-open available is the
166
+ * working tree, which is the defect. `wingfoil init` commits the scaffold, so no legitimate flow
167
+ * reaches this;
69
168
  * - the committed `memory.yaml` does not parse or validate → `VALIDATION`, same reasoning;
70
- * - no document carries that frontmatter `id` → `NOT_FOUND` `document not found: <id>` (P1.6 sc.3);
169
+ * - no document at `HEAD` carries that frontmatter `id` → `NOT_FOUND` `document not found: <id>`
170
+ * (P1.6 sc.3); when a working-tree document carries it, the message says so and names `memory add`
171
+ * (task-247), since a transition acts only on an element a commit records — or, when `HEAD` holds
172
+ * that path under another id, `VALIDATION` naming the renamed `id` field;
173
+ * - `HEAD` holds the document but the working tree deleted it → `VALIDATION`, naming the path;
174
+ * - the working tree changes the document's `id` or `type` → `VALIDATION`;
71
175
  * - its `type` is not registered → `NOT_FOUND` with `memory add`'s unknown-type message;
72
- * - its `status` is not a state of the type → `VALIDATION` `invalid state '<s>' for type '<t>'`
73
- * (task-036's `validateFrontmatterState`);
176
+ * - its committed `status` is not a state of the type → `VALIDATION` `invalid state '<s>' for type
177
+ * '<t>'` (task-036's `validateFrontmatterState`);
74
178
  * - the verb is illegal from that state → `INVALID_TRANSITION` with the `dl-032` contract message
75
- * (`resolveTypeTransition`), the engine's explanation in `details.issues[0].detail`.
179
+ * (`resolveTypeTransition`), the engine's explanation in `details.issues[0].detail`. `amend`
180
+ * (task-127) never takes this branch: its target is the current state.
181
+ * - the document, as `HEAD` records it or as the working tree would have it committed, declares a
182
+ * `format` newer than this build reads → `VALIDATION` with the `dl-149` `E_INVALID_FORMAT` text, the
183
+ * file named (task-257, `bug-241`);
184
+ * - the target state declares a WIP limit its holders have reached → `CONFLICT`
185
+ * ({@link requireWipSlot}, task-180), the holders counted across every ref (task-274). Every
186
+ * transition into a state goes through here, so the limit holds whichever verb or engine action
187
+ * moves the element — except `reject` and `park`, which send it back along a reject or `returns`
188
+ * edge and are exempt (`dl-156` Q2 (i)).
76
189
  *
77
- * The last four keep their pinned messages verbatim as the first sentence;
78
- * {@link uncommittedMachineNote} may append a second one.
190
+ * The unknown-type, invalid-state and illegal-transition refusals keep their pinned messages
191
+ * verbatim as the first sentence; {@link uncommittedMachineNote} may append a second one.
79
192
  */
80
193
  function prepareMemoryTransition(root, id, op) {
194
+ // Resolved ONCE: every read below is at this sha, so the machine and the document cannot come from
195
+ // two commits even if `HEAD` moves while the verb runs (task-137). No commit at all is the same
196
+ // answer as a commit without `memory.yaml`.
197
+ const sha = (0, revision_1.atHeadOr)(root, () => (0, revision_1.resolveRevision)(root, 'HEAD'), null);
81
198
  let memoryYaml;
82
199
  try {
83
- memoryYaml = (0, loaders_1.loadMemoryYamlAtHead)(root);
200
+ memoryYaml = sha === null ? null : (0, loaders_1.loadMemoryYamlAtRev)(root, sha);
84
201
  }
85
202
  catch (error) {
86
203
  if (!(error instanceof validation_1.ValidationError))
@@ -93,18 +210,102 @@ function prepareMemoryTransition(root, id, op) {
93
210
  details: { issues: error.issues },
94
211
  });
95
212
  }
96
- if (memoryYaml === null) {
213
+ if (sha === null || memoryYaml === null) {
97
214
  return (0, types_1.coreErr)({
98
215
  code: 'VALIDATION',
99
216
  message: `cannot resolve the state machine: '${loaders_1.MEMORY_YAML_PATH}' is not committed at HEAD. A transition is decided by ` +
100
217
  `the machine the repository records, not by a working tree (dl-080); commit '${loaders_1.MEMORY_YAML_PATH}' first, then retry.`,
101
218
  });
102
219
  }
103
- const found = (0, memory_1.findMemoryDocumentById)(root, memoryYaml, id);
220
+ return prepareMemoryTransitionAtRev(root, sha, memoryYaml, id, op);
221
+ }
222
+ /**
223
+ * The body of {@link prepareMemoryTransition}, at a sha and a committed `memory.yaml` the caller has
224
+ * already resolved: locate document `id` at `sha`, check the working tree carries the same element,
225
+ * and resolve `op` on its committed `status`. Every refusal {@link prepareMemoryTransition} documents
226
+ * past the `memory.yaml` read comes from here, unchanged.
227
+ *
228
+ * It exists so that a second decision in one command reads the same commit as the first: the
229
+ * `supersedes:` trigger (task-162) prepares the superseded element at the sha its superseding
230
+ * element's approve was decided at, with `op` `supersede`. With `expectedType`, a document of another
231
+ * type is refused (`VALIDATION`) before its own machine is consulted, since the caller's rule is about
232
+ * the type, not about that machine's states.
233
+ */
234
+ function prepareMemoryTransitionAtRev(root, sha, memoryYaml, id, op, expectedType) {
235
+ // Tolerant (task-171, `bug-031`): a committed document the scan cannot read no longer refuses the
236
+ // transition of another element. It is skipped and reported; the verb's success carries it as a
237
+ // warning, and a miss names it, since the id may be in it.
238
+ const unreadable = [];
239
+ let found;
240
+ try {
241
+ found = (0, memory_1.findMemoryDocumentByIdAtRev)(root, sha, memoryYaml, id, { onDiagnostic: (diagnostic) => unreadable.push(diagnostic) });
242
+ }
243
+ catch (error) {
244
+ // The lookup throws only the `dl-149` refusal of the element it names (task-257, `bug-241`).
245
+ return newerFormatRefusal(op, id, 'HEAD', error);
246
+ }
104
247
  if (!found) {
105
- return (0, types_1.coreErr)({ code: 'NOT_FOUND', message: `document not found: ${id}${uncommittedMachineNote(root)}` });
248
+ const onDisk = uncommittedDocumentPath(root, memoryYaml, id);
249
+ if (onDisk !== undefined) {
250
+ // A document reached through a symbolic link (its own name, or its type directory) is not a
251
+ // tree entry under the scan roots at HEAD, so the HEAD lookup cannot find it; the refusal is
252
+ // already decided, and the filesystem guard words it truthfully (bug-117, bug-120 D2).
253
+ const confined = (0, confinement_1.requireConfinedWriteTarget)(root, onDisk, 'write');
254
+ if (!confined.ok)
255
+ return confined;
256
+ const inspectable = (0, write_guard_1.requireInspectableTarget)(root, onDisk, TRANSITION_CONTRACT);
257
+ if (!inspectable.ok)
258
+ return inspectable;
259
+ const recorded = recordedIdAt(root, sha, onDisk);
260
+ if (recorded !== undefined) {
261
+ return (0, types_1.coreErr)({
262
+ code: 'VALIDATION',
263
+ message: `refusing to ${op} ${id}: the working tree changes frontmatter field 'id' of ${onDisk}, which HEAD records ` +
264
+ `as '${recorded}'. A transition acts on the element the commit records; restore the id, then retry.`,
265
+ });
266
+ }
267
+ return (0, types_1.coreErr)({
268
+ code: 'NOT_FOUND',
269
+ message: `document not found: ${id} — ${onDisk} is not committed at HEAD, though it carries that id in the working tree. ` +
270
+ 'A transition is decided by the status the repository records (spec-006 §6 item 1, dl-080), so it acts only ' +
271
+ 'on a committed element; register a new element with `memory add`, then retry.',
272
+ });
273
+ }
274
+ return (0, types_1.coreErr)({
275
+ code: 'NOT_FOUND',
276
+ message: `document not found: ${id}${unreadableNote(unreadable)}${uncommittedMachineNote(root)}`,
277
+ ...(unreadable.length > 0 ? { details: { issues: unreadable } } : {}),
278
+ });
279
+ }
280
+ const path = found.path;
281
+ // `lstat`, which never follows a link: a symbolic link in place of the document is present even when
282
+ // it dangles. A live one reaches the write-side guards `commitMemoryTransition` runs (REQ-SEC-06,
283
+ // `bug-120`); a dangling one is refused here, because the content read below would fail on it first
284
+ // (task-247 review).
285
+ const present = isPresent((0, path_1.join)(root, path));
286
+ if (present && !(0, fs_1.existsSync)((0, path_1.join)(root, path))) {
287
+ return (0, types_1.coreErr)({
288
+ code: 'VALIDATION',
289
+ message: `refusing to ${op} ${id}: its document '${path}' is a symbolic link whose target does not exist in the working ` +
290
+ `tree. Restore the committed file (git restore --source=HEAD --staged --worktree -- ${path}) and retry.`,
291
+ });
292
+ }
293
+ if (!present) {
294
+ // `--source=HEAD --staged --worktree`: a plain `git restore -- <path>` restores from the index,
295
+ // which no longer holds the path after `git rm` or `git mv` (task-247 review).
296
+ return (0, types_1.coreErr)({
297
+ code: 'VALIDATION',
298
+ message: `refusing to ${op} ${id}: its document '${path}' is held by HEAD but deleted in the working tree. Restore it ` +
299
+ `(git restore --source=HEAD --staged --worktree -- ${path}) and retry.`,
300
+ });
106
301
  }
107
302
  const type = found.frontmatter.type;
303
+ if (expectedType !== undefined && type !== expectedType) {
304
+ return (0, types_1.coreErr)({
305
+ code: 'VALIDATION',
306
+ message: `${id}, which is of type '${String(type)}', not of type '${expectedType}': only an element of the same type can be ${op}d`,
307
+ });
308
+ }
108
309
  if (typeof type !== 'string' || memoryYaml.types[type] === undefined) {
109
310
  return (0, types_1.coreErr)({
110
311
  code: 'NOT_FOUND',
@@ -122,10 +323,66 @@ function prepareMemoryTransition(root, id, op) {
122
323
  // A missing or non-string `status` is reported as an invalid state, never as the text 'undefined'.
123
324
  const from = typeof status === 'string' ? status : String(status ?? '');
124
325
  try {
125
- (0, memory_1.validateFrontmatterState)(machine, type, from, found.path);
126
- const to = (0, memory_1.resolveTypeTransition)(memoryYaml, type, from, op, found.path);
127
- const content = (0, storage_1.readDocument)((0, path_1.join)(root, found.path));
128
- return (0, types_1.coreOk)({ memoryYaml, id, type, path: found.path, frontmatter: found.frontmatter, content, from, to });
326
+ (0, memory_1.validateFrontmatterState)(machine, type, from, path);
327
+ // `amend` moves no state (`dl-108`): its edge is the self-loop `[s → s]` in every state, so no
328
+ // machine lookup can refuse it. Whether the TYPE may be amended is the verb's own check.
329
+ const to = op === 'amend'
330
+ ? from
331
+ : op === 'supersede'
332
+ ? (0, memory_1.resolveSupersedeTarget)(memoryYaml, type, from, path)
333
+ : op === 'finalize'
334
+ ? (0, memory_1.resolveWaitingTarget)(memoryYaml, type, from, path)
335
+ : (0, memory_1.resolveTypeTransition)(memoryYaml, type, from, op, path);
336
+ // A self-loop (`amend`) enters no state, so it takes no slot. Nor does a return (`dl-156` Q2 (i),
337
+ // task-274): `reject` only ever takes a `gates.<from>.reject` edge and `park` only a
338
+ // `returns.<from>` edge (`resolveTransitionTarget`), and a reject or returns edge is exempt: the
339
+ // approver's verdict and a scheduling step are not capped by a capacity rule (a `bug`'s reject edges
340
+ // even lead forward, to `closed`). Keyed on the verb, not on the target, so an `approve` whose
341
+ // forward target equals the gate's reject target still takes the check. A `finalize` (task-217)
342
+ // enters a state like any forward move, so it takes the check too.
343
+ if (to !== from && op !== 'reject' && op !== 'park') {
344
+ const slot = requireWipSlot(root, sha, memoryYaml, type, to, id);
345
+ if (!slot.ok)
346
+ return slot;
347
+ // The documents the slot count could not read, if the lookup above has not already named them.
348
+ for (const diagnostic of slot.value) {
349
+ if (!unreadable.some((known) => known.file === diagnostic.file))
350
+ unreadable.push(diagnostic);
351
+ }
352
+ }
353
+ // Content from the working tree: what `submit` and `amend` commit, and what the other verbs'
354
+ // unmodified-document guard compares with `HEAD`. A working-tree edit that declares a newer
355
+ // `format` is refused before it can be committed (task-257, `bug-241`).
356
+ let frontmatter;
357
+ try {
358
+ ({ frontmatter } = (0, memory_1.loadMemoryDocumentSummary)(root, path));
359
+ }
360
+ catch (error) {
361
+ return newerFormatRefusal(op, id, 'the working tree', error);
362
+ }
363
+ const changed = ['id', 'type'].filter((key) => frontmatter[key] !== found.frontmatter[key]);
364
+ if (changed.length > 0) {
365
+ return (0, types_1.coreErr)({
366
+ code: 'VALIDATION',
367
+ message: `refusing to ${op} ${id}: the working tree changes ${changed.map((key) => `frontmatter field '${key}'`).join(' and ')} ` +
368
+ `of ${path}, which HEAD records as ${changed.map((key) => `'${String(found.frontmatter[key])}'`).join(' and ')}. ` +
369
+ 'A transition acts on the element the commit records; restore the recorded value, then retry.',
370
+ });
371
+ }
372
+ const content = (0, storage_1.readDocument)((0, path_1.join)(root, path));
373
+ return (0, types_1.coreOk)({
374
+ memoryYaml,
375
+ id,
376
+ type,
377
+ path,
378
+ frontmatter,
379
+ content,
380
+ from,
381
+ to,
382
+ sha,
383
+ committedFrontmatter: found.frontmatter,
384
+ warnings: unreadable.map(validation_1.formatDiagnostic),
385
+ });
129
386
  }
130
387
  catch (error) {
131
388
  if (!(error instanceof validation_1.ValidationError))
@@ -135,6 +392,148 @@ function prepareMemoryTransition(root, id, op) {
135
392
  return (0, types_1.coreErr)({ code, message, details: { issues: error.issues } });
136
393
  }
137
394
  }
395
+ /**
396
+ * The sentence every WIP refusal ends with (`dl-156` Q1 (a), task-274): where the holders were counted,
397
+ * that a clone sees only the refs it has fetched, and where a holder recorded elsewhere is moved out.
398
+ */
399
+ exports.WIP_REFS_SENTENCE = 'The holders are counted at HEAD and on every local and remote-tracking branch that changed them since it forked from HEAD, ' +
400
+ 'so the count depends on which refs were last fetched; a holder another branch records is moved out on that branch.';
401
+ /**
402
+ * Refuse to move an element into `state` when the type's machine declares a WIP limit there
403
+ * (`limits: { <state>: N }`, `spec-001`, `dl-110` P3 (a), task-180) and N elements of the type already
404
+ * hold it — `CONFLICT`, exit `1`, naming every holder in path order, before anything is written.
405
+ *
406
+ * The one shared check: {@link prepareMemoryTransitionAtRev} calls it for every transition into a new
407
+ * state except along a reject or `returns` edge (`submit`, `approve`, the `supersedes:` trigger, and
408
+ * any workflow emitter that prepares its transition there — not `reject` nor `park`, `dl-156` Q2 (i)),
409
+ * and `memory add` calls it for the initial state, since `add` is the verb that enters that state.
410
+ *
411
+ * **Where the holders are counted** (`dl-156` Q1 (a), task-274, as the approver ruled on 2026-10-11 at
412
+ * its review, option (a)): each element of the type counts in one state —
413
+ *
414
+ * - the state a ref records, when that ref **changed** the element since its merge-base with commit
415
+ * `sha` (the one the transition is decided at, `dl-080`): its `status` differs from the merge-base
416
+ * copy's, or the merge-base has no copy (an element added on the ref; a ref sharing no history with
417
+ * `sha` counts every copy it holds). The refs are those {@link refBaselineCommits} lists for
418
+ * `memory add`'s id counter (`dl-101` §2 (a)); a ref that is an ancestor of `sha` changed nothing.
419
+ * When several refs changed it, the most advanced of their copies wins
420
+ * ({@link isMoreAdvancedState}), the decided commit's copy not competing;
421
+ * - otherwise the state commit `sha` records.
422
+ *
423
+ * So a stale branch does not keep a parked holder counted, and an older copy elsewhere does not hide an
424
+ * element a reject moved back into the state. "Changed" compares `status`, not bytes: an edit that
425
+ * leaves the status alone (Execution Notes, an amend) is not a move. `exceptId`, the element being
426
+ * moved, is never its own holder. The refusal ends with {@link WIP_REFS_SENTENCE}. This read is wider
427
+ * than `HEAD`, which the `command-baseline` directive declares by name.
428
+ *
429
+ * Only the type's directory is read, every commit's listing and every distinct blob in one batch each,
430
+ * each blob parsed once (`loadTypeDocumentCopiesAtRevs`; task-274 review F2, the `bug-178` class);
431
+ * one `git merge-base` per ref. A document none of those reads can parse is not counted (task-171's
432
+ * tolerant scan) and is returned as a `W_MEMORY_UNREADABLE` diagnostic, once per file, which the
433
+ * caller's success carries as a warning and a refusal carries in `details.issues`, so a limit that may
434
+ * be undercounted says so. Without a declared limit nothing is read and nothing is returned.
435
+ */
436
+ function requireWipSlot(root, sha, memoryYaml, type, state, exceptId) {
437
+ const machine = (0, memory_1.resolveStateMachine)(memoryYaml, type);
438
+ const limit = machine.limits?.[state];
439
+ if (limit === undefined)
440
+ return (0, types_1.coreOk)([]);
441
+ const decided = (0, revision_1.resolveRevision)(root, sha);
442
+ const refs = (0, memory_1.refBaselineCommits)(root).filter((commit) => commit !== decided);
443
+ const bases = (0, storage_1.mergeBasesWith)(root, decided, refs);
444
+ // A ref that is an ancestor of the decided commit changed nothing the decided commit lacks.
445
+ const moved = refs.map((ref, index) => ({ ref, base: bases[index] })).filter(({ ref, base }) => base !== ref);
446
+ const revs = [...new Set([decided, ...moved.map(({ ref }) => ref), ...moved.flatMap(({ base }) => (base === null ? [] : [base]))])];
447
+ const unreadable = [];
448
+ const onDiagnostic = (diagnostic) => {
449
+ if (!unreadable.some((known) => known.file === diagnostic.file))
450
+ unreadable.push(diagnostic);
451
+ };
452
+ const copiesAt = new Map();
453
+ (0, memory_1.loadTypeDocumentCopiesAtRevs)(root, revs, memoryYaml, type, { onDiagnostic }).forEach((copies, index) => {
454
+ const byKey = new Map();
455
+ for (const { frontmatter, path } of copies) {
456
+ // A copy with no string `status` holds no state, and is no move either.
457
+ if (typeof frontmatter.status !== 'string')
458
+ continue;
459
+ const id = frontmatter.id === undefined ? undefined : String(frontmatter.id);
460
+ byKey.set(id === undefined ? `path:${path}` : `id:${id}`, { name: id ?? path, path, state: frontmatter.status });
461
+ }
462
+ copiesAt.set(revs[index], byKey);
463
+ });
464
+ // The decided commit's copy, unless a ref changed the element since the fork.
465
+ const elements = new Map(copiesAt.get(decided));
466
+ const changed = new Map();
467
+ for (const { ref, base } of moved) {
468
+ const atBase = base === null ? new Map() : copiesAt.get(base);
469
+ for (const [key, copy] of copiesAt.get(ref)) {
470
+ if (atBase.get(key)?.state === copy.state)
471
+ continue;
472
+ const known = changed.get(key);
473
+ if (known === undefined || isMoreAdvancedState(machine, copy.state, known.state))
474
+ changed.set(key, copy);
475
+ }
476
+ }
477
+ for (const [key, copy] of changed)
478
+ elements.set(key, copy);
479
+ // Path order, then the element key (unique), as one string each: the default sort is by UTF-16 code
480
+ // units, independent of locale and of the order the commits were read in (REQ-SYS-07).
481
+ const named = new Map();
482
+ for (const [key, element] of elements) {
483
+ if (element.state === state && element.name !== exceptId)
484
+ named.set(`${element.path}\u0000${key}`, element.name);
485
+ }
486
+ const holders = [...named.keys()].sort().map((order) => named.get(order));
487
+ if (holders.length < limit)
488
+ return (0, types_1.coreOk)(unreadable);
489
+ return (0, types_1.coreErr)({
490
+ code: 'CONFLICT',
491
+ message: `WIP limit reached for '${state}' on type '${type}' (limit ${limit}): held by ${holders.join(', ')}. ` +
492
+ `Move one of them out of '${state}', then retry. ${exports.WIP_REFS_SENTENCE}`,
493
+ ...(unreadable.length > 0 ? { details: { issues: unreadable } } : {}),
494
+ });
495
+ }
496
+ /**
497
+ * Whether state `a` is further along `machine` than state `b` — the rule that picks the one state an
498
+ * element counts in when the refs disagree (`dl-156` Q1 (a): "the most advanced state wins"). A
499
+ * `sequence` state ranks by its position; a state outside `sequence` (an off-chain `gates` reject
500
+ * target, `deprecated`, or a value the machine does not declare) ranks after every `sequence` state,
501
+ * since the element has left the chain, and `deprecated` ranks last of all. Equal ranks are ordered by
502
+ * name, so the answer never depends on the order the commits were read in (REQ-SYS-07). Pure.
503
+ */
504
+ function isMoreAdvancedState(machine, a, b) {
505
+ const rank = (state) => {
506
+ if (state === memory_1.DEPRECATED_STATE)
507
+ return machine.sequence.length + 1;
508
+ const index = machine.sequence.indexOf(state);
509
+ return index === -1 ? machine.sequence.length : index;
510
+ };
511
+ const ra = rank(a);
512
+ const rb = rank(b);
513
+ return ra !== rb ? ra > rb : a > b;
514
+ }
515
+ /**
516
+ * The shared preamble of every state-moving `memory` verb — `submit`, `approve`, `reject`,
517
+ * `deprecate`, `amend` — written once (task-132, `bug-142`): resolve the git identity
518
+ * (`requireGitIdentity`, REQ-SEC-01, exit `1`), then locate the document and resolve verb `op` on it
519
+ * ({@link prepareMemoryTransition}, exit `1`). The first refusal is returned unchanged; nothing is
520
+ * written either way.
521
+ *
522
+ * The identity is read here ONCE and rides the result, so no verb reads it again (the structural test
523
+ * `test/core/memory-transition-preamble.test.ts` holds every registered transition verb to that).
524
+ * The order matches `spec-006` §7: a verb's usage checks run before it calls this (task-125,
525
+ * `bug-172`), and an approver-gated verb's authority check runs after it, because that check's
526
+ * message names the document's type, which only this step knows.
527
+ */
528
+ function beginMemoryTransition(root, id, op) {
529
+ const identity = (0, git_identity_1.requireGitIdentity)(root);
530
+ if (!identity.ok)
531
+ return identity;
532
+ const prepared = prepareMemoryTransition(root, id, op);
533
+ if (!prepared.ok)
534
+ return prepared;
535
+ return (0, types_1.coreOk)({ ...prepared.value, identity: identity.value });
536
+ }
138
537
  /**
139
538
  * Refuse, before anything is written, a document that already carries modifications this transition
140
539
  * does not own (task-088, `bug-076`; AC2 option (b)).
@@ -148,10 +547,10 @@ function prepareMemoryTransition(root, id, op) {
148
547
  *
149
548
  * **Why refusing rather than committing only the status hunk.** Partial staging is undefined here
150
549
  * before it is difficult: there are two candidate baselines on disk (the index and the working tree)
151
- * and they can disagree, so "only the status hunk" does not say onto which text. Worse, the verb reads
152
- * `status` itself from the working tree, so a hand-edited-but-uncommitted `status` would have the
153
- * commit record `draft → approved` under a subject declaring `pending → approved` — the audit trail
154
- * asserting something that did not happen, which is the defect, not a fix for it. And the edits a
550
+ * and they can disagree, so "only the status hunk" does not say onto which text. Worse, a
551
+ * hand-edited-but-uncommitted `status` riding along would have the commit record `draft → approved`
552
+ * under a subject declaring `pending → approved` (the subject's `from` is `HEAD`'s since task-247) —
553
+ * the audit trail asserting something that did not happen, which is the defect, not a fix for it. And the edits a
155
554
  * partial commit left behind would be invisible, deferred, and swept into whatever commits next. A
156
555
  * refusal costs the user two commands, now, on a document this function has provably not touched.
157
556
  *
@@ -193,11 +592,41 @@ function verifyCommittedScope(root, sha, path, expected, scope) {
193
592
  return [...problems, `it does not contain '${path}'`];
194
593
  return [...problems, ...(0, memory_1.verifyDocumentEdit)((0, storage_1.readPathAtRev)(root, parent, path) ?? '', after, expected, scope)];
195
594
  }
595
+ /**
596
+ * The pre-write half of {@link commitMemoryTransition} — its checks 1 to 3 (confinement, an
597
+ * unmodified working tree under `declared-fields-only` or no divergent stage under
598
+ * `carries-content`, and the rendering's post-condition), with nothing written. A command that makes
599
+ * more than one commit runs it on every document first, so a refusal of any of them leaves the
600
+ * repository as it was (the `supersedes:` trigger, task-162). {@link commitMemoryTransition} runs it
601
+ * again before its own write, so calling it first is never required for safety.
602
+ */
603
+ function checkMemoryTransition(root, prepared, content, expected = {}, scope = 'declared-fields-only') {
604
+ const owned = { status: prepared.to, ...expected };
605
+ const confined = (0, confinement_1.requireConfinedWriteTarget)(root, prepared.path, 'write');
606
+ if (!confined.ok)
607
+ return confined;
608
+ const unmodified = scope === 'declared-fields-only'
609
+ ? requireUnmodifiedDocument(root, prepared)
610
+ : (0, write_guard_1.requireNoDivergentStage)(root, prepared.path, TRANSITION_CONTRACT);
611
+ if (!unmodified.ok)
612
+ return unmodified;
613
+ const problems = (0, memory_1.verifyDocumentEdit)(prepared.content, content, owned, 'declared-fields-only');
614
+ if (problems.length > 0) {
615
+ return (0, types_1.coreErr)({
616
+ code: 'VALIDATION',
617
+ message: `refusing to write ${prepared.path}: the rendered document failed its post-condition: ${problems.join('; ')}`,
618
+ });
619
+ }
620
+ return (0, types_1.coreOk)(undefined);
621
+ }
196
622
  /**
197
623
  * Write `content` over the prepared document and commit exactly that one path with `message`,
198
624
  * returning the new commit's sha (`commitPaths`, task-018; scoped to that path even when other changes
199
- * are staged, bug-027). Callers must have run the git-identity pre-flight (REQ-SEC-01) and every refusal
200
- * check first; this step is the only write.
625
+ * are staged, bug-027). The commit's author is pinned to `prepared.identity` — the identity the
626
+ * pre-flight checked, and the one any `Approver:` line names — so git's own author resolution cannot
627
+ * substitute another (task-132, `bug-149`). `prepared` comes from {@link beginMemoryTransition}, which
628
+ * is how the git-identity pre-flight (REQ-SEC-01) is guaranteed to have run; callers run every other
629
+ * refusal check first, and this step is the only write.
201
630
  *
202
631
  * Four checks bound what reaches the repository, in this order — they are not redundant, they catch
203
632
  * different defects:
@@ -216,7 +645,10 @@ function verifyCommittedScope(root, sha, path, expected, scope) {
216
645
  * --porcelain` reports a path beyond a symbolic link as clean, which is `bug-118`).
217
646
  * 2. **The working tree is unmodified** ({@link requireUnmodifiedDocument}, `declared-fields-only`
218
647
  * only) — catches a wrong *baseline*: content that was already on disk before the verb ran
219
- * (`bug-076`).
648
+ * (`bug-076`). Under `carries-content` the working tree IS the content, so the check narrows to
649
+ * `requireNoDivergentStage`: a staged version differing from both `HEAD` and the working tree,
650
+ * which `git add` would silently discard, is refused (task-131, `bug-182`). Both shapes first
651
+ * refuse a document behind a symlinked directory, which git cannot report on (`bug-118`).
220
652
  * 3. **The rendering is in scope** ({@link verifyDocumentEdit} against the prepared document) —
221
653
  * catches a defect in the *editor*: `status` must be the prepared target, every field in `expected`
222
654
  * must have its value (`undefined` = absent), and no other field and no byte of the body may have
@@ -229,34 +661,23 @@ function verifyCommittedScope(root, sha, path, expected, scope) {
229
661
  * Checks 1–3 report a `VALIDATION` error (exit 1) with nothing written or committed. Check 4 can
230
662
  * only report; see {@link verifyCommittedScope}.
231
663
  *
232
- * Check 1 resolves on the **working tree**, not at `HEAD`, which departs from `command-baseline`'s
233
- * rule for a gating read. The argument is `task-102`'s, recorded in
234
- * `dl-086-a-guard-over-a-filesystem-effect-resolves-on-the-filesystem` (`in-discussion`) and cited
235
- * rather than re-made: it predicts where `writeDocument` will land, and that follows the symlinks on
236
- * disk rather than the ones a commit records.
664
+ * Check 1 resolves on the **working tree**, not at `HEAD`: it is the filesystem-effect read
665
+ * `command-baseline` and `spec-006-core-domain-api` §6 declare, ratified in
666
+ * `dl-086-a-guard-over-a-filesystem-effect-resolves-on-the-filesystem` from `task-102`'s argument,
667
+ * which is cited rather than re-made: it predicts where `writeDocument` will land, and that follows
668
+ * the symlinks on disk rather than the ones a commit records.
237
669
  *
238
670
  * @param scope - How much of the document this operation owns; defaults to the strict
239
671
  * `declared-fields-only`, so a new verb is guarded unless it opts out deliberately.
672
+ * @param warnings - The success warnings the verb will report, handed to the commit primitive so a dry
673
+ * run carries them (task-210 review, F4); defaults to the lookup's own, `prepared.warnings`.
240
674
  */
241
- function commitMemoryTransition(root, prepared, content, message, expected = {}, scope = 'declared-fields-only') {
675
+ function commitMemoryTransition(root, prepared, content, message, expected = {}, scope = 'declared-fields-only', warnings = prepared.warnings) {
676
+ const checked = checkMemoryTransition(root, prepared, content, expected, scope);
677
+ if (!checked.ok)
678
+ return checked;
242
679
  const owned = { status: prepared.to, ...expected };
243
- const confined = (0, confinement_1.requireConfinedWriteTarget)(root, prepared.path, 'write');
244
- if (!confined.ok)
245
- return confined;
246
- if (scope === 'declared-fields-only') {
247
- const unmodified = requireUnmodifiedDocument(root, prepared);
248
- if (!unmodified.ok)
249
- return unmodified;
250
- }
251
- const problems = (0, memory_1.verifyDocumentEdit)(prepared.content, content, owned, 'declared-fields-only');
252
- if (problems.length > 0) {
253
- return (0, types_1.coreErr)({
254
- code: 'VALIDATION',
255
- message: `refusing to write ${prepared.path}: the rendered document failed its post-condition: ${problems.join('; ')}`,
256
- });
257
- }
258
- (0, storage_1.writeDocument)((0, path_1.join)(root, prepared.path), content);
259
- const sha = (0, storage_1.commitPaths)(root, [prepared.path], message);
680
+ const sha = (0, storage_1.writeAndCommit)(root, [{ path: prepared.path, content }], message, { author: prepared.identity, warnings });
260
681
  const leaked = verifyCommittedScope(root, sha, prepared.path, owned, scope);
261
682
  if (leaked.length > 0) {
262
683
  return (0, types_1.coreErr)({