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 @@
1
+ {"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/memory/submit.ts"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,qBAAqB,CAAC;AAUzD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAG3H;AAED,6GAA6G;AAC7G,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5E"}
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REJECTION_REASON_FIELD = void 0;
4
+ exports.missingRequiredFields = missingRequiredFields;
5
+ exports.renderSubmitDocument = renderSubmitDocument;
6
+ /**
7
+ * Pure helpers behind `wingfoil memory submit` (P1.6, task-045-memory-submit), kept out of the
8
+ * `CoreResult`-wrapped operation in `src/core` the same way `./add.ts` serves `memory add`.
9
+ *
10
+ * Both implement `spec-010-memory-frontmatter-schema`:
11
+ * - "Validation rules": `title`, and every field in the type's `template.frontmatter.required`, must
12
+ * be non-empty once `status` is anything other than `draft` — so a submit checks them first.
13
+ * - "Field-write ownership": `memory.submit` moves `status` to the next state and clears
14
+ * `rejection_reason` by removing the key (it mirrors only the most recent reject).
15
+ *
16
+ * Deterministic (REQ-SYS-07): results follow the declared field order, never object-key order.
17
+ */
18
+ const frontmatter_edit_1 = require("./frontmatter-edit");
19
+ /** The frontmatter key `memory.reject` sets and `memory.submit` removes (spec-010). */
20
+ exports.REJECTION_REASON_FIELD = 'rejection_reason';
21
+ /** Absent, `null`, a blank string or an empty list count as "not filled in". */
22
+ function isEmptyValue(value) {
23
+ if (value === undefined || value === null)
24
+ return true;
25
+ if (typeof value === 'string')
26
+ return value.trim().length === 0;
27
+ if (Array.isArray(value))
28
+ return value.length === 0;
29
+ return false;
30
+ }
31
+ /**
32
+ * The fields that must be filled before a submit but are not: `title` first (spec-010 requires it of
33
+ * every type), then each of `required` in its declared order, without duplicates. `[]` means the
34
+ * document may be submitted.
35
+ */
36
+ function missingRequiredFields(frontmatter, required) {
37
+ const fields = [...new Set(['title', ...required])];
38
+ return fields.filter((field) => isEmptyValue(frontmatter[field]));
39
+ }
40
+ /** The submitted document: `status` set to `target` and `rejection_reason` removed; nothing else changes. */
41
+ function renderSubmitDocument(content, target) {
42
+ return (0, frontmatter_edit_1.removeFrontmatterField)((0, frontmatter_edit_1.setFrontmatterField)(content, 'status', target), exports.REJECTION_REASON_FIELD);
43
+ }
44
+ //# sourceMappingURL=submit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"submit.js","sourceRoot":"","sources":["../../src/memory/submit.ts"],"names":[],"mappings":";;;AA8BA,sDAGC;AAGD,oDAEC;AAtCD;;;;;;;;;;;GAWG;AACH,yDAAiF;AAEjF,uFAAuF;AAC1E,QAAA,sBAAsB,GAAG,kBAAkB,CAAC;AAEzD,gFAAgF;AAChF,SAAS,YAAY,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,CAAC;IAChE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;IACpD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,SAAgB,qBAAqB,CAAC,WAA8C,EAAE,QAA2B;IAC/G,MAAM,MAAM,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,6GAA6G;AAC7G,SAAgB,oBAAoB,CAAC,OAAe,EAAE,MAAc;IAClE,OAAO,IAAA,yCAAsB,EAAC,IAAA,sCAAmB,EAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,8BAAsB,CAAC,CAAC;AACxG,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * The official built-in directive templates (P3.8, US-0A-09 — `task-057-builtin-directive-templates`):
3
+ * Code Quality, Testing, Code Review, Architecture, Security, Documentation.
4
+ *
5
+ * **Where they live and how they reach a project.** `spec-011-storage-layout` reserves
6
+ * `.wingfoil/directives/built-in/` for "the official P3.8 directive templates shipped by the `wingfoil`
7
+ * npm package", and `spec-015-packaging-publishing` §1 keeps the tarball allowlist at
8
+ * `files: ["dist", "README.md"]` — so the templates ship as DATA compiled into `dist/`, not as loose
9
+ * Markdown beside it. `templateScaffold` (./templates) renders them into the `ScaffoldFile[]` that
10
+ * `wingfoil init` writes, which is also the list `initWingfoilProject` schema-checks first (REQ-SEC-10,
11
+ * derived by `builtinTemplateSources`): adding or editing a template here is automatically checked.
12
+ *
13
+ * **Frontmatter** (`spec-013-directive-frontmatter-schema`): exactly the declared keys `id` (the filename
14
+ * stem), `name`, `type: directive`, `kind: built-in`, `title`, `tags`, `ref: [P3.8]`. No other key: an
15
+ * undeclared key rides `.passthrough()` and prints an `unknown field(s) ignored` warning on stderr during
16
+ * every `init` (task-044's hand-off).
17
+ *
18
+ * **Body**: normative, project-agnostic rules for AI agents and humans. Deliberately free of any
19
+ * project-specific identifier, date or version, and of credential-shaped example text — the `security`
20
+ * template must not trip the spec-007 secret scan it asks the reader to respect (asserted per template in
21
+ * `test/storage/builtin-directives.test.ts`).
22
+ *
23
+ * **Customization** (`dl-037-builtin-vs-custom-directive-precedence`, implemented by `task-055` in
24
+ * `selectDirectivesById`): a directive under `directives/custom/` with the same `id` wins over the
25
+ * built-in, and the shadow is reported as a warning. Built-ins themselves are non-removable
26
+ * (REQ-SEC-07, keyed on the `built-in/` directory).
27
+ *
28
+ * Pure data + a pure renderer (REQ-SYS-07): byte-identical output run to run.
29
+ */
30
+ /** One built-in directive template, as structured data rendered by {@link builtinDirectiveMd}. */
31
+ export interface BuiltinDirectiveTemplate {
32
+ /** Stable directive id — also the installed filename stem and the key `roles.yaml` binds on. */
33
+ readonly id: string;
34
+ /** Human-readable name; used as both `name` and `title` (spec-013 notes they coincide). */
35
+ readonly name: string;
36
+ /** One sentence naming who the directive applies to. */
37
+ readonly appliesTo: string;
38
+ /** The normative rules, in order, rendered as a Markdown bullet list. */
39
+ readonly rules: readonly string[];
40
+ }
41
+ /**
42
+ * The six P3.8 built-in directive templates, in the order the P3.8 feature lists them ("code-quality,
43
+ * testing, code-review, architecture, security, documentation"). Fixed order (REQ-SYS-07).
44
+ */
45
+ export declare const BUILTIN_DIRECTIVE_TEMPLATES: readonly BuiltinDirectiveTemplate[];
46
+ /** The built-in directive ids, in {@link BUILTIN_DIRECTIVE_TEMPLATES} order. */
47
+ export declare const BUILTIN_DIRECTIVE_IDS: readonly string[];
48
+ /**
49
+ * Render one built-in directive as the Markdown document installed at
50
+ * `.wingfoil/directives/built-in/<id>.md`: spec-013 frontmatter, then the rules, then a note on how to
51
+ * customize it. Pure — fixed strings only.
52
+ */
53
+ export declare function builtinDirectiveMd(t: BuiltinDirectiveTemplate): string;
54
+ //# sourceMappingURL=builtin-directives.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-directives.d.ts","sourceRoot":"","sources":["../../src/storage/builtin-directives.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,kGAAkG;AAClG,MAAM,WAAW,wBAAwB;IACvC,gGAAgG;IAChG,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2FAA2F;IAC3F,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAoFD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,SAAS,wBAAwB,EAO1E,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,qBAAqB,EAAE,SAAS,MAAM,EAAiD,CAAC;AAErG;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,wBAAwB,GAAG,MAAM,CAsBtE"}
@@ -0,0 +1,152 @@
1
+ "use strict";
2
+ /**
3
+ * The official built-in directive templates (P3.8, US-0A-09 — `task-057-builtin-directive-templates`):
4
+ * Code Quality, Testing, Code Review, Architecture, Security, Documentation.
5
+ *
6
+ * **Where they live and how they reach a project.** `spec-011-storage-layout` reserves
7
+ * `.wingfoil/directives/built-in/` for "the official P3.8 directive templates shipped by the `wingfoil`
8
+ * npm package", and `spec-015-packaging-publishing` §1 keeps the tarball allowlist at
9
+ * `files: ["dist", "README.md"]` — so the templates ship as DATA compiled into `dist/`, not as loose
10
+ * Markdown beside it. `templateScaffold` (./templates) renders them into the `ScaffoldFile[]` that
11
+ * `wingfoil init` writes, which is also the list `initWingfoilProject` schema-checks first (REQ-SEC-10,
12
+ * derived by `builtinTemplateSources`): adding or editing a template here is automatically checked.
13
+ *
14
+ * **Frontmatter** (`spec-013-directive-frontmatter-schema`): exactly the declared keys `id` (the filename
15
+ * stem), `name`, `type: directive`, `kind: built-in`, `title`, `tags`, `ref: [P3.8]`. No other key: an
16
+ * undeclared key rides `.passthrough()` and prints an `unknown field(s) ignored` warning on stderr during
17
+ * every `init` (task-044's hand-off).
18
+ *
19
+ * **Body**: normative, project-agnostic rules for AI agents and humans. Deliberately free of any
20
+ * project-specific identifier, date or version, and of credential-shaped example text — the `security`
21
+ * template must not trip the spec-007 secret scan it asks the reader to respect (asserted per template in
22
+ * `test/storage/builtin-directives.test.ts`).
23
+ *
24
+ * **Customization** (`dl-037-builtin-vs-custom-directive-precedence`, implemented by `task-055` in
25
+ * `selectDirectivesById`): a directive under `directives/custom/` with the same `id` wins over the
26
+ * built-in, and the shadow is reported as a warning. Built-ins themselves are non-removable
27
+ * (REQ-SEC-07, keyed on the `built-in/` directory).
28
+ *
29
+ * Pure data + a pure renderer (REQ-SYS-07): byte-identical output run to run.
30
+ */
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ exports.BUILTIN_DIRECTIVE_IDS = exports.BUILTIN_DIRECTIVE_TEMPLATES = void 0;
33
+ exports.builtinDirectiveMd = builtinDirectiveMd;
34
+ const CODE_QUALITY = {
35
+ id: 'code-quality',
36
+ name: 'Code Quality',
37
+ appliesTo: 'Applies to every role that writes or changes code.',
38
+ rules: [
39
+ 'The linter reports no errors; warnings are triaged before a change is merged.',
40
+ 'Prefer small, single-responsibility functions and modules; keep complexity low.',
41
+ 'No dead code and no commented-out blocks.',
42
+ 'Match the style, naming and idioms of the surrounding code.',
43
+ 'Give public interfaces explicit types and validate external input at system boundaries.',
44
+ 'Keep each commit to one logical change with a descriptive message.',
45
+ ],
46
+ };
47
+ const TESTING = {
48
+ id: 'testing',
49
+ name: 'Testing',
50
+ appliesTo: 'Applies to developers and QA.',
51
+ rules: [
52
+ 'Test first: write a failing test before the implementation (red, green, refactor).',
53
+ 'Classify each acceptance criterion before testing it: red-first when the behaviour is new, characterization when the behaviour already exists and the test is expected to pass on its first run. Never fabricate a failing test or add dead code to force one.',
54
+ 'Every behaviour has at least one happy-path test and one edge- or error-path test.',
55
+ 'Keep coverage at or above the threshold the project declares; coverage must not regress.',
56
+ 'Tests are deterministic and isolated: no reliance on external services, wall-clock time or randomness.',
57
+ ],
58
+ };
59
+ const CODE_REVIEW = {
60
+ id: 'code-review',
61
+ name: 'Code Review',
62
+ appliesTo: 'Applies to reviewers and to whoever holds approval authority.',
63
+ rules: [
64
+ 'Check every change for correctness, tests that are present and passing, adherence to the other directives, and the absence of secrets.',
65
+ 'Verify the change satisfies the acceptance criteria of the task it implements.',
66
+ 'Verify claims by running the command that settles them; do not accept a statement about a file or test without checking it.',
67
+ 'Every finding is either fixed in the change or recorded as a tracked element (a bug or a decision-log); never leave a finding only in review notes.',
68
+ 'Approve or reject with a recorded reason; a rejection states what must change before resubmitting.',
69
+ 'Approval authority belongs to a role, not to a person; AI agents never approve their own work.',
70
+ ],
71
+ };
72
+ const ARCHITECTURE = {
73
+ id: 'architecture',
74
+ name: 'Architecture',
75
+ appliesTo: 'Applies to architects and the tech lead.',
76
+ rules: [
77
+ 'Record every significant architectural decision as an ADR stating its context, the decision and its consequences.',
78
+ 'Every architectural decision references the requirement or requirements it implements.',
79
+ 'Keep modules cohesive and loosely coupled; a change in one module must not force edits in unrelated ones.',
80
+ 'Write a technical specification for every shared file format, schema, constant set or module API before the work that implements it starts.',
81
+ 'Before approving a specification or an ADR, check that it is internally consistent, consistent with the already-approved specifications, aligned with the acceptance criteria, and traceable to its requirements.',
82
+ ],
83
+ };
84
+ const SECURITY = {
85
+ id: 'security',
86
+ name: 'Security',
87
+ appliesTo: 'Applies to every role.',
88
+ rules: [
89
+ 'Never hardcode credentials, tokens, private keys or other secrets in source code, configuration, documentation or project memory.',
90
+ 'Keep secrets out of version control; supply them at runtime from the environment or a secret manager.',
91
+ 'When an example needs a credential, describe it in words or use an obvious placeholder; never paste a real value.',
92
+ 'Validate and sanitize all external input at trust boundaries.',
93
+ 'Grant the least privilege each component needs.',
94
+ 'Review dependencies for known vulnerabilities before adding or upgrading them.',
95
+ ],
96
+ };
97
+ const DOCUMENTATION = {
98
+ id: 'documentation',
99
+ name: 'Documentation',
100
+ appliesTo: 'Applies to every role.',
101
+ rules: [
102
+ 'Document every user-facing command and feature before it ships.',
103
+ 'Update the affected documentation in the same change that alters behaviour.',
104
+ 'Every public or exported API element carries a doc comment.',
105
+ 'Record decisions in project memory (ADRs for architectural decisions, decision-logs for product and process decisions), not scattered through the codebase.',
106
+ 'Keep cross-references between documents intact.',
107
+ 'Document why, not only what.',
108
+ ],
109
+ };
110
+ /**
111
+ * The six P3.8 built-in directive templates, in the order the P3.8 feature lists them ("code-quality,
112
+ * testing, code-review, architecture, security, documentation"). Fixed order (REQ-SYS-07).
113
+ */
114
+ exports.BUILTIN_DIRECTIVE_TEMPLATES = [
115
+ CODE_QUALITY,
116
+ TESTING,
117
+ CODE_REVIEW,
118
+ ARCHITECTURE,
119
+ SECURITY,
120
+ DOCUMENTATION,
121
+ ];
122
+ /** The built-in directive ids, in {@link BUILTIN_DIRECTIVE_TEMPLATES} order. */
123
+ exports.BUILTIN_DIRECTIVE_IDS = exports.BUILTIN_DIRECTIVE_TEMPLATES.map((t) => t.id);
124
+ /**
125
+ * Render one built-in directive as the Markdown document installed at
126
+ * `.wingfoil/directives/built-in/<id>.md`: spec-013 frontmatter, then the rules, then a note on how to
127
+ * customize it. Pure — fixed strings only.
128
+ */
129
+ function builtinDirectiveMd(t) {
130
+ const rules = t.rules.map((rule) => `- ${rule}`).join('\n');
131
+ return `---
132
+ id: ${t.id}
133
+ name: "${t.name}"
134
+ type: directive
135
+ kind: built-in
136
+ title: "${t.name}"
137
+ tags: [built-in, ${t.id}]
138
+ ref: [P3.8]
139
+ ---
140
+
141
+ # Directive — ${t.name}
142
+
143
+ ${t.appliesTo}
144
+
145
+ ${rules}
146
+
147
+ > Built-in WingFoil directive template. It cannot be removed. To adapt it, create
148
+ > \`directives/custom/${t.id}.md\` with \`id: ${t.id}\`: a custom directive with the same id takes
149
+ > precedence over this one, and \`wingfoil directives list\` reports the override.
150
+ `;
151
+ }
152
+ //# sourceMappingURL=builtin-directives.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-directives.js","sourceRoot":"","sources":["../../src/storage/builtin-directives.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;;;AAqHH,gDAsBC;AA7HD,MAAM,YAAY,GAA6B;IAC7C,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,cAAc;IACpB,SAAS,EAAE,oDAAoD;IAC/D,KAAK,EAAE;QACL,+EAA+E;QAC/E,iFAAiF;QACjF,2CAA2C;QAC3C,6DAA6D;QAC7D,yFAAyF;QACzF,oEAAoE;KACrE;CACF,CAAC;AAEF,MAAM,OAAO,GAA6B;IACxC,EAAE,EAAE,SAAS;IACb,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,+BAA+B;IAC1C,KAAK,EAAE;QACL,oFAAoF;QACpF,gQAAgQ;QAChQ,oFAAoF;QACpF,0FAA0F;QAC1F,wGAAwG;KACzG;CACF,CAAC;AAEF,MAAM,WAAW,GAA6B;IAC5C,EAAE,EAAE,aAAa;IACjB,IAAI,EAAE,aAAa;IACnB,SAAS,EAAE,+DAA+D;IAC1E,KAAK,EAAE;QACL,wIAAwI;QACxI,gFAAgF;QAChF,6HAA6H;QAC7H,qJAAqJ;QACrJ,oGAAoG;QACpG,gGAAgG;KACjG;CACF,CAAC;AAEF,MAAM,YAAY,GAA6B;IAC7C,EAAE,EAAE,cAAc;IAClB,IAAI,EAAE,cAAc;IACpB,SAAS,EAAE,0CAA0C;IACrD,KAAK,EAAE;QACL,mHAAmH;QACnH,wFAAwF;QACxF,2GAA2G;QAC3G,6IAA6I;QAC7I,mNAAmN;KACpN;CACF,CAAC;AAEF,MAAM,QAAQ,GAA6B;IACzC,EAAE,EAAE,UAAU;IACd,IAAI,EAAE,UAAU;IAChB,SAAS,EAAE,wBAAwB;IACnC,KAAK,EAAE;QACL,mIAAmI;QACnI,uGAAuG;QACvG,mHAAmH;QACnH,+DAA+D;QAC/D,iDAAiD;QACjD,gFAAgF;KACjF;CACF,CAAC;AAEF,MAAM,aAAa,GAA6B;IAC9C,EAAE,EAAE,eAAe;IACnB,IAAI,EAAE,eAAe;IACrB,SAAS,EAAE,wBAAwB;IACnC,KAAK,EAAE;QACL,iEAAiE;QACjE,6EAA6E;QAC7E,6DAA6D;QAC7D,6JAA6J;QAC7J,iDAAiD;QACjD,8BAA8B;KAC/B;CACF,CAAC;AAEF;;;GAGG;AACU,QAAA,2BAA2B,GAAwC;IAC9E,YAAY;IACZ,OAAO;IACP,WAAW;IACX,YAAY;IACZ,QAAQ;IACR,aAAa;CACd,CAAC;AAEF,gFAAgF;AACnE,QAAA,qBAAqB,GAAsB,mCAA2B,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAErG;;;;GAIG;AACH,SAAgB,kBAAkB,CAAC,CAA2B;IAC5D,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,OAAO;MACH,CAAC,CAAC,EAAE;SACD,CAAC,CAAC,IAAI;;;UAGL,CAAC,CAAC,IAAI;mBACG,CAAC,CAAC,EAAE;;;;gBAIP,CAAC,CAAC,IAAI;;EAEpB,CAAC,CAAC,SAAS;;EAEX,KAAK;;;wBAGiB,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,EAAE;;CAEnD,CAAC;AACF,CAAC"}
@@ -0,0 +1,92 @@
1
+ /** Options for {@link commitPaths} — carries the git-author/env override used by callers (e.g. task-029's wizard). */
2
+ export interface CommitOptions {
3
+ /** Additional environment for the git invocations (merged over `process.env`). */
4
+ readonly env?: NodeJS.ProcessEnv;
5
+ }
6
+ /**
7
+ * Stage exactly `paths` (root-relative or absolute; each passed verbatim after `--` so a path that
8
+ * looks like a flag is never misread) and create a single commit with `message` that contains **only**
9
+ * those paths, returning the new commit's 40-hex sha. Other changes already staged in the index are
10
+ * neither committed nor unstaged (bug-027) — this also holds for the first commit of an empty
11
+ * repository (`wingfoil init`).
12
+ *
13
+ * Determinism note (REQ-SYS-07): a git commit's sha necessarily incorporates the author/commit
14
+ * timestamp, so two runs produce different shas — that is inherent to *creating* history and is not
15
+ * a context-building read path (the determinism rule targets read/derivation paths, e.g.
16
+ * `computeStateSnapshot`), so it is correct and intended here.
17
+ *
18
+ * @throws whatever `git` raises (via `execFileSync`) — e.g. nothing staged to commit, or `root` is
19
+ * not a git repository. Callers that must translate those into a `CoreResult` do so at their layer
20
+ * (see `src/core/init.ts`); this primitive stays a thin, throwing mechanism by design.
21
+ */
22
+ export declare function commitPaths(root: string, paths: readonly string[], message: string, options?: CommitOptions): string;
23
+ /**
24
+ * git's canonical empty tree object, the same on every repository (`git hash-object -t tree
25
+ * /dev/null`). Used as the parent of a **root** commit so "what changed between this commit and its
26
+ * parent" is total rather than conditional.
27
+ */
28
+ export declare const EMPTY_TREE_SHA = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
29
+ /**
30
+ * The content of `path` at revision `rev`, or `null` when the path does not exist there (git exits
31
+ * non-zero, which `execFileSync` raises).
32
+ *
33
+ * `rev` is any revision git accepts before a `:` — a sha, `HEAD`, or the index stage `:0`, which is
34
+ * how a caller reads what the user has **staged** as opposed to what is in the working tree. The two
35
+ * can disagree, and the difference is load-bearing: `git add` would silently replace a staged version
36
+ * with the working-tree one.
37
+ */
38
+ export declare function readPathAtRev(root: string, rev: string, path: string, options?: CommitOptions): string | null;
39
+ /**
40
+ * The two-character `git status --porcelain` code for `path` (index status, then working-tree
41
+ * status), or the empty string when the path is clean — unmodified in both, and tracked.
42
+ *
43
+ * Deliberately git's own answer rather than a content comparison: git owns what "modified" means
44
+ * here (index refresh, `core.autocrlf`, `.gitattributes` filters), and a caller that re-derived it
45
+ * from bytes would disagree with `git status` on exactly the machines where it matters.
46
+ */
47
+ export declare function pathPorcelainStatus(root: string, path: string, options?: CommitOptions): string;
48
+ /** The commit's parent sha, or {@link EMPTY_TREE_SHA} when it is a root commit. */
49
+ export declare function commitParent(root: string, sha: string, options?: CommitOptions): string;
50
+ /** Root-relative paths whose content differs between revisions `from` and `to`, in git's own order. */
51
+ export declare function changedPathsBetween(root: string, from: string, to: string, options?: CommitOptions): string[];
52
+ /**
53
+ * Every **file** that exists at revision `rev` under `prefix`, recursively, as root-relative POSIX
54
+ * paths sorted ascending — the directory counterpart of {@link readPathAtRev}, and the primitive a
55
+ * read whose baseline is a *directory* needs (`task-096`, `bug-086`).
56
+ *
57
+ * `readPathAtRev` answers "what does this one path contain at `<rev>`", which is enough while every
58
+ * committed-baseline read is of a file named in advance (`.wingfoil/dna.yaml`,
59
+ * `.wingfoil/memory.yaml`). It is not enough for `.wingfoil/directives/**`, whose members are
60
+ * discovered rather than named: without this, resolving the directive inventory at `HEAD` was
61
+ * impossible and `task-091` scoped `bug-086` out on exactly that ground. The two compose — list, then
62
+ * read each entry — and `src/core/loaders.ts`'s `loadDirectivesAtHead` is the first caller to do so.
63
+ *
64
+ * **Blobs only.** Whatever this returns must be readable with `readPathAtRev` at the same revision; a
65
+ * gitlink would break that, so it is filtered out rather than reported as a file.
66
+ *
67
+ * **`-z`, not the default output.** Without it git C-quotes a path containing a byte outside printable
68
+ * ASCII (`core.quotePath`, on by default), a control byte, a `"` or a `\`: it wraps the whole name in
69
+ * double quotes and escapes the offending bytes, so `caffè.md` is reported as `"caff\303\250.md"` and
70
+ * a caller then looks for a file whose name it has mis-spelled. A **space is not quoted** — worth
71
+ * naming because it makes `two words.md` a useless test of this property, and only a name git really
72
+ * quotes can hold the flag in place (`test/storage/list-paths-at-rev.test.ts`, "the `-z` pin"). With
73
+ * `-z` the records are NUL-separated and never quoted, whatever the bytes.
74
+ *
75
+ * **`null` is not `[]`.** `[]` means *the revision exists and holds nothing under `prefix`*; `null`
76
+ * means *`rev` does not resolve at all* — an unborn `HEAD` in a repository with no commits, or a name
77
+ * no object carries. A caller that must fail closed when there is no committed baseline has to be able
78
+ * to tell those apart; one that only wants "what is committed there" can write `?? []`.
79
+ *
80
+ * **Sorted explicitly** even though git's own output already is (REQ-SYS-07: no unordered iteration in
81
+ * a context-building path — the working-tree walk in `loadDirectives` sorts for the same reason, and
82
+ * the two must not differ by accident).
83
+ *
84
+ * @param root - Project root (the git repository).
85
+ * @param rev - Any tree-ish git accepts: a sha, `HEAD`, `HEAD~1`, a tag.
86
+ * @param prefix - Root-relative directory to limit the listing to; **omitted or empty lists the whole
87
+ * tree**, because `git ls-tree -- ''` is an error rather than a match-all. Passed verbatim after
88
+ * `--`, so a path that looks like a flag is never misread.
89
+ * @returns The paths, or `null` when `rev` does not resolve.
90
+ */
91
+ export declare function listPathsAtRev(root: string, rev: string, prefix?: string, options?: CommitOptions): string[] | null;
92
+ //# sourceMappingURL=commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.d.ts","sourceRoot":"","sources":["../../src/storage/commit.ts"],"names":[],"mappings":"AAoBA,sHAAsH;AACtH,MAAM,WAAW,aAAa;IAC5B,kFAAkF;IAClF,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAClC;AA6BD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,aAAkB,GAC1B,MAAM,CAOR;AASD;;;;GAIG;AACH,eAAO,MAAM,cAAc,6CAA6C,CAAC;AAEzE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,GAAG,IAAI,CAMjH;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAMnG;AAED,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,CAM3F;AAED,uGAAuG;AACvG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,MAAM,EAAE,CAIjH;AAYD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,MAAM,SAAK,EACX,OAAO,GAAE,aAAkB,GAC1B,MAAM,EAAE,GAAG,IAAI,CAejB"}
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.EMPTY_TREE_SHA = void 0;
4
+ exports.commitPaths = commitPaths;
5
+ exports.readPathAtRev = readPathAtRev;
6
+ exports.pathPorcelainStatus = pathPorcelainStatus;
7
+ exports.commitParent = commitParent;
8
+ exports.changedPathsBetween = changedPathsBetween;
9
+ exports.listPathsAtRev = listPathsAtRev;
10
+ /**
11
+ * The reusable git-commit primitive (task-018-implement-git-backed-storage, P1.1, REQ-SYS-01).
12
+ *
13
+ * `writeDocument` (./document) writes bytes only; nothing else in `src/storage` turns a set of
14
+ * writes into a commit, yet every mutating core operation must return a `CoreResult.commit`
15
+ * `{sha, message}` (src/core/types). This is that missing producer: it stages **only** the scoped
16
+ * paths it is handed — never `git add -A`/`git add .`, which would sweep in unrelated working-tree
17
+ * changes (and, in a WingFoil worktree, the `node_modules` symlink) — and produces **exactly one**
18
+ * commit, returning its full sha. Every mutating Wave-3 task (task-019 versioning, task-020 memory
19
+ * add, task-025 dna set, task-029 `wingfoil init`) turns its writes into a single attributable
20
+ * commit through this one helper, so the "one operation = one scoped commit" convention
21
+ * (CLAUDE.md §5.1) has a single implementation rather than being re-derived per task.
22
+ *
23
+ * Mirrors the git-primitive style in `src/memory/git-log.ts`: `execFileSync('git', …)` (never a
24
+ * shell), `-C <root>` to target the repository, and `env: process.env` passed **explicitly** — the
25
+ * latter matters under Jest, whose worker env is not the ambient shell's, so relying on the default
26
+ * env silently drops `GIT_*` overrides a test sets (the task-014 env-isolation gotcha).
27
+ */
28
+ const child_process_1 = require("child_process");
29
+ function runGit(root, args, options) {
30
+ return (0, child_process_1.execFileSync)('git', ['-C', root, ...args], {
31
+ encoding: 'utf-8',
32
+ env: options.env ? { ...process.env, ...options.env } : process.env,
33
+ });
34
+ }
35
+ /**
36
+ * {@link runGit} for a **probe** — an invocation whose failure is an expected answer rather than an
37
+ * error, or whose stderr is noise the caller must not surface, so git's own diagnostic does not reach
38
+ * the caller's stderr. Without `stdio[2]: 'ignore'`, `execFileSync` inherits fd 2 and
39
+ * `git show HEAD:<untracked>` prints `fatal: path … exists on disk, but not in 'HEAD'` into the
40
+ * user's terminal alongside the message the CLI actually meant to emit.
41
+ *
42
+ * The second case arrived with task-092: `git status --porcelain -- <path>` exits **0** but prints
43
+ * `warning: could not open directory '<dir>/': No such file or directory` when an intermediate
44
+ * directory of the pathspec is absent — the ordinary case for a write guard asking about a file that
45
+ * has not been created yet. A non-zero exit still raises through `execFileSync` exactly as before.
46
+ */
47
+ function probeGit(root, args, options) {
48
+ return (0, child_process_1.execFileSync)('git', ['-C', root, ...args], {
49
+ encoding: 'utf-8',
50
+ env: options.env ? { ...process.env, ...options.env } : process.env,
51
+ stdio: ['ignore', 'pipe', 'ignore'],
52
+ });
53
+ }
54
+ /**
55
+ * Stage exactly `paths` (root-relative or absolute; each passed verbatim after `--` so a path that
56
+ * looks like a flag is never misread) and create a single commit with `message` that contains **only**
57
+ * those paths, returning the new commit's 40-hex sha. Other changes already staged in the index are
58
+ * neither committed nor unstaged (bug-027) — this also holds for the first commit of an empty
59
+ * repository (`wingfoil init`).
60
+ *
61
+ * Determinism note (REQ-SYS-07): a git commit's sha necessarily incorporates the author/commit
62
+ * timestamp, so two runs produce different shas — that is inherent to *creating* history and is not
63
+ * a context-building read path (the determinism rule targets read/derivation paths, e.g.
64
+ * `computeStateSnapshot`), so it is correct and intended here.
65
+ *
66
+ * @throws whatever `git` raises (via `execFileSync`) — e.g. nothing staged to commit, or `root` is
67
+ * not a git repository. Callers that must translate those into a `CoreResult` do so at their layer
68
+ * (see `src/core/init.ts`); this primitive stays a thin, throwing mechanism by design.
69
+ */
70
+ function commitPaths(root, paths, message, options = {}) {
71
+ runGit(root, ['add', '--', ...paths], options);
72
+ // `--only -- <paths>` records exactly these paths, whatever else is staged: anything a caller or
73
+ // another tool already staged stays staged and uncommitted (bug-027). A plain `git commit` would
74
+ // commit the whole index under a subject that names only this operation.
75
+ runGit(root, ['commit', '--only', '--quiet', '-m', message, '--', ...paths], options);
76
+ return runGit(root, ['rev-parse', 'HEAD'], options).trim();
77
+ }
78
+ // --- Read primitives for asserting what a commit CONTAINS (task-088, bug-076) ------------------
79
+ //
80
+ // `commitPaths` above bounds a commit by *pathspec*; nothing bounded it by *content*, so a path that
81
+ // was already modified on disk rode into a commit whose subject declared only a state change. The
82
+ // three readers below are what lets a caller assert the diff a commit actually carries, instead of
83
+ // re-reading the file on disk and finding — truthfully, and uselessly — that it says what it should.
84
+ /**
85
+ * git's canonical empty tree object, the same on every repository (`git hash-object -t tree
86
+ * /dev/null`). Used as the parent of a **root** commit so "what changed between this commit and its
87
+ * parent" is total rather than conditional.
88
+ */
89
+ exports.EMPTY_TREE_SHA = '4b825dc642cb6eb9a060e54bf8d69288fbee4904';
90
+ /**
91
+ * The content of `path` at revision `rev`, or `null` when the path does not exist there (git exits
92
+ * non-zero, which `execFileSync` raises).
93
+ *
94
+ * `rev` is any revision git accepts before a `:` — a sha, `HEAD`, or the index stage `:0`, which is
95
+ * how a caller reads what the user has **staged** as opposed to what is in the working tree. The two
96
+ * can disagree, and the difference is load-bearing: `git add` would silently replace a staged version
97
+ * with the working-tree one.
98
+ */
99
+ function readPathAtRev(root, rev, path, options = {}) {
100
+ try {
101
+ return probeGit(root, ['show', `${rev}:${path}`], options);
102
+ }
103
+ catch {
104
+ return null;
105
+ }
106
+ }
107
+ /**
108
+ * The two-character `git status --porcelain` code for `path` (index status, then working-tree
109
+ * status), or the empty string when the path is clean — unmodified in both, and tracked.
110
+ *
111
+ * Deliberately git's own answer rather than a content comparison: git owns what "modified" means
112
+ * here (index refresh, `core.autocrlf`, `.gitattributes` filters), and a caller that re-derived it
113
+ * from bytes would disagree with `git status` on exactly the machines where it matters.
114
+ */
115
+ function pathPorcelainStatus(root, path, options = {}) {
116
+ // `probeGit`, not `runGit`: git writes a `warning: could not open directory …` to stderr — while
117
+ // still exiting 0 and answering correctly — whenever an intermediate directory of the pathspec is
118
+ // absent, which is routine for a guard asking about a file that does not exist yet (task-092).
119
+ const line = probeGit(root, ['status', '--porcelain', '--', path], options).split('\n')[0] ?? '';
120
+ return line.length === 0 ? '' : line.slice(0, 2);
121
+ }
122
+ /** The commit's parent sha, or {@link EMPTY_TREE_SHA} when it is a root commit. */
123
+ function commitParent(root, sha, options = {}) {
124
+ try {
125
+ return probeGit(root, ['rev-parse', '--verify', '--quiet', `${sha}^`], options).trim();
126
+ }
127
+ catch {
128
+ return exports.EMPTY_TREE_SHA;
129
+ }
130
+ }
131
+ /** Root-relative paths whose content differs between revisions `from` and `to`, in git's own order. */
132
+ function changedPathsBetween(root, from, to, options = {}) {
133
+ return runGit(root, ['diff', '--name-only', from, to], options)
134
+ .split('\n')
135
+ .filter((path) => path.length > 0);
136
+ }
137
+ // --- Listing a DIRECTORY at a revision (task-096, bug-086) -------------------------------------
138
+ /**
139
+ * One `git ls-tree -z` record: `<mode> SP <type> SP <object> TAB <path>`. Matched rather than split
140
+ * so that (a) only **blobs** survive — a gitlink (submodule, mode `160000`) is an entry in the tree
141
+ * but not a file anyone can read back — and (b) the path is taken verbatim from the first TAB
142
+ * onwards, which is the one separator a path cannot contain.
143
+ */
144
+ const LS_TREE_BLOB_RECORD = /^\d+ blob [0-9a-f]+\t/;
145
+ /**
146
+ * Every **file** that exists at revision `rev` under `prefix`, recursively, as root-relative POSIX
147
+ * paths sorted ascending — the directory counterpart of {@link readPathAtRev}, and the primitive a
148
+ * read whose baseline is a *directory* needs (`task-096`, `bug-086`).
149
+ *
150
+ * `readPathAtRev` answers "what does this one path contain at `<rev>`", which is enough while every
151
+ * committed-baseline read is of a file named in advance (`.wingfoil/dna.yaml`,
152
+ * `.wingfoil/memory.yaml`). It is not enough for `.wingfoil/directives/**`, whose members are
153
+ * discovered rather than named: without this, resolving the directive inventory at `HEAD` was
154
+ * impossible and `task-091` scoped `bug-086` out on exactly that ground. The two compose — list, then
155
+ * read each entry — and `src/core/loaders.ts`'s `loadDirectivesAtHead` is the first caller to do so.
156
+ *
157
+ * **Blobs only.** Whatever this returns must be readable with `readPathAtRev` at the same revision; a
158
+ * gitlink would break that, so it is filtered out rather than reported as a file.
159
+ *
160
+ * **`-z`, not the default output.** Without it git C-quotes a path containing a byte outside printable
161
+ * ASCII (`core.quotePath`, on by default), a control byte, a `"` or a `\`: it wraps the whole name in
162
+ * double quotes and escapes the offending bytes, so `caffè.md` is reported as `"caff\303\250.md"` and
163
+ * a caller then looks for a file whose name it has mis-spelled. A **space is not quoted** — worth
164
+ * naming because it makes `two words.md` a useless test of this property, and only a name git really
165
+ * quotes can hold the flag in place (`test/storage/list-paths-at-rev.test.ts`, "the `-z` pin"). With
166
+ * `-z` the records are NUL-separated and never quoted, whatever the bytes.
167
+ *
168
+ * **`null` is not `[]`.** `[]` means *the revision exists and holds nothing under `prefix`*; `null`
169
+ * means *`rev` does not resolve at all* — an unborn `HEAD` in a repository with no commits, or a name
170
+ * no object carries. A caller that must fail closed when there is no committed baseline has to be able
171
+ * to tell those apart; one that only wants "what is committed there" can write `?? []`.
172
+ *
173
+ * **Sorted explicitly** even though git's own output already is (REQ-SYS-07: no unordered iteration in
174
+ * a context-building path — the working-tree walk in `loadDirectives` sorts for the same reason, and
175
+ * the two must not differ by accident).
176
+ *
177
+ * @param root - Project root (the git repository).
178
+ * @param rev - Any tree-ish git accepts: a sha, `HEAD`, `HEAD~1`, a tag.
179
+ * @param prefix - Root-relative directory to limit the listing to; **omitted or empty lists the whole
180
+ * tree**, because `git ls-tree -- ''` is an error rather than a match-all. Passed verbatim after
181
+ * `--`, so a path that looks like a flag is never misread.
182
+ * @returns The paths, or `null` when `rev` does not resolve.
183
+ */
184
+ function listPathsAtRev(root, rev, prefix = '', options = {}) {
185
+ const pathspec = prefix.length === 0 ? [] : ['--', prefix];
186
+ let records;
187
+ try {
188
+ // `probeGit`: an unresolvable revision is an expected answer here, and git's `fatal: Not a valid
189
+ // object name` must not reach the user's terminal beside the CLI's own message.
190
+ records = probeGit(root, ['ls-tree', '-r', '-z', '--full-tree', rev, ...pathspec], options);
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ return records
196
+ .split('\0')
197
+ .filter((record) => LS_TREE_BLOB_RECORD.test(record))
198
+ .map((record) => record.slice(record.indexOf('\t') + 1))
199
+ .sort();
200
+ }
201
+ //# sourceMappingURL=commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../src/storage/commit.ts"],"names":[],"mappings":"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"}