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,307 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.E_EMPTY_SEARCH_QUERY = void 0;
4
+ exports.computeMemoryContentRoots = computeMemoryContentRoots;
5
+ exports.listMemoryDocumentPaths = listMemoryDocumentPaths;
6
+ exports.loadMemoryDocumentSummary = loadMemoryDocumentSummary;
7
+ exports.findMemoryDocumentById = findMemoryDocumentById;
8
+ exports.listMemoryDocumentsByType = listMemoryDocumentsByType;
9
+ exports.findMemoryDocumentByTypeAndId = findMemoryDocumentByTypeAndId;
10
+ exports.validateSearchQuery = validateSearchQuery;
11
+ exports.searchMemoryDocuments = searchMemoryDocuments;
12
+ /**
13
+ * Memory query primitives (task-008-dna-memory-query-latency, REQ-PERF-02; match/rank algorithm and
14
+ * empty-query validation hardened by task-023-implement-keyword-search, P1.12) — the performance-
15
+ * bearing foundation `wingfoil memory search` (task-021-implement-memory-search, P1.5) builds its
16
+ * CLI/MCP surface on top of. Deliberately NOT wired into `src/core`'s `CORE_MODULES` registry yet
17
+ * (see the task's Execution Notes for the scoping decision): this module ships the scan +
18
+ * keyword/frontmatter relevance primitives plus the query-validation guard, not the `--tag` CLI
19
+ * grammar, output rendering, or the "no documents matched" exit-code contract, which are task-021's
20
+ * own scope.
21
+ *
22
+ * Three things keep this fast and correct at the 1,000-Memory-document reference scale (REQ-PERF-02)
23
+ * and satisfy P1.12's fit criteria:
24
+ *
25
+ * - **Path-pattern-derived scan roots** (spec-011-storage-layout): rather than walking the whole
26
+ * project tree, {@link computeMemoryContentRoots} derives the minimal set of directories to scan
27
+ * from `memory.yaml`'s per-type `path` patterns (spec-001-memory-yaml-schema) — the same
28
+ * predictability spec-011 calls out as what keeps `memory search`/`history` from needing a
29
+ * full-repo walk for every query.
30
+ * - **Deterministic keyword/frontmatter relevance, not full-text/semantic search**
31
+ * (spec-012-context-loader-relevance-filtering's discipline, applied here to `memory search`
32
+ * rather than the Agent Context Loader spec-012 itself defines): a metadata match (title/id/tag)
33
+ * ranks above a body-only match (P1.12-keyword-search.feature Scenario 1), case-insensitive
34
+ * substring matching (Scenario 2), sorted with a total, deterministic order (REQ-SYS-07: no
35
+ * unordered iteration in a query-building path). Both were already satisfied by
36
+ * {@link searchMemoryDocuments} as shipped by task-008 — task-023 verified this against P1.12's
37
+ * fit criteria and added characterization tests, no algorithm change was needed.
38
+ * - **Empty-query rejection** ({@link validateSearchQuery}, P1.12-keyword-search.feature Scenario 3):
39
+ * a genuine gap task-008 left open (an empty query previously matched every document instead of
40
+ * being rejected) — task-023 closed it with a `ValidationError.semantic` guard a caller runs before
41
+ * invoking {@link searchMemoryDocuments}, exiting 2 with message "empty search query".
42
+ *
43
+ * **Archived-exclusion (REQ-STATE-06, task-038-deprecated-excluded-from-context; set widened by
44
+ * `dl-028-archived-states-excluded-from-context`):** {@link searchMemoryDocuments} excludes documents
45
+ * in an archived state from its default result — an archived document "never appears in … default
46
+ * `memory search` results" (the SARD Fit Criterion) while staying present on disk and in git history.
47
+ * The archived set is `{deprecated, superseded}` and the single shared check is
48
+ * `state-machine.ts`'s {@link isArchivedStatus} (it superseded task-038's `isDeprecatedStatus`), so
49
+ * the Agent Context Loader relevance-filter (spec-012 §6, `src/core/relevance.ts`) applies the same
50
+ * predicate rather than re-deciding what "archived" means. {@link MemorySearchOptions.includeArchived}
51
+ * is the explicit opt-out.
52
+ *
53
+ * `draft` is deliberately NOT excluded here: spec-012 §6 excludes drafts from an assembled agent
54
+ * *context*, but REQ-STATE-06 scopes default-search exclusion to archived content only, so a draft
55
+ * document a user is actively working on stays findable. The two filters are different sets on purpose.
56
+ */
57
+ const fs_1 = require("fs");
58
+ const path_1 = require("path");
59
+ const validation_1 = require("../validation");
60
+ const state_machine_1 = require("./state-machine");
61
+ const storage_1 = require("../storage");
62
+ /**
63
+ * The static (placeholder-free) directory prefix of a `memory.yaml` type `path` pattern — e.g.
64
+ * `"docs/04_memory/design/adrs/{id}.md"` -> `"docs/04_memory/design/adrs"`. A pattern whose first
65
+ * placeholder sits in the directory portion (e.g. task's `"docs/04_memory/{release}/{id}.md"`)
66
+ * collapses to the parent of that placeholder — `"docs/04_memory"` — because every possible
67
+ * `{release}` value lives under it.
68
+ */
69
+ function staticDirPrefix(pattern) {
70
+ const braceIndex = pattern.indexOf('{');
71
+ const staticPart = braceIndex === -1 ? pattern : pattern.slice(0, braceIndex);
72
+ const lastSlash = staticPart.lastIndexOf('/');
73
+ return lastSlash === -1 ? '' : staticPart.slice(0, lastSlash);
74
+ }
75
+ /**
76
+ * Derive the minimal set of root-relative directories a scan needs to walk to see every Memory
77
+ * document declared by `memoryYaml`'s types (spec-011: path-pattern predictability, not a full-repo
78
+ * walk). A directory already covered by another (shorter) directory in the set is dropped, so the
79
+ * result never contains redundant, nested roots.
80
+ */
81
+ function computeMemoryContentRoots(memoryYaml) {
82
+ const dirs = new Set();
83
+ for (const typeEntry of Object.values(memoryYaml.types)) {
84
+ const dir = staticDirPrefix(typeEntry.path);
85
+ if (dir)
86
+ dirs.add(dir);
87
+ }
88
+ const all = [...dirs].sort();
89
+ return all.filter((dir) => !all.some((other) => other !== dir && dir.startsWith(`${other}/`)));
90
+ }
91
+ /** Recursively list every `.md` file under `root/dir`, as root-relative POSIX paths, sorted. */
92
+ function listMarkdownFilesUnder(root, dir) {
93
+ const absoluteDir = (0, path_1.join)(root, dir);
94
+ if (!(0, fs_1.existsSync)(absoluteDir) || !(0, fs_1.statSync)(absoluteDir).isDirectory())
95
+ return [];
96
+ const out = [];
97
+ const walk = (current, relativePrefix) => {
98
+ for (const entry of (0, fs_1.readdirSync)(current).sort()) {
99
+ const full = (0, path_1.join)(current, entry);
100
+ const relative = `${relativePrefix}/${entry}`;
101
+ if ((0, fs_1.statSync)(full).isDirectory()) {
102
+ walk(full, relative);
103
+ }
104
+ else if (entry.endsWith('.md')) {
105
+ out.push(relative);
106
+ }
107
+ }
108
+ };
109
+ walk(absoluteDir, dir);
110
+ return out;
111
+ }
112
+ /**
113
+ * List every Memory document under `root`, as root-relative POSIX paths, sorted lexicographically
114
+ * (REQ-SYS-07 — deterministic, no unordered iteration). Scans only the directories
115
+ * {@link computeMemoryContentRoots} derives from `memoryYaml`, never the whole project tree.
116
+ */
117
+ function listMemoryDocumentPaths(root, memoryYaml) {
118
+ const out = new Set();
119
+ for (const dir of computeMemoryContentRoots(memoryYaml)) {
120
+ for (const path of listMarkdownFilesUnder(root, dir))
121
+ out.add(path);
122
+ }
123
+ return [...out].sort();
124
+ }
125
+ /**
126
+ * Read one Memory document and split it into its parsed frontmatter and body text, without running
127
+ * it through any type's Zod schema — `memory search`/`history` must handle documents of every type
128
+ * and any (even structurally imperfect) state, so this is a read, never a validation.
129
+ */
130
+ function loadMemoryDocumentSummary(root, relativePath) {
131
+ const absolute = (0, path_1.join)(root, relativePath);
132
+ const raw = (0, storage_1.readDocument)(absolute);
133
+ const { frontmatter: frontmatterText, body } = (0, storage_1.splitFrontmatter)(raw);
134
+ let frontmatter = {};
135
+ if (frontmatterText) {
136
+ const parsed = (0, validation_1.parseYaml)(frontmatterText, absolute);
137
+ if (parsed !== null && typeof parsed === 'object')
138
+ frontmatter = parsed;
139
+ }
140
+ return { path: relativePath, frontmatter, body };
141
+ }
142
+ function asStringArray(value) {
143
+ return Array.isArray(value) ? value.filter((entry) => typeof entry === 'string') : [];
144
+ }
145
+ function asString(value) {
146
+ return typeof value === 'string' ? value : undefined;
147
+ }
148
+ /**
149
+ * Resolve a single Memory document by its `id` frontmatter value alone — REQ-PERF-04 /
150
+ * task-009-mcp-resource-fetch-latency's Acceptance Criteria, which name a `wingfoil://memory/{id}`
151
+ * benchmark fetch. This is NOT spec-004-mcp-surface-contract §2.1's Resource addressing: spec-004's
152
+ * actual scheme is `wingfoil://memory/{type}` (collection listing) and `wingfoil://memory/{type}/{id}`
153
+ * (single document) — there is no bare, single-segment `wingfoil://memory/{id}` form there, and this
154
+ * `{id}` segment would collide with spec-004's `{type}` segment. task-011-mcp-resources-read-only has
155
+ * since replaced the `wingfoil://memory/{id}` *Resource* this primitive originally backed with the
156
+ * conformant `wingfoil://memory/{type}/{id}` form (see {@link findMemoryDocumentByTypeAndId}) — this
157
+ * bare-id primitive itself is left in place (still covered by its own `test/memory/query.test.ts`
158
+ * unit tests and REQ-PERF-04's ported benchmark) as a generic, type-agnostic lookup; nothing in
159
+ * `src/mcp` calls it anymore.
160
+ *
161
+ * A linear scan over every document {@link listMemoryDocumentPaths} returns, in its
162
+ * already-deterministic sorted order, stopping at the first document whose frontmatter `id` matches
163
+ * *exactly* (never a substring — that remains `searchMemoryDocuments`'/task-021's keyword-search
164
+ * surface, not this primitive's). Returns `undefined` — never throws — when no document matches;
165
+ * turning that into a protocol-level "resource not found" failure is the MCP Resource adapter's job
166
+ * (spec-004 §2.2's general unresolvable-URI contract), not this primitive's.
167
+ */
168
+ function findMemoryDocumentById(root, memoryYaml, id) {
169
+ for (const path of listMemoryDocumentPaths(root, memoryYaml)) {
170
+ const summary = loadMemoryDocumentSummary(root, path);
171
+ if (asString(summary.frontmatter.id) === id)
172
+ return summary;
173
+ }
174
+ return undefined;
175
+ }
176
+ /**
177
+ * List every Memory document whose frontmatter `type:` field equals `type` (a `memory.yaml` `types:`
178
+ * key), as frontmatter-only summaries — spec-004 §2.1's `wingfoil://memory/{type}` collection
179
+ * addressing (task-011-mcp-resources-read-only, REQ-INT-01). Sorted by `id` (falling back to `path`
180
+ * when a document has no `id`) ascending (REQ-SYS-07 — deterministic, no unordered iteration).
181
+ *
182
+ * Membership is decided by each document's own frontmatter `type:` field, not by which directory it
183
+ * lives in: several types' `path` patterns collapse to the *same* static directory prefix (e.g.
184
+ * `release`/`release-line` both resolve to `docs/04_memory/planning`; `task`'s own pattern collapses
185
+ * all the way to `docs/04_memory` itself — see {@link computeMemoryContentRoots}'s doc comment), so a
186
+ * directory-only filter would wrongly fold sibling types' documents into this type's collection.
187
+ */
188
+ function listMemoryDocumentsByType(root, memoryYaml, type) {
189
+ const out = [];
190
+ for (const path of listMemoryDocumentPaths(root, memoryYaml)) {
191
+ const { frontmatter } = loadMemoryDocumentSummary(root, path);
192
+ if (asString(frontmatter.type) !== type)
193
+ continue;
194
+ out.push({
195
+ path,
196
+ id: asString(frontmatter.id),
197
+ title: asString(frontmatter.title),
198
+ status: asString(frontmatter.status),
199
+ tags: asStringArray(frontmatter.tags),
200
+ });
201
+ }
202
+ return out.sort((a, b) => {
203
+ const keyA = a.id ?? a.path;
204
+ const keyB = b.id ?? b.path;
205
+ return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
206
+ });
207
+ }
208
+ /**
209
+ * Resolve a single Memory document by (`type`, `id`) — spec-004 §2.1's `wingfoil://memory/{type}/{id}`
210
+ * single-document addressing (task-011-mcp-resources-read-only, REQ-INT-01), the conformant
211
+ * replacement for task-009's bare-`{id}` `findMemoryDocumentById` Resource usage. Both `type` and `id`
212
+ * must match a document's own frontmatter — same directory-collision reasoning as
213
+ * {@link listMemoryDocumentsByType} — so this never returns a document of a *different* type merely
214
+ * because that type's path pattern happens to also resolve under the same directory. Returns
215
+ * `undefined` — never throws — when nothing matches; surfacing that as a protocol-level "resource not
216
+ * found" failure is the MCP Resource adapter's job (spec-004 §2.2), not this primitive's.
217
+ */
218
+ function findMemoryDocumentByTypeAndId(root, memoryYaml, type, id) {
219
+ for (const path of listMemoryDocumentPaths(root, memoryYaml)) {
220
+ const summary = loadMemoryDocumentSummary(root, path);
221
+ if (asString(summary.frontmatter.type) === type && asString(summary.frontmatter.id) === id)
222
+ return summary;
223
+ }
224
+ return undefined;
225
+ }
226
+ /** `E_EMPTY_SEARCH_QUERY` field-level code (spec-009-validation-strategy §3) for a rejected empty
227
+ * or whitespace-only `wingfoil memory search` query. */
228
+ exports.E_EMPTY_SEARCH_QUERY = 'E_EMPTY_SEARCH_QUERY';
229
+ /**
230
+ * Reject an empty or whitespace-only search query (P1.12 BDD Scenario "Error - empty query string":
231
+ * "no search is performed" and exit code 2, message "empty search query"). Mirrors
232
+ * `resolveTransitionTarget`'s `ValidationError.semantic` pattern (`./state-machine.ts`) so the shared
233
+ * exit-code mapping (spec-009 §3) surfaces this as exit 2 without a bespoke error path; task-021's
234
+ * `wingfoil memory search` CLI/MCP surface calls this on the user-supplied query string before it
235
+ * ever reaches {@link searchMemoryDocuments}.
236
+ *
237
+ * Deliberately a separate guard, not a change to `searchMemoryDocuments`'s own signature/behavior:
238
+ * `searchMemoryDocuments(root, memoryYaml, '', { tag })` remains a legitimate "browse by tag alone,
239
+ * no keyword" call (task-008's own characterization test) — the empty-query rejection is this task's
240
+ * (P1.12's) algorithm-level validation concern, applied at the point a *user-facing* query string is
241
+ * about to be searched, not baked into the lower-level scan primitive that also serves tag-only
242
+ * listing.
243
+ */
244
+ function validateSearchQuery(query) {
245
+ if (query.trim().length === 0) {
246
+ throw validation_1.ValidationError.semantic([
247
+ { code: exports.E_EMPTY_SEARCH_QUERY, path: '', file: '', message: 'empty search query' },
248
+ ]);
249
+ }
250
+ }
251
+ /**
252
+ * Deterministic keyword/frontmatter search over every Memory document `memoryYaml` declares
253
+ * (P1.5/P1.12): case-insensitive substring matching against title/id/tags (metadata) and body text,
254
+ * optionally narrowed to one exact `tag`. A query that matches nothing returns `[]` — a successful,
255
+ * empty result, never a thrown error (that "no documents matched" outcome is a CLI/MCP-surface
256
+ * concern, task-021's, not this primitive's).
257
+ *
258
+ * Ordering is a total, deterministic order (REQ-SYS-07): metadata matches before body-only matches,
259
+ * then by `id` (falling back to `path` when a document has no `id`) ascending — so calling this
260
+ * twice against unchanged state always returns the exact same array.
261
+ *
262
+ * **REQ-STATE-06:** a document whose frontmatter `status` is archived — `deprecated` or `superseded`
263
+ * (`isArchivedStatus`, `dl-028`) — is excluded by default, so it never appears in these "default
264
+ * `memory search` results", matching the Fit Criterion verbatim, while the file itself is untouched on
265
+ * disk and in git history (`memory deprecate`, P1.9, never deletes it; `superseded` is reached by an
266
+ * ordinary `approve`). Pass `options.includeArchived: true` for the one legitimate exception: an
267
+ * explicit, intentional request to see archived documents too. `draft` documents are NOT excluded
268
+ * here — see this module's header for why the search set and the context set differ.
269
+ */
270
+ function searchMemoryDocuments(root, memoryYaml, query, options = {}) {
271
+ const needle = query.trim().toLowerCase();
272
+ const matches = [];
273
+ for (const path of listMemoryDocumentPaths(root, memoryYaml)) {
274
+ const { frontmatter, body } = loadMemoryDocumentSummary(root, path);
275
+ const status = asString(frontmatter.status);
276
+ if (!options.includeArchived && (0, state_machine_1.isArchivedStatus)(status))
277
+ continue;
278
+ const tags = asStringArray(frontmatter.tags);
279
+ if (options.tag && !tags.includes(options.tag))
280
+ continue;
281
+ const title = asString(frontmatter.title);
282
+ const id = asString(frontmatter.id);
283
+ const type = asString(frontmatter.type);
284
+ let metadataMatch = false;
285
+ let bodyMatch = false;
286
+ if (needle.length > 0) {
287
+ metadataMatch =
288
+ (title !== undefined && title.toLowerCase().includes(needle)) ||
289
+ (id !== undefined && id.toLowerCase().includes(needle)) ||
290
+ tags.some((tag) => tag.toLowerCase().includes(needle));
291
+ bodyMatch = body.toLowerCase().includes(needle);
292
+ if (!metadataMatch && !bodyMatch)
293
+ continue;
294
+ }
295
+ matches.push({ path, id, title, tags, status, type, metadataMatch, bodyMatch });
296
+ }
297
+ return matches.sort((a, b) => {
298
+ const scoreA = a.metadataMatch ? 1 : 0;
299
+ const scoreB = b.metadataMatch ? 1 : 0;
300
+ if (scoreA !== scoreB)
301
+ return scoreB - scoreA;
302
+ const keyA = a.id ?? a.path;
303
+ const keyB = b.id ?? b.path;
304
+ return keyA < keyB ? -1 : keyA > keyB ? 1 : 0;
305
+ });
306
+ }
307
+ //# sourceMappingURL=query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/memory/query.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * The rejected document: `status` set to `target` (the type's `gates.<state>.reject` value, taken
3
+ * verbatim per `spec-001-memory-yaml-schema`) and `rejection_reason` set to `reason`. Every other byte
4
+ * — the remaining frontmatter entries, their inline comments, and the whole body — is untouched.
5
+ *
6
+ * `reason` is arbitrary user input (`--reason <text>`, `spec-008-cli-grammar` §2), so it is written
7
+ * through `setFrontmatterField`'s YAML-safe serialization: quotes, colons, `#`, newlines, a leading
8
+ * `-`, YAML-typed words such as `no`/`null` and unicode all parse back to exactly the text given.
9
+ */
10
+ export declare function renderRejectDocument(content: string, target: string, reason: string): string;
11
+ //# sourceMappingURL=reject.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject.d.ts","sourceRoot":"","sources":["../../src/memory/reject.ts"],"names":[],"mappings":"AAiBA;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE5F"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderRejectDocument = renderRejectDocument;
4
+ /**
5
+ * The pure document edit behind `wingfoil memory reject` (P1.8, task-047-memory-reject), kept out of
6
+ * the `CoreResult`-wrapped operation in `src/core` exactly as `./submit.ts` serves `memory submit`.
7
+ *
8
+ * `spec-010-memory-frontmatter-schema`'s field-write ownership table makes `memory.reject` the one
9
+ * transition verb that writes TWO frontmatter fields — "`memory.reject` changes `status` plus
10
+ * `rejection_reason` — the one exception to 'status only' among the transition verbs". The reason is
11
+ * stored verbatim, as the mirror of the `Reason:` trailer the commit body carries (the commit stays
12
+ * the authoritative audit record, P1.7/REQ-SEC-04); the next `memory.submit` removes the key again
13
+ * ({@link renderSubmitDocument}), so it always reflects only the most recent reject.
14
+ *
15
+ * Deterministic (REQ-SYS-07): a pure function of its arguments, with no clock, randomness or
16
+ * object-key iteration.
17
+ */
18
+ const frontmatter_edit_1 = require("./frontmatter-edit");
19
+ const submit_1 = require("./submit");
20
+ /**
21
+ * The rejected document: `status` set to `target` (the type's `gates.<state>.reject` value, taken
22
+ * verbatim per `spec-001-memory-yaml-schema`) and `rejection_reason` set to `reason`. Every other byte
23
+ * — the remaining frontmatter entries, their inline comments, and the whole body — is untouched.
24
+ *
25
+ * `reason` is arbitrary user input (`--reason <text>`, `spec-008-cli-grammar` §2), so it is written
26
+ * through `setFrontmatterField`'s YAML-safe serialization: quotes, colons, `#`, newlines, a leading
27
+ * `-`, YAML-typed words such as `no`/`null` and unicode all parse back to exactly the text given.
28
+ */
29
+ function renderRejectDocument(content, target, reason) {
30
+ return (0, frontmatter_edit_1.setFrontmatterField)((0, frontmatter_edit_1.setFrontmatterField)(content, 'status', target), submit_1.REJECTION_REASON_FIELD, reason);
31
+ }
32
+ //# sourceMappingURL=reject.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reject.js","sourceRoot":"","sources":["../../src/memory/reject.ts"],"names":[],"mappings":";;AA0BA,oDAEC;AA5BD;;;;;;;;;;;;;GAaG;AACH,yDAAyD;AACzD,qCAAkD;AAElD;;;;;;;;GAQG;AACH,SAAgB,oBAAoB,CAAC,OAAe,EAAE,MAAc,EAAE,MAAc;IAClF,OAAO,IAAA,sCAAmB,EAAC,IAAA,sCAAmB,EAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE,+BAAsB,EAAE,MAAM,CAAC,CAAC;AAC7G,CAAC"}
@@ -0,0 +1,104 @@
1
+ /**
2
+ * MemoryYaml schema (spec-001-memory-yaml-schema) — the Project Memory type registry (P1.13). This
3
+ * is one of the three independent per-pillar schemas task-004-decoupled-pillars keeps decoupled
4
+ * (REQ-SYS-02): it has no dependency on `dna.yaml`'s or `workflows.yaml`'s schema, and its own
5
+ * validation never inspects any other file.
6
+ *
7
+ * Every object node is `.passthrough()` per spec-009-validation-strategy §2 (unknown fields are
8
+ * preserved and warned about, not fatal) — see `src/core/loaders.ts` for the loader that wires this
9
+ * schema through the shared two-pass pipeline.
10
+ */
11
+ import { z } from 'zod';
12
+ /**
13
+ * The sequence/gates/waiting state-machine encoding (spec-001 "Sub-schema: StateMachine"),
14
+ * replacing the earlier ambiguous `transitions: {state: [target, ...]}` dict-of-arrays format.
15
+ *
16
+ * The semantic rules from spec-001's "Semantic validation (post-parse)" section are embedded here
17
+ * as a `.superRefine()` — spec-009 §1 frames exactly this kind of same-document, cross-field rule
18
+ * ("a phase's `gates` key must reference a step name that is itself a member of that phase's
19
+ * `sequence` array") as expressible via `.superRefine()`, "still inside the Zod schema, logically
20
+ * Pass 2":
21
+ *
22
+ * - Every key in `gates` and every entry in `waiting` MUST be a member of `sequence`.
23
+ * - A `gates.<state>.reject` target need NOT be a member of `sequence` (it may revert into the
24
+ * chain or name an off-chain decline state reached by no forward edge).
25
+ * - The literal string `"deprecated"` is reserved: it may not appear in `sequence`, as a `gates`
26
+ * key, as a `gates.<state>.reject` target, or in `waiting` — it is an implicit wildcard edge to a
27
+ * reserved state, never declared explicitly.
28
+ */
29
+ export declare const StateMachine: z.ZodObject<{
30
+ sequence: z.ZodArray<z.ZodString>;
31
+ gates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
32
+ reject: z.ZodString;
33
+ }, z.core.$loose>>>;
34
+ waiting: z.ZodOptional<z.ZodArray<z.ZodString>>;
35
+ }, z.core.$loose>;
36
+ export type StateMachine = z.infer<typeof StateMachine>;
37
+ /** `template.frontmatter.required` + the scaffold file path a `memory.add --type <t>` copies. */
38
+ export declare const TemplateConfig: z.ZodObject<{
39
+ frontmatter: z.ZodObject<{
40
+ required: z.ZodArray<z.ZodString>;
41
+ }, z.core.$loose>;
42
+ file: z.ZodString;
43
+ }, z.core.$loose>;
44
+ export type TemplateConfig = z.infer<typeof TemplateConfig>;
45
+ /** One `types.<name>` entry — path pattern, id pattern, human metadata, template, state machine. */
46
+ export declare const MemoryTypeEntry: z.ZodObject<{
47
+ path: z.ZodString;
48
+ id_pattern: z.ZodOptional<z.ZodString>;
49
+ name: z.ZodOptional<z.ZodString>;
50
+ description: z.ZodOptional<z.ZodString>;
51
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
52
+ template: z.ZodOptional<z.ZodObject<{
53
+ frontmatter: z.ZodObject<{
54
+ required: z.ZodArray<z.ZodString>;
55
+ }, z.core.$loose>;
56
+ file: z.ZodString;
57
+ }, z.core.$loose>>;
58
+ states: z.ZodOptional<z.ZodObject<{
59
+ sequence: z.ZodArray<z.ZodString>;
60
+ gates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
61
+ reject: z.ZodString;
62
+ }, z.core.$loose>>>;
63
+ waiting: z.ZodOptional<z.ZodArray<z.ZodString>>;
64
+ }, z.core.$loose>>;
65
+ }, z.core.$loose>;
66
+ export type MemoryTypeEntry = z.infer<typeof MemoryTypeEntry>;
67
+ /**
68
+ * `memory.yaml`'s top-level shape. `version` is `z.number().positive()`, NOT `.int()` — the file's
69
+ * `version: 1.0` (and `1.1`) is a YAML float and `.int()` would spuriously reject it (spec-001).
70
+ */
71
+ export declare const MemoryYaml: z.ZodObject<{
72
+ version: z.ZodNumber;
73
+ defaults: z.ZodOptional<z.ZodObject<{
74
+ states: z.ZodObject<{
75
+ sequence: z.ZodArray<z.ZodString>;
76
+ gates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
77
+ reject: z.ZodString;
78
+ }, z.core.$loose>>>;
79
+ waiting: z.ZodOptional<z.ZodArray<z.ZodString>>;
80
+ }, z.core.$loose>;
81
+ }, z.core.$loose>>;
82
+ types: z.ZodRecord<z.ZodString, z.ZodObject<{
83
+ path: z.ZodString;
84
+ id_pattern: z.ZodOptional<z.ZodString>;
85
+ name: z.ZodOptional<z.ZodString>;
86
+ description: z.ZodOptional<z.ZodString>;
87
+ tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
88
+ template: z.ZodOptional<z.ZodObject<{
89
+ frontmatter: z.ZodObject<{
90
+ required: z.ZodArray<z.ZodString>;
91
+ }, z.core.$loose>;
92
+ file: z.ZodString;
93
+ }, z.core.$loose>>;
94
+ states: z.ZodOptional<z.ZodObject<{
95
+ sequence: z.ZodArray<z.ZodString>;
96
+ gates: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
97
+ reject: z.ZodString;
98
+ }, z.core.$loose>>>;
99
+ waiting: z.ZodOptional<z.ZodArray<z.ZodString>>;
100
+ }, z.core.$loose>>;
101
+ }, z.core.$loose>>;
102
+ }, z.core.$loose>;
103
+ export type MemoryYaml = z.infer<typeof MemoryYaml>;
104
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/memory/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,YAAY;;;;;;iBA2DrB,CAAC;AACL,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAExD,iGAAiG;AACjG,eAAO,MAAM,cAAc;;;;;iBAKX,CAAC;AACjB,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,cAAc,CAAC,CAAC;AAE5D,oGAAoG;AACpG,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;iBAUZ,CAAC;AACjB,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAC;AAE9D;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8CnB,CAAC;AACL,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
@@ -0,0 +1,161 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MemoryYaml = exports.MemoryTypeEntry = exports.TemplateConfig = exports.StateMachine = void 0;
4
+ /**
5
+ * MemoryYaml schema (spec-001-memory-yaml-schema) — the Project Memory type registry (P1.13). This
6
+ * is one of the three independent per-pillar schemas task-004-decoupled-pillars keeps decoupled
7
+ * (REQ-SYS-02): it has no dependency on `dna.yaml`'s or `workflows.yaml`'s schema, and its own
8
+ * validation never inspects any other file.
9
+ *
10
+ * Every object node is `.passthrough()` per spec-009-validation-strategy §2 (unknown fields are
11
+ * preserved and warned about, not fatal) — see `src/core/loaders.ts` for the loader that wires this
12
+ * schema through the shared two-pass pipeline.
13
+ */
14
+ const zod_1 = require("zod");
15
+ const RESERVED_STATE = 'deprecated';
16
+ /**
17
+ * The sequence/gates/waiting state-machine encoding (spec-001 "Sub-schema: StateMachine"),
18
+ * replacing the earlier ambiguous `transitions: {state: [target, ...]}` dict-of-arrays format.
19
+ *
20
+ * The semantic rules from spec-001's "Semantic validation (post-parse)" section are embedded here
21
+ * as a `.superRefine()` — spec-009 §1 frames exactly this kind of same-document, cross-field rule
22
+ * ("a phase's `gates` key must reference a step name that is itself a member of that phase's
23
+ * `sequence` array") as expressible via `.superRefine()`, "still inside the Zod schema, logically
24
+ * Pass 2":
25
+ *
26
+ * - Every key in `gates` and every entry in `waiting` MUST be a member of `sequence`.
27
+ * - A `gates.<state>.reject` target need NOT be a member of `sequence` (it may revert into the
28
+ * chain or name an off-chain decline state reached by no forward edge).
29
+ * - The literal string `"deprecated"` is reserved: it may not appear in `sequence`, as a `gates`
30
+ * key, as a `gates.<state>.reject` target, or in `waiting` — it is an implicit wildcard edge to a
31
+ * reserved state, never declared explicitly.
32
+ */
33
+ exports.StateMachine = zod_1.z
34
+ .object({
35
+ sequence: zod_1.z.array(zod_1.z.string()).min(1),
36
+ gates: zod_1.z.record(zod_1.z.string(), zod_1.z.object({ reject: zod_1.z.string() }).passthrough()).optional(),
37
+ waiting: zod_1.z.array(zod_1.z.string()).optional(),
38
+ })
39
+ .passthrough()
40
+ .superRefine((value, ctx) => {
41
+ const sequenceSet = new Set(value.sequence);
42
+ value.sequence.forEach((state, index) => {
43
+ if (state === RESERVED_STATE) {
44
+ ctx.addIssue({
45
+ code: 'custom',
46
+ message: `"${RESERVED_STATE}" is a reserved implicit state and may not appear in \`sequence\``,
47
+ path: ['sequence', index],
48
+ });
49
+ }
50
+ });
51
+ for (const [state, gate] of Object.entries(value.gates ?? {})) {
52
+ if (state === RESERVED_STATE) {
53
+ ctx.addIssue({
54
+ code: 'custom',
55
+ message: `"${RESERVED_STATE}" is a reserved implicit state and may not be declared as a \`gates\` key`,
56
+ path: ['gates', state],
57
+ });
58
+ }
59
+ else if (!sequenceSet.has(state)) {
60
+ ctx.addIssue({
61
+ code: 'custom',
62
+ message: `\`gates\` key "${state}" must be a member of \`sequence\``,
63
+ path: ['gates', state],
64
+ });
65
+ }
66
+ if (gate.reject === RESERVED_STATE) {
67
+ ctx.addIssue({
68
+ code: 'custom',
69
+ message: `"${RESERVED_STATE}" is a reserved implicit state and may not be a \`gates.<state>.reject\` target`,
70
+ path: ['gates', state, 'reject'],
71
+ });
72
+ }
73
+ // Note: gate.reject need NOT be a member of `sequence` (spec-001) — no membership check here.
74
+ }
75
+ (value.waiting ?? []).forEach((state, index) => {
76
+ if (state === RESERVED_STATE) {
77
+ ctx.addIssue({
78
+ code: 'custom',
79
+ message: `"${RESERVED_STATE}" is a reserved implicit state and may not be declared in \`waiting\``,
80
+ path: ['waiting', index],
81
+ });
82
+ }
83
+ else if (!sequenceSet.has(state)) {
84
+ ctx.addIssue({
85
+ code: 'custom',
86
+ message: `\`waiting\` entry "${state}" must be a member of \`sequence\``,
87
+ path: ['waiting', index],
88
+ });
89
+ }
90
+ });
91
+ });
92
+ /** `template.frontmatter.required` + the scaffold file path a `memory.add --type <t>` copies. */
93
+ exports.TemplateConfig = zod_1.z
94
+ .object({
95
+ frontmatter: zod_1.z.object({ required: zod_1.z.array(zod_1.z.string()) }).passthrough(),
96
+ file: zod_1.z.string(),
97
+ })
98
+ .passthrough();
99
+ /** One `types.<name>` entry — path pattern, id pattern, human metadata, template, state machine. */
100
+ exports.MemoryTypeEntry = zod_1.z
101
+ .object({
102
+ path: zod_1.z.string(),
103
+ id_pattern: zod_1.z.string().optional(),
104
+ name: zod_1.z.string().optional(),
105
+ description: zod_1.z.string().optional(),
106
+ tags: zod_1.z.array(zod_1.z.string()).optional(),
107
+ template: exports.TemplateConfig.optional(),
108
+ states: exports.StateMachine.optional(), // absent ⇒ `defaults.states` applies (REQ-STATE-08)
109
+ })
110
+ .passthrough();
111
+ /**
112
+ * `memory.yaml`'s top-level shape. `version` is `z.number().positive()`, NOT `.int()` — the file's
113
+ * `version: 1.0` (and `1.1`) is a YAML float and `.int()` would spuriously reject it (spec-001).
114
+ */
115
+ exports.MemoryYaml = zod_1.z
116
+ .object({
117
+ version: zod_1.z.number().positive(),
118
+ defaults: zod_1.z.object({ states: exports.StateMachine }).passthrough().optional(),
119
+ types: zod_1.z.record(zod_1.z.string(), exports.MemoryTypeEntry),
120
+ })
121
+ .passthrough()
122
+ /**
123
+ * Type-contextualized restatement of spec-001's "Semantic validation (post-parse)" membership rule
124
+ * — the P1.13 acceptance contract (task-024-implement-memory-element-schema): a state referenced by
125
+ * a type's machine (a `gates` key or a `waiting` entry) that is NOT one of that type's declared
126
+ * states (`sequence`) is a malformed schema and must be rejected at load time, **before any document
127
+ * of that type can be created or transitioned** (REQ-STATE-01). The `StateMachine` sub-schema's own
128
+ * `.superRefine` already flags the same structural violation, but only this top-level refinement
129
+ * knows the *owning type name*, so P1.13's required wording
130
+ * (`transition target '<state>' not in declared states for type '<type>'`) can only be produced
131
+ * here. `defaults.states` (which has no owning type) is left to the `StateMachine`-level check.
132
+ *
133
+ * `gates.<state>.reject` targets are intentionally NOT checked: spec-001 explicitly allows them to
134
+ * be off-chain ("need **not** be a member of `sequence` ... e.g. `bug`'s `open: { reject: closed }`").
135
+ * Iteration is over insertion-ordered `Object.entries`/`Object.keys` only — no wall-clock, no
136
+ * randomness, no set ordering (REQ-SYS-07 determinism).
137
+ */
138
+ .superRefine((value, ctx) => {
139
+ for (const [typeName, entry] of Object.entries(value.types)) {
140
+ const machine = entry.states;
141
+ if (!machine)
142
+ continue; // no own machine ⇒ `defaults.states` applies (REQ-STATE-08)
143
+ const sequenceSet = new Set(machine.sequence);
144
+ const flag = (state, path) => {
145
+ if (state !== RESERVED_STATE && !sequenceSet.has(state)) {
146
+ ctx.addIssue({
147
+ code: 'custom',
148
+ message: `transition target '${state}' not in declared states for type '${typeName}'`,
149
+ path: ['types', typeName, 'states', ...path],
150
+ });
151
+ }
152
+ };
153
+ for (const gateState of Object.keys(machine.gates ?? {})) {
154
+ flag(gateState, ['gates', gateState]);
155
+ }
156
+ (machine.waiting ?? []).forEach((waitState, index) => {
157
+ flag(waitState, ['waiting', index]);
158
+ });
159
+ }
160
+ });
161
+ //# sourceMappingURL=schema.js.map