wingfoil 0.2.1

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 (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +334 -0
  3. package/dist/cli/error.d.ts +11 -0
  4. package/dist/cli/error.d.ts.map +1 -0
  5. package/dist/cli/error.js +27 -0
  6. package/dist/cli/error.js.map +1 -0
  7. package/dist/cli/exit.d.ts +19 -0
  8. package/dist/cli/exit.d.ts.map +1 -0
  9. package/dist/cli/exit.js +14 -0
  10. package/dist/cli/exit.js.map +1 -0
  11. package/dist/cli/index.d.ts +28 -0
  12. package/dist/cli/index.d.ts.map +1 -0
  13. package/dist/cli/index.js +36 -0
  14. package/dist/cli/index.js.map +1 -0
  15. package/dist/cli/init-command.d.ts +34 -0
  16. package/dist/cli/init-command.d.ts.map +1 -0
  17. package/dist/cli/init-command.js +100 -0
  18. package/dist/cli/init-command.js.map +1 -0
  19. package/dist/cli/mcp-command.d.ts +24 -0
  20. package/dist/cli/mcp-command.d.ts.map +1 -0
  21. package/dist/cli/mcp-command.js +42 -0
  22. package/dist/cli/mcp-command.js.map +1 -0
  23. package/dist/cli/output.d.ts +13 -0
  24. package/dist/cli/output.d.ts.map +1 -0
  25. package/dist/cli/output.js +28 -0
  26. package/dist/cli/output.js.map +1 -0
  27. package/dist/cli/program.d.ts +12 -0
  28. package/dist/cli/program.d.ts.map +1 -0
  29. package/dist/cli/program.js +279 -0
  30. package/dist/cli/program.js.map +1 -0
  31. package/dist/cli/registrar.d.ts +69 -0
  32. package/dist/cli/registrar.d.ts.map +1 -0
  33. package/dist/cli/registrar.js +82 -0
  34. package/dist/cli/registrar.js.map +1 -0
  35. package/dist/cli.d.ts +3 -0
  36. package/dist/cli.d.ts.map +1 -0
  37. package/dist/cli.js +45 -0
  38. package/dist/cli.js.map +1 -0
  39. package/dist/core/approval-authority.d.ts +83 -0
  40. package/dist/core/approval-authority.d.ts.map +1 -0
  41. package/dist/core/approval-authority.js +112 -0
  42. package/dist/core/approval-authority.js.map +1 -0
  43. package/dist/core/builtin-asset.d.ts +71 -0
  44. package/dist/core/builtin-asset.d.ts.map +1 -0
  45. package/dist/core/builtin-asset.js +137 -0
  46. package/dist/core/builtin-asset.js.map +1 -0
  47. package/dist/core/builtin-integrity.d.ts +32 -0
  48. package/dist/core/builtin-integrity.d.ts.map +1 -0
  49. package/dist/core/builtin-integrity.js +148 -0
  50. package/dist/core/builtin-integrity.js.map +1 -0
  51. package/dist/core/confinement.d.ts +57 -0
  52. package/dist/core/confinement.d.ts.map +1 -0
  53. package/dist/core/confinement.js +108 -0
  54. package/dist/core/confinement.js.map +1 -0
  55. package/dist/core/context.d.ts +187 -0
  56. package/dist/core/context.d.ts.map +1 -0
  57. package/dist/core/context.js +192 -0
  58. package/dist/core/context.js.map +1 -0
  59. package/dist/core/directive-assign.d.ts +131 -0
  60. package/dist/core/directive-assign.d.ts.map +1 -0
  61. package/dist/core/directive-assign.js +352 -0
  62. package/dist/core/directive-assign.js.map +1 -0
  63. package/dist/core/directives-list.d.ts +80 -0
  64. package/dist/core/directives-list.d.ts.map +1 -0
  65. package/dist/core/directives-list.js +148 -0
  66. package/dist/core/directives-list.js.map +1 -0
  67. package/dist/core/exit-code.d.ts +85 -0
  68. package/dist/core/exit-code.d.ts.map +1 -0
  69. package/dist/core/exit-code.js +163 -0
  70. package/dist/core/exit-code.js.map +1 -0
  71. package/dist/core/git-identity.d.ts +32 -0
  72. package/dist/core/git-identity.d.ts.map +1 -0
  73. package/dist/core/git-identity.js +72 -0
  74. package/dist/core/git-identity.js.map +1 -0
  75. package/dist/core/index.d.ts +388 -0
  76. package/dist/core/index.d.ts.map +1 -0
  77. package/dist/core/index.js +1331 -0
  78. package/dist/core/index.js.map +1 -0
  79. package/dist/core/init.d.ts +78 -0
  80. package/dist/core/init.d.ts.map +1 -0
  81. package/dist/core/init.js +167 -0
  82. package/dist/core/init.js.map +1 -0
  83. package/dist/core/loaders.d.ts +174 -0
  84. package/dist/core/loaders.d.ts.map +1 -0
  85. package/dist/core/loaders.js +364 -0
  86. package/dist/core/loaders.js.map +1 -0
  87. package/dist/core/memory-add-type.d.ts +43 -0
  88. package/dist/core/memory-add-type.d.ts.map +1 -0
  89. package/dist/core/memory-add-type.js +151 -0
  90. package/dist/core/memory-add-type.js.map +1 -0
  91. package/dist/core/memory-transition.d.ts +111 -0
  92. package/dist/core/memory-transition.d.ts.map +1 -0
  93. package/dist/core/memory-transition.js +269 -0
  94. package/dist/core/memory-transition.js.map +1 -0
  95. package/dist/core/registry.d.ts +189 -0
  96. package/dist/core/registry.d.ts.map +1 -0
  97. package/dist/core/registry.js +66 -0
  98. package/dist/core/registry.js.map +1 -0
  99. package/dist/core/relevance.d.ts +86 -0
  100. package/dist/core/relevance.d.ts.map +1 -0
  101. package/dist/core/relevance.js +258 -0
  102. package/dist/core/relevance.js.map +1 -0
  103. package/dist/core/require-reason.d.ts +27 -0
  104. package/dist/core/require-reason.d.ts.map +1 -0
  105. package/dist/core/require-reason.js +95 -0
  106. package/dist/core/require-reason.js.map +1 -0
  107. package/dist/core/types.d.ts +45 -0
  108. package/dist/core/types.d.ts.map +1 -0
  109. package/dist/core/types.js +22 -0
  110. package/dist/core/types.js.map +1 -0
  111. package/dist/core/usage-error.d.ts +20 -0
  112. package/dist/core/usage-error.d.ts.map +1 -0
  113. package/dist/core/usage-error.js +29 -0
  114. package/dist/core/usage-error.js.map +1 -0
  115. package/dist/core/write-guard.d.ts +99 -0
  116. package/dist/core/write-guard.d.ts.map +1 -0
  117. package/dist/core/write-guard.js +247 -0
  118. package/dist/core/write-guard.js.map +1 -0
  119. package/dist/directives/create.d.ts +47 -0
  120. package/dist/directives/create.d.ts.map +1 -0
  121. package/dist/directives/create.js +82 -0
  122. package/dist/directives/create.js.map +1 -0
  123. package/dist/directives/index.d.ts +20 -0
  124. package/dist/directives/index.d.ts.map +1 -0
  125. package/dist/directives/index.js +32 -0
  126. package/dist/directives/index.js.map +1 -0
  127. package/dist/directives/roles-edit.d.ts +53 -0
  128. package/dist/directives/roles-edit.d.ts.map +1 -0
  129. package/dist/directives/roles-edit.js +286 -0
  130. package/dist/directives/roles-edit.js.map +1 -0
  131. package/dist/directives/schema.d.ts +65 -0
  132. package/dist/directives/schema.d.ts.map +1 -0
  133. package/dist/directives/schema.js +68 -0
  134. package/dist/directives/schema.js.map +1 -0
  135. package/dist/dna/edit.d.ts +61 -0
  136. package/dist/dna/edit.d.ts.map +1 -0
  137. package/dist/dna/edit.js +429 -0
  138. package/dist/dna/edit.js.map +1 -0
  139. package/dist/dna/index.d.ts +24 -0
  140. package/dist/dna/index.d.ts.map +1 -0
  141. package/dist/dna/index.js +59 -0
  142. package/dist/dna/index.js.map +1 -0
  143. package/dist/dna/mutate.d.ts +74 -0
  144. package/dist/dna/mutate.d.ts.map +1 -0
  145. package/dist/dna/mutate.js +318 -0
  146. package/dist/dna/mutate.js.map +1 -0
  147. package/dist/dna/path.d.ts +175 -0
  148. package/dist/dna/path.d.ts.map +1 -0
  149. package/dist/dna/path.js +289 -0
  150. package/dist/dna/path.js.map +1 -0
  151. package/dist/dna/roles.d.ts +57 -0
  152. package/dist/dna/roles.d.ts.map +1 -0
  153. package/dist/dna/roles.js +50 -0
  154. package/dist/dna/roles.js.map +1 -0
  155. package/dist/dna/schema.d.ts +172 -0
  156. package/dist/dna/schema.d.ts.map +1 -0
  157. package/dist/dna/schema.js +182 -0
  158. package/dist/dna/schema.js.map +1 -0
  159. package/dist/dna/set.d.ts +145 -0
  160. package/dist/dna/set.d.ts.map +1 -0
  161. package/dist/dna/set.js +428 -0
  162. package/dist/dna/set.js.map +1 -0
  163. package/dist/mcp/dna-resource.d.ts +16 -0
  164. package/dist/mcp/dna-resource.d.ts.map +1 -0
  165. package/dist/mcp/dna-resource.js +56 -0
  166. package/dist/mcp/dna-resource.js.map +1 -0
  167. package/dist/mcp/index.d.ts +49 -0
  168. package/dist/mcp/index.d.ts.map +1 -0
  169. package/dist/mcp/index.js +60 -0
  170. package/dist/mcp/index.js.map +1 -0
  171. package/dist/mcp/memory-resource.d.ts +17 -0
  172. package/dist/mcp/memory-resource.d.ts.map +1 -0
  173. package/dist/mcp/memory-resource.js +133 -0
  174. package/dist/mcp/memory-resource.js.map +1 -0
  175. package/dist/mcp/prompt.d.ts +48 -0
  176. package/dist/mcp/prompt.d.ts.map +1 -0
  177. package/dist/mcp/prompt.js +176 -0
  178. package/dist/mcp/prompt.js.map +1 -0
  179. package/dist/mcp/read-only.d.ts +42 -0
  180. package/dist/mcp/read-only.d.ts.map +1 -0
  181. package/dist/mcp/read-only.js +93 -0
  182. package/dist/mcp/read-only.js.map +1 -0
  183. package/dist/mcp/registrar.d.ts +54 -0
  184. package/dist/mcp/registrar.d.ts.map +1 -0
  185. package/dist/mcp/registrar.js +72 -0
  186. package/dist/mcp/registrar.js.map +1 -0
  187. package/dist/mcp/server.d.ts +58 -0
  188. package/dist/mcp/server.d.ts.map +1 -0
  189. package/dist/mcp/server.js +64 -0
  190. package/dist/mcp/server.js.map +1 -0
  191. package/dist/mcp/workflow-resource.d.ts +17 -0
  192. package/dist/mcp/workflow-resource.d.ts.map +1 -0
  193. package/dist/mcp/workflow-resource.js +63 -0
  194. package/dist/mcp/workflow-resource.js.map +1 -0
  195. package/dist/memory/add.d.ts +50 -0
  196. package/dist/memory/add.d.ts.map +1 -0
  197. package/dist/memory/add.js +131 -0
  198. package/dist/memory/add.js.map +1 -0
  199. package/dist/memory/audit.d.ts +177 -0
  200. package/dist/memory/audit.d.ts.map +1 -0
  201. package/dist/memory/audit.js +287 -0
  202. package/dist/memory/audit.js.map +1 -0
  203. package/dist/memory/commit-message.d.ts +146 -0
  204. package/dist/memory/commit-message.d.ts.map +1 -0
  205. package/dist/memory/commit-message.js +203 -0
  206. package/dist/memory/commit-message.js.map +1 -0
  207. package/dist/memory/entry.d.ts +56 -0
  208. package/dist/memory/entry.d.ts.map +1 -0
  209. package/dist/memory/entry.js +28 -0
  210. package/dist/memory/entry.js.map +1 -0
  211. package/dist/memory/frontmatter-edit.d.ts +68 -0
  212. package/dist/memory/frontmatter-edit.d.ts.map +1 -0
  213. package/dist/memory/frontmatter-edit.js +333 -0
  214. package/dist/memory/frontmatter-edit.js.map +1 -0
  215. package/dist/memory/git-log.d.ts +32 -0
  216. package/dist/memory/git-log.d.ts.map +1 -0
  217. package/dist/memory/git-log.js +100 -0
  218. package/dist/memory/git-log.js.map +1 -0
  219. package/dist/memory/history.d.ts +142 -0
  220. package/dist/memory/history.d.ts.map +1 -0
  221. package/dist/memory/history.js +250 -0
  222. package/dist/memory/history.js.map +1 -0
  223. package/dist/memory/index.d.ts +58 -0
  224. package/dist/memory/index.d.ts.map +1 -0
  225. package/dist/memory/index.js +107 -0
  226. package/dist/memory/index.js.map +1 -0
  227. package/dist/memory/query.d.ts +150 -0
  228. package/dist/memory/query.d.ts.map +1 -0
  229. package/dist/memory/query.js +307 -0
  230. package/dist/memory/query.js.map +1 -0
  231. package/dist/memory/reject.d.ts +11 -0
  232. package/dist/memory/reject.d.ts.map +1 -0
  233. package/dist/memory/reject.js +32 -0
  234. package/dist/memory/reject.js.map +1 -0
  235. package/dist/memory/schema.d.ts +104 -0
  236. package/dist/memory/schema.d.ts.map +1 -0
  237. package/dist/memory/schema.js +161 -0
  238. package/dist/memory/schema.js.map +1 -0
  239. package/dist/memory/state-machine.d.ts +166 -0
  240. package/dist/memory/state-machine.d.ts.map +1 -0
  241. package/dist/memory/state-machine.js +431 -0
  242. package/dist/memory/state-machine.js.map +1 -0
  243. package/dist/memory/submit.d.ts +11 -0
  244. package/dist/memory/submit.d.ts.map +1 -0
  245. package/dist/memory/submit.js +44 -0
  246. package/dist/memory/submit.js.map +1 -0
  247. package/dist/storage/builtin-directives.d.ts +54 -0
  248. package/dist/storage/builtin-directives.d.ts.map +1 -0
  249. package/dist/storage/builtin-directives.js +152 -0
  250. package/dist/storage/builtin-directives.js.map +1 -0
  251. package/dist/storage/commit.d.ts +92 -0
  252. package/dist/storage/commit.d.ts.map +1 -0
  253. package/dist/storage/commit.js +201 -0
  254. package/dist/storage/commit.js.map +1 -0
  255. package/dist/storage/confinement.d.ts +93 -0
  256. package/dist/storage/confinement.d.ts.map +1 -0
  257. package/dist/storage/confinement.js +164 -0
  258. package/dist/storage/confinement.js.map +1 -0
  259. package/dist/storage/document.d.ts +27 -0
  260. package/dist/storage/document.d.ts.map +1 -0
  261. package/dist/storage/document.js +52 -0
  262. package/dist/storage/document.js.map +1 -0
  263. package/dist/storage/errors.d.ts +36 -0
  264. package/dist/storage/errors.d.ts.map +1 -0
  265. package/dist/storage/errors.js +46 -0
  266. package/dist/storage/errors.js.map +1 -0
  267. package/dist/storage/frontmatter.d.ts +27 -0
  268. package/dist/storage/frontmatter.d.ts.map +1 -0
  269. package/dist/storage/frontmatter.js +37 -0
  270. package/dist/storage/frontmatter.js.map +1 -0
  271. package/dist/storage/git-root.d.ts +17 -0
  272. package/dist/storage/git-root.d.ts.map +1 -0
  273. package/dist/storage/git-root.js +49 -0
  274. package/dist/storage/git-root.js.map +1 -0
  275. package/dist/storage/index.d.ts +29 -0
  276. package/dist/storage/index.d.ts.map +1 -0
  277. package/dist/storage/index.js +66 -0
  278. package/dist/storage/index.js.map +1 -0
  279. package/dist/storage/init-state.d.ts +9 -0
  280. package/dist/storage/init-state.d.ts.map +1 -0
  281. package/dist/storage/init-state.js +24 -0
  282. package/dist/storage/init-state.js.map +1 -0
  283. package/dist/storage/layout.d.ts +51 -0
  284. package/dist/storage/layout.d.ts.map +1 -0
  285. package/dist/storage/layout.js +88 -0
  286. package/dist/storage/layout.js.map +1 -0
  287. package/dist/storage/memory-path.d.ts +72 -0
  288. package/dist/storage/memory-path.d.ts.map +1 -0
  289. package/dist/storage/memory-path.js +127 -0
  290. package/dist/storage/memory-path.js.map +1 -0
  291. package/dist/storage/snapshot.d.ts +16 -0
  292. package/dist/storage/snapshot.d.ts.map +1 -0
  293. package/dist/storage/snapshot.js +72 -0
  294. package/dist/storage/snapshot.js.map +1 -0
  295. package/dist/storage/templates.d.ts +88 -0
  296. package/dist/storage/templates.d.ts.map +1 -0
  297. package/dist/storage/templates.js +422 -0
  298. package/dist/storage/templates.js.map +1 -0
  299. package/dist/validation/error-mapper.d.ts +16 -0
  300. package/dist/validation/error-mapper.d.ts.map +1 -0
  301. package/dist/validation/error-mapper.js +18 -0
  302. package/dist/validation/error-mapper.js.map +1 -0
  303. package/dist/validation/errors.d.ts +69 -0
  304. package/dist/validation/errors.d.ts.map +1 -0
  305. package/dist/validation/errors.js +69 -0
  306. package/dist/validation/errors.js.map +1 -0
  307. package/dist/validation/id.d.ts +16 -0
  308. package/dist/validation/id.d.ts.map +1 -0
  309. package/dist/validation/id.js +177 -0
  310. package/dist/validation/id.js.map +1 -0
  311. package/dist/validation/index.d.ts +18 -0
  312. package/dist/validation/index.d.ts.map +1 -0
  313. package/dist/validation/index.js +37 -0
  314. package/dist/validation/index.js.map +1 -0
  315. package/dist/validation/secret-scan.d.ts +129 -0
  316. package/dist/validation/secret-scan.d.ts.map +1 -0
  317. package/dist/validation/secret-scan.js +367 -0
  318. package/dist/validation/secret-scan.js.map +1 -0
  319. package/dist/validation/two-pass.d.ts +24 -0
  320. package/dist/validation/two-pass.d.ts.map +1 -0
  321. package/dist/validation/two-pass.js +24 -0
  322. package/dist/validation/two-pass.js.map +1 -0
  323. package/dist/validation/warning.d.ts +31 -0
  324. package/dist/validation/warning.d.ts.map +1 -0
  325. package/dist/validation/warning.js +81 -0
  326. package/dist/validation/warning.js.map +1 -0
  327. package/dist/validation/yaml.d.ts +9 -0
  328. package/dist/validation/yaml.d.ts.map +1 -0
  329. package/dist/validation/yaml.js +30 -0
  330. package/dist/validation/yaml.js.map +1 -0
  331. package/dist/workflow/index.d.ts +10 -0
  332. package/dist/workflow/index.d.ts.map +1 -0
  333. package/dist/workflow/index.js +16 -0
  334. package/dist/workflow/index.js.map +1 -0
  335. package/dist/workflow/schema.d.ts +89 -0
  336. package/dist/workflow/schema.d.ts.map +1 -0
  337. package/dist/workflow/schema.js +73 -0
  338. package/dist/workflow/schema.js.map +1 -0
  339. package/package.json +78 -0
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.reasonDefectMessage = reasonDefectMessage;
4
+ exports.normalizeReason = normalizeReason;
5
+ exports.reasonDefect = reasonDefect;
6
+ exports.parseReasonBlock = parseReasonBlock;
7
+ exports.parseApproverTrailerLine = parseApproverTrailerLine;
8
+ exports.formatMemoryCommitMessage = formatMemoryCommitMessage;
9
+ /** The arrow used in `[from → to]` subject brackets (U+2192), as `./audit.ts`'s `BRACKET_RE` expects. */
10
+ const ARROW = '→';
11
+ // --- The reason grammar (dl-067-reason-trailer-contract) ---------------------------------------
12
+ /**
13
+ * A git trailer line's shape (`Token: value`), as git itself recognises one. Used ONLY to identify a
14
+ * message's trailing trailer paragraph — the `Co-Authored-By:` block a hand-written commit ends with —
15
+ * which is where a `Reason:` block stops.
16
+ */
17
+ const TRAILER_LINE_RE = /^[A-Za-z][A-Za-z0-9-]*:[ \t]\S/;
18
+ /**
19
+ * The two trailer keys THIS project's reader acts on. A reason may not contain a line starting with
20
+ * either, because such a line is indistinguishable from the trailer itself. Deliberately narrow: on
21
+ * `main`, 8 approve/reject commits carry a generic `Key: value` line inside their reason (ordinary
22
+ * prose — `Action: amend spec-015 §3`, `A: before the v0.2 …`) and **0** carry a reserved one, so a
23
+ * broader rule would outlaw the approver's own writing style (dl-067 E5).
24
+ */
25
+ const RESERVED_TRAILER_LINE_RE = /^(?:Approver|Reason):/;
26
+ /** The `Reason:` key, at the start of a line. */
27
+ const REASON_KEY_RE = /^Reason:[ \t]*/;
28
+ /** The `Approver:` key, at the start of a line. */
29
+ const APPROVER_KEY_RE = /^Approver:/;
30
+ /** The exact refusal message for each defect — `spec-008-cli-grammar` §2's "invalid flag value" class (exit 2). */
31
+ const REASON_DEFECT_MESSAGES = {
32
+ blank: 'invalid flag value: --reason must not be blank',
33
+ 'reserved-trailer-line': 'invalid flag value: --reason must not contain a line starting with "Approver:" or "Reason:"',
34
+ 'trailing-trailer-paragraph': 'invalid flag value: --reason must not end in a paragraph of "Key: value" lines',
35
+ };
36
+ /**
37
+ * The refusal message for `defect` — the single source of the wording the CLI prints and
38
+ * `spec-008-cli-grammar` §2 pins. Deliberately distinct from `missing required argument: --reason`
39
+ * (`src/core/require-reason.ts`), which answers the *omitted* case that spec-008 §2 and the P1.7/P1.8
40
+ * BDD features already quote verbatim (dl-067 S1).
41
+ */
42
+ function reasonDefectMessage(defect) {
43
+ return REASON_DEFECT_MESSAGES[defect];
44
+ }
45
+ /**
46
+ * The declared normal form of a reason (`dl-067` clause 3) — two rules, from two different sources,
47
+ * and it is worth keeping them apart:
48
+ *
49
+ * 1. **git's**, which applies whether or not this function exists. `commitPaths`
50
+ * (`src/storage/commit.ts`) commits with `-m`, so git's `cleanup=whitespace` strips per-line
51
+ * trailing whitespace, collapses runs of blank lines to one, and drops leading and trailing blank
52
+ * lines. This is why `spec-008-cli-grammar` §2's original "Recorded verbatim" was already false
53
+ * for any multi-line text, independently of bug-042.
54
+ * 2. **This module's**: the first line's leading whitespace is trimmed. git does NOT do this. It is
55
+ * needed because that line sits after `Reason: ` on the same physical line and
56
+ * {@link parseReasonBlock} consumes the key together with the whitespace that follows it — so
57
+ * without the trim, a reason beginning with spaces would not round-trip equally.
58
+ *
59
+ * Applying both HERE, on the way in, is what turns "approximately what you typed" into an assertable
60
+ * equality: what {@link parseReasonBlock} reads back out of the commit is exactly this function's
61
+ * output. Interior indentation is preserved by both rules — it carries meaning in real approval prose.
62
+ *
63
+ * Idempotent, and a pure function of its input (REQ-SYS-07).
64
+ */
65
+ function normalizeReason(reason) {
66
+ return reason
67
+ .replace(/\r\n?/g, '\n')
68
+ .split('\n')
69
+ .map((line) => line.replace(/[ \t]+$/, ''))
70
+ .join('\n')
71
+ .replace(/\n{3,}/g, '\n\n')
72
+ .replace(/^\n+/, '')
73
+ .replace(/\n+$/, '')
74
+ .replace(/^[ \t]+/, '');
75
+ }
76
+ /** Split a normalized reason into its paragraphs, dropping the blank separators. */
77
+ function paragraphsOf(normalized) {
78
+ const paragraphs = [[]];
79
+ for (const line of normalized.split('\n')) {
80
+ if (line.trim() === '')
81
+ paragraphs.push([]);
82
+ else
83
+ paragraphs[paragraphs.length - 1].push(line);
84
+ }
85
+ return paragraphs.filter((paragraph) => paragraph.length > 0);
86
+ }
87
+ /**
88
+ * Why `reason` cannot be recorded in the `Reason:` trailer, or `null` when it can (`dl-067` clause 4).
89
+ *
90
+ * Judged on the NORMALIZED text ({@link normalizeReason}), because that is what would actually be
91
+ * stored — otherwise a defect could hide behind trailing whitespace git strips on the way in. This is
92
+ * the ONE place the rule is decided: `src/core/require-reason.ts` turns a non-`null` result into the
93
+ * `UsageError` (exit 2) the CLI boundary reports, and {@link formatMemoryCommitMessage} refuses the
94
+ * same values so no caller can route around that boundary.
95
+ */
96
+ function reasonDefect(reason) {
97
+ const normalized = normalizeReason(reason);
98
+ if (normalized === '')
99
+ return 'blank';
100
+ const lines = normalized.split('\n');
101
+ if (lines.some((line) => RESERVED_TRAILER_LINE_RE.test(line)))
102
+ return 'reserved-trailer-line';
103
+ const paragraphs = paragraphsOf(normalized);
104
+ const last = paragraphs[paragraphs.length - 1];
105
+ if (paragraphs.length > 1 && last && last.every((line) => TRAILER_LINE_RE.test(line))) {
106
+ return 'trailing-trailer-paragraph';
107
+ }
108
+ return null;
109
+ }
110
+ /**
111
+ * Where a commit body's trailing trailer paragraph begins, or `lines.length` when it has none — the
112
+ * `Co-Authored-By:` block a hand-written WingFoil commit ends with. Defined the way git defines a
113
+ * trailer block: the final paragraph of the message, every line of which is trailer-shaped.
114
+ */
115
+ function trailerParagraphStart(lines) {
116
+ let end = lines.length;
117
+ while (end > 0 && lines[end - 1].trim() === '')
118
+ end -= 1;
119
+ let start = 0;
120
+ for (let index = end - 1; index >= 0; index -= 1) {
121
+ if (lines[index].trim() === '') {
122
+ start = index + 1;
123
+ break;
124
+ }
125
+ }
126
+ if (start === 0 || start >= end)
127
+ return lines.length;
128
+ return lines.slice(start, end).every((line) => TRAILER_LINE_RE.test(line)) ? start : lines.length;
129
+ }
130
+ /**
131
+ * The `Reason:` a commit body records, read as a BLOCK (`dl-067` clause 2): the remainder of the
132
+ * `Reason:` line plus every following body line, up to (exclusive) git's trailing trailer paragraph or
133
+ * the end of the body. `null` when the body records no reason, or records a bare `Reason:` with no
134
+ * value — the shape git's cleanup leaves behind when an empty reason is written (bug-042 F2), which
135
+ * `parseApprovalMetadata` degrades around rather than treating as an absent approval.
136
+ *
137
+ * This replaces the first-line capture `/^Reason:\s*(.+)$/m` that preceded it, and that is a real
138
+ * change to how existing history reads: 79 of `main`'s 171 approve/reject commits (46%) carry a reason
139
+ * continuing past line one, and every one of them was silently halved. It is a recovery, not a
140
+ * reinterpretation — the text was always in the commit; only the reader dropped it.
141
+ *
142
+ * A generic `Key: value` line INSIDE the block is ordinary prose and does not end it; only a trailing
143
+ * paragraph made entirely of trailer lines does (dl-067 E5).
144
+ */
145
+ function parseReasonBlock(body) {
146
+ const lines = body.replace(/\r\n?/g, '\n').split('\n');
147
+ const start = lines.findIndex((line) => REASON_KEY_RE.test(line));
148
+ if (start === -1)
149
+ return null;
150
+ const end = Math.max(trailerParagraphStart(lines), start + 1);
151
+ const block = [lines[start].replace(REASON_KEY_RE, ''), ...lines.slice(start + 1, end)].join('\n');
152
+ const normalized = normalizeReason(block);
153
+ return normalized === '' ? null : normalized;
154
+ }
155
+ /**
156
+ * The commit body's `Approver:` trailer line, or `null` when it has none — anchored to the body's
157
+ * FIRST non-empty line (`dl-067` clause 5). {@link formatMemoryCommitMessage} has always emitted it
158
+ * there, and it is the first body line in 171 of `main`'s 171 approve/reject commits (dl-067 E4), so
159
+ * anchoring costs no existing commit its approver while closing bug-042 F3 on the read side: an
160
+ * `Approver:` line appearing anywhere else is text some reason happens to contain, never an approval
161
+ * record. `./audit.ts` destructures the returned line into an identity — that shape is its concern;
162
+ * the line's POSITION is this module's.
163
+ */
164
+ function parseApproverTrailerLine(body) {
165
+ const first = body
166
+ .replace(/\r\n?/g, '\n')
167
+ .split('\n')
168
+ .find((line) => line.trim() !== '');
169
+ return first !== undefined && APPROVER_KEY_RE.test(first) ? first : null;
170
+ }
171
+ /**
172
+ * Format a Memory transition commit message: the subject, then — only when an approver or reason is
173
+ * given — a blank line and the `Approver:` / `Reason:` lines in that order.
174
+ *
175
+ * The reason is emitted in its declared normal form and, when it carries a defect
176
+ * ({@link reasonDefect}), refused rather than written. The CLI boundary
177
+ * (`src/core/require-reason.ts`) already refuses the same values with the same messages at exit 2, so
178
+ * reaching this throw means a caller bypassed that boundary — it exists so no *future* caller can
179
+ * (dl-067 clause 5; bug-042 F2/F3).
180
+ *
181
+ * @throws `Error` when `ids` is empty: a transition commit always names what it moved.
182
+ * @throws `Error` when `reason` cannot be recorded in the trailer, carrying that defect's message.
183
+ */
184
+ function formatMemoryCommitMessage(input) {
185
+ if (input.ids.length === 0) {
186
+ throw new Error('a Memory transition commit must name at least one id');
187
+ }
188
+ const defect = input.reason === undefined ? null : reasonDefect(input.reason);
189
+ if (defect !== null) {
190
+ throw new Error(reasonDefectMessage(defect));
191
+ }
192
+ const bracket = input.transition ? ` [${input.transition.from} ${ARROW} ${input.transition.to}]` : '';
193
+ const subject = `wf(${input.type}): ${input.op} ${input.ids.join(', ')}${bracket}`;
194
+ const body = [];
195
+ if (input.approver) {
196
+ body.push(`Approver: ${input.approver.name} <${input.approver.email}> (${input.approver.role})`);
197
+ }
198
+ if (input.reason !== undefined) {
199
+ body.push(`Reason: ${normalizeReason(input.reason)}`);
200
+ }
201
+ return body.length === 0 ? subject : `${subject}\n\n${body.join('\n')}`;
202
+ }
203
+ //# sourceMappingURL=commit-message.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit-message.js","sourceRoot":"","sources":["../../src/memory/commit-message.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * The git-backed Memory-entry store primitive (task-022-implement-memory-entries, P1.11,
3
+ * REQ-SYS-01/REQ-SYS-03, REQ-SEC-06) — the storage foundation `wingfoil memory add` (task-020) and
4
+ * `wingfoil memory submit` build their CLI/CoreResult surface on top of.
5
+ *
6
+ * This module composes three primitives that already exist and are NOT re-implemented here:
7
+ * - `resolveConfinedMemoryPath` (task-017-storage-confinement, `../storage/memory-path` — not
8
+ * re-exported by the `../storage` barrel, imported directly per that module's own convention)
9
+ * renders a type's `path` pattern against concrete values and refuses — throwing `StorageError`
10
+ * `E_PATH_ESCAPES_ROOT` — any resolution that would land outside the project root, BEFORE
11
+ * anything is written, judging the rendered string **and** its resolution on the filesystem
12
+ * (`task-105`, `bug-117`: a symlinked type directory leaves the project with no traversal
13
+ * anywhere in the string). Its message opens with the corrected, canonical REQ-SEC-06
14
+ * fit-criterion sentence — `'Memory entries must reside within the project root'` — and then
15
+ * names both spellings of the path, what the pattern rendered and where it really lands, because
16
+ * on the symlink case the two differing is the finding. The BDD `.feature` file's older "must
17
+ * reside under .wingfoil/memory/" wording is stale (see this task's Execution Notes for the
18
+ * reconciliation).
19
+ * - `writeDocument` (`../storage`) writes bytes only (mkdir-p).
20
+ * - `commitPaths` (`../storage`) stages exactly the one resolved path and produces exactly one
21
+ * commit — so calling {@link writeMemoryEntry} twice against the SAME `pattern`/`values` (i.e.
22
+ * the same target file, modified) yields two DISTINCT commits, with the file's prior content
23
+ * retrievable from git history via that file's own commit log — the P1.11 "each Memory entry is
24
+ * individually versioned" contract.
25
+ *
26
+ * Deliberately a throwing **library** primitive, not a `CoreResult`-wrapped `CORE_MODULES` operation:
27
+ * this task's scope is the reusable store primitive, not the `wingfoil memory add` CLI command or its
28
+ * `StorageError` → `CoreError` mapping — both of those are task-020's scope, which wires this
29
+ * primitive in (see the task's Execution Notes for that scoping decision).
30
+ */
31
+ import type { CommitOptions } from '../storage';
32
+ /** The result of a single {@link writeMemoryEntry} call. */
33
+ export interface MemoryEntryWrite {
34
+ /** The absolute, confinement-verified path that was written (see `resolveConfinedMemoryPath`). */
35
+ readonly path: string;
36
+ /** The 40-hex sha of the single commit this write produced. */
37
+ readonly sha: string;
38
+ }
39
+ /**
40
+ * Render `pattern` against `values` (per `memory.yaml`'s per-type `path` pattern,
41
+ * spec-001-memory-yaml-schema), confining the result to `root` (REQ-SEC-06), write `content` to that
42
+ * path, and commit exactly that one path as a single commit with `message` (REQ-SYS-01).
43
+ *
44
+ * @throws {@link ../storage/errors.StorageError} `E_PATH_ESCAPES_ROOT` when the resolved path would
45
+ * escape `root` — refused before any write, so a rejected call writes and commits nothing.
46
+ * @throws {@link ../storage/errors.StorageError} `E_TARGET_IS_SYMLINK` when the target itself is a
47
+ * symbolic link, dangling or live (`task-106`, `bug-120`): `writeDocument`'s `writeFileSync`
48
+ * follows one, so the bytes would land at the link's destination rather than at the path this
49
+ * function names — and through a *dangling* link the write used to succeed and commit. Refused in
50
+ * the same place, before the same write.
51
+ * @throws whatever `commitPaths`/git raises (e.g. no configured git identity) — callers that need a
52
+ * pre-flight identity check must call `requireGitIdentity` (`../core/git-identity`) themselves
53
+ * before invoking this primitive, same as every other mutating core operation.
54
+ */
55
+ export declare function writeMemoryEntry(root: string, pattern: string, values: Record<string, string>, content: string, message: string, options?: CommitOptions): MemoryEntryWrite;
56
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../../src/memory/entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD,4DAA4D;AAC5D,MAAM,WAAW,gBAAgB;IAC/B,kGAAkG;IAClG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,aAAkB,GAC1B,gBAAgB,CAKlB"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.writeMemoryEntry = writeMemoryEntry;
4
+ const storage_1 = require("../storage");
5
+ const memory_path_1 = require("../storage/memory-path");
6
+ /**
7
+ * Render `pattern` against `values` (per `memory.yaml`'s per-type `path` pattern,
8
+ * spec-001-memory-yaml-schema), confining the result to `root` (REQ-SEC-06), write `content` to that
9
+ * path, and commit exactly that one path as a single commit with `message` (REQ-SYS-01).
10
+ *
11
+ * @throws {@link ../storage/errors.StorageError} `E_PATH_ESCAPES_ROOT` when the resolved path would
12
+ * escape `root` — refused before any write, so a rejected call writes and commits nothing.
13
+ * @throws {@link ../storage/errors.StorageError} `E_TARGET_IS_SYMLINK` when the target itself is a
14
+ * symbolic link, dangling or live (`task-106`, `bug-120`): `writeDocument`'s `writeFileSync`
15
+ * follows one, so the bytes would land at the link's destination rather than at the path this
16
+ * function names — and through a *dangling* link the write used to succeed and commit. Refused in
17
+ * the same place, before the same write.
18
+ * @throws whatever `commitPaths`/git raises (e.g. no configured git identity) — callers that need a
19
+ * pre-flight identity check must call `requireGitIdentity` (`../core/git-identity`) themselves
20
+ * before invoking this primitive, same as every other mutating core operation.
21
+ */
22
+ function writeMemoryEntry(root, pattern, values, content, message, options = {}) {
23
+ const path = (0, memory_path_1.resolveConfinedMemoryPath)(root, pattern, values);
24
+ (0, storage_1.writeDocument)(path, content);
25
+ const sha = (0, storage_1.commitPaths)(root, [path], message, options);
26
+ return { path, sha };
27
+ }
28
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/memory/entry.ts"],"names":[],"mappings":";;AA0DA,4CAYC;AAvCD,wCAAwD;AACxD,wDAAmE;AAUnE;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,gBAAgB,CAC9B,IAAY,EACZ,OAAe,EACf,MAA8B,EAC9B,OAAe,EACf,OAAe,EACf,UAAyB,EAAE;IAE3B,MAAM,IAAI,GAAG,IAAA,uCAAyB,EAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAC9D,IAAA,uBAAa,EAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,GAAG,GAAG,IAAA,qBAAW,EAAC,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;AACvB,CAAC"}
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Set top-level `key` to the string `value`, serialized YAML-safely. An existing entry is replaced as a
3
+ * whole — continuation lines, block-scalar body or multi-line quoted value included. A `# comment` on
4
+ * the key line is kept when the old value ended on that line; the line ending of the key line is kept.
5
+ * An absent key is appended after the last non-blank frontmatter line, with the document's line ending.
6
+ *
7
+ * @throws `Error` when the document has no frontmatter block.
8
+ */
9
+ export declare function setFrontmatterField(content: string, key: string, value: string): string;
10
+ /**
11
+ * Remove top-level `key` together with every line its value spans (rules in the module doc). Blank
12
+ * lines and comments that follow the value belong to the parent mapping and are kept. Returns `content`
13
+ * unchanged when the key is absent.
14
+ *
15
+ * @throws `Error` when the document has no frontmatter block.
16
+ */
17
+ export declare function removeFrontmatterField(content: string, key: string): string;
18
+ /**
19
+ * The post-condition of a frontmatter edit, checked by re-parsing rather than by trusting the editor.
20
+ * `expected` maps each field the operation owns to its required value (`undefined` = must be absent).
21
+ * Returns the problems found, empty when the edit is sound:
22
+ *
23
+ * - the rendered document has no frontmatter, or it does not parse;
24
+ * - an owned field does not have its expected value, or is still present when it should be removed;
25
+ * - any **other** field's parsed value differs from `before` — an edit leaked into a field it does not own.
26
+ *
27
+ * Deterministic (REQ-SYS-07): owned fields in `expected`'s order, then other fields sorted by name.
28
+ */
29
+ export declare function verifyFrontmatterEdit(before: string, after: string, expected: Readonly<Record<string, string | undefined>>): string[];
30
+ /**
31
+ * How much of a document an operation is entitled to change (task-088, `bug-076`), per
32
+ * `spec-010-memory-frontmatter-schema` § "Field-write ownership":
33
+ *
34
+ * - `declared-fields-only` — the operation owns `status` (plus `rejection_reason` on `memory.reject`)
35
+ * and **nothing else**: no other frontmatter field, and not one byte of the body. This is
36
+ * `memory.approve`, `memory.reject` and `memory.deprecate`.
37
+ * - `carries-content` — the operation is defined as filling content *and* moving state, so the body
38
+ * and the type's other frontmatter fields may legitimately change. This is `memory.submit` alone,
39
+ * and the asymmetry is deliberate rather than an oversight: an approval that carried a body would
40
+ * attest, under an approver's name, to content no commit subject mentions.
41
+ */
42
+ export type DocumentScope = 'declared-fields-only' | 'carries-content';
43
+ /**
44
+ * The post-condition of a whole-document edit: {@link verifyFrontmatterEdit}'s frontmatter rules plus
45
+ * the body, gated by `scope`. Returns the problems found, empty when the edit is within scope.
46
+ *
47
+ * Under `carries-content` only the `expected` fields are checked — every other field and the body are
48
+ * the operation's to write. Under `declared-fields-only` an unowned field or a changed body is a
49
+ * problem, which is the rule `bug-076` showed nothing was enforcing.
50
+ *
51
+ * Deterministic (REQ-SYS-07): owned fields in `expected`'s order, then other fields sorted by name,
52
+ * then the body.
53
+ */
54
+ export declare function verifyDocumentEdit(before: string, after: string, expected: Readonly<Record<string, string | undefined>>, scope: DocumentScope): string[];
55
+ /**
56
+ * Name, in a form a person can act on, every way `after` differs from `before` — the frontmatter
57
+ * fields whose parsed value moved, and whether the body moved. `before` is `null` when the document
58
+ * does not exist at the revision being compared against.
59
+ *
60
+ * This is the *reporting* half of {@link verifyDocumentEdit}: the verifier answers "is this edit in
61
+ * scope", this answers "so what exactly is in the way". A difference that changes no parsed value and
62
+ * no body byte — a reordered comment, a requoted scalar — is still a difference git will commit, so
63
+ * it is reported as such rather than dropped.
64
+ *
65
+ * Deterministic (REQ-SYS-07): fields sorted by name, then the frontmatter-text fallback, then the body.
66
+ */
67
+ export declare function describeDocumentChanges(before: string | null, after: string): string[];
68
+ //# sourceMappingURL=frontmatter-edit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"frontmatter-edit.d.ts","sourceRoot":"","sources":["../../src/memory/frontmatter-edit.ts"],"names":[],"mappings":"AAwKA;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAsBvF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK3E;AAeD;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAAG,MAAM,EAAE,CAOrI;AAkCD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,aAAa,GAAG,sBAAsB,GAAG,iBAAiB,CAAC;AAEvE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EACtD,KAAK,EAAE,aAAa,GACnB,MAAM,EAAE,CAYV;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBtF"}