@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13

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 (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,308 @@
1
+ /**
2
+ * Read model of the docs repo — enumeration, and only by the filesystem.
3
+ *
4
+ * Files are the source of truth, so `services/` IS the list of services and
5
+ * there is no manifest that can disagree with it. The shapes this hands back
6
+ * live in `entries.ts`, the layout it walks in `paths.ts`, and whether there is
7
+ * a repo to walk at all in `state.ts`.
8
+ */
9
+ import { existsSync } from "node:fs";
10
+ import { readdir, readFile } from "node:fs/promises";
11
+ import { join } from "node:path";
12
+ import { contentStamp, listField, movedUnderVouch, readFrontmatter, stringField, } from "../document/frontmatter.js";
13
+ import { featureDirOf } from "../kernel/ids/dirs.js";
14
+ import { rawServiceId, serviceIdProblem } from "../kernel/ids/service.js";
15
+ import { readVouchScope } from "../provenance/sample/scope.js";
16
+ import { compareIds, featureIdFromDirName } from "./entries.js";
17
+ import { ARCHIVE_DIR, featurePaths, featuresDir, fleetAdrsDir, isServiceArtifactName, servicePathsAt, SPEC_AXES, } from "./paths.js";
18
+ import { requireDocsRepo } from "./state.js";
19
+ import { countMarkdown, entryIs } from "./tree/fs.js";
20
+ import { walkServicesTree } from "./tree/walk.js";
21
+ /* ------------------------------------------------------------------ */
22
+ /* Enumeration */
23
+ /* ------------------------------------------------------------------ */
24
+ /**
25
+ * Sorted names of the real subdirectories of `dir` (dot-dirs and files skipped).
26
+ * A missing `dir` is an empty list — the swallow is deliberate but narrow: it
27
+ * only ever runs INSIDE a docs repo that `requireDocsRepo` has already
28
+ * confirmed, where an absent `features/` or `specs/` means "none yet" and
29
+ * nothing else.
30
+ */
31
+ async function subdirs(dir) {
32
+ if (!existsSync(dir))
33
+ return [];
34
+ const entries = await readdir(dir, { withFileTypes: true });
35
+ return entries
36
+ .filter((e) => !e.name.startsWith(".") && entryIs(dir, e, "dir"))
37
+ .map((e) => e.name)
38
+ .sort(compareIds);
39
+ }
40
+ /** Services a feature carries a delta for, ordered — the subdirs of its specs/. */
41
+ export async function featureSpecServices(featureDir, context) {
42
+ if (context !== undefined)
43
+ return context.featureSpecServices(featureDir);
44
+ return (await subdirs(featurePaths(featureDir).specsDir)).map(rawServiceId);
45
+ }
46
+ /**
47
+ * The classified `services/` tree — services at any depth, the subsystems
48
+ * grouping them, and the walk's own findings (`subsystem.*`). The walk itself
49
+ * lives in `./tree/walk.ts` and never imports back into this package; this
50
+ * function is where its two injected dependencies are built — the docs-repo
51
+ * precondition and the artifact-name table `paths.ts` owns.
52
+ */
53
+ export async function listFleetTree(docsDir, context) {
54
+ if (context !== undefined)
55
+ return context.fleetTree(docsDir);
56
+ requireDocsRepo(docsDir, ["ok"]);
57
+ return walkServicesTree({ docsDir, isServiceArtifact: isServiceArtifactName });
58
+ }
59
+ /** Every service in the docs repo, at any depth of the tree, ordered by id. */
60
+ export async function listServices(docsDir, context) {
61
+ if (context !== undefined)
62
+ return context.listServices(docsDir);
63
+ return serviceEntries(await listFleetTree(docsDir));
64
+ }
65
+ /**
66
+ * The full entries for a walked tree — frontmatter, artifact presence, ADR
67
+ * count. Split from `listServices` so `FleetContext` can derive its services
68
+ * memo from its tree memo: one walk per invocation answers both questions.
69
+ * Ordering is `compareIds` over the id wherever the service sits — placement
70
+ * is never part of any identity, and `--json` consumers diff this order — with
71
+ * the directory as the tiebreak so a duplicated id (its own error finding)
72
+ * still lists deterministically.
73
+ */
74
+ /**
75
+ * The second spec axis's header, or an empty one when nobody could read it.
76
+ *
77
+ * `readFrontmatter` folds a decode failure into a flag but still THROWS when
78
+ * the path exists and cannot be read as a file at all — a directory named
79
+ * `arch.spec.md`, which test/gate-command.test.ts builds on purpose. This is
80
+ * the fleet ENUMERATION, where one service's bad byte must cost one subject
81
+ * and not the listing of the other 119, so the throw stops here.
82
+ *
83
+ * The distinction between "no scope" and "nobody could look" is not lost by
84
+ * swallowing it: a path that exists and cannot be read is `service.unreadable`
85
+ * — an ERROR that fails `loam validate` and `loam gate` — which is a louder
86
+ * signal than any row of a listing, and it names the file this cannot.
87
+ */
88
+ async function archHeader(path) {
89
+ try {
90
+ return await readFrontmatter(path);
91
+ }
92
+ catch {
93
+ return { present: false, malformed: false, data: {}, body: "" };
94
+ }
95
+ }
96
+ /**
97
+ * The spec files whose body moved under their vouch — `content.stale`'s
98
+ * question, asked through the one predicate `loam validate` grades with
99
+ * (`movedUnderVouch`) so the fleet listing and the finding cannot disagree
100
+ * about one file. Only a header that carries a stamp (`contentStamp`) costs the
101
+ * second read: the frontmatter read already answered whether there is anything
102
+ * to compare, and on a fleet mid-adoption most headers do not. The body is
103
+ * read exactly as the finding reads it, as UTF-8 text, because the stamp is
104
+ * byte-exact.
105
+ */
106
+ async function filesMovedUnderVouch(axes) {
107
+ const moved = await Promise.all(axes.map(async ({ file, path, header }) => contentStamp(header) !== undefined && movedUnderVouch(header, await readFile(path, "utf8")) ? [file] : []));
108
+ return moved.flat();
109
+ }
110
+ /**
111
+ * `ServiceEntry.adoption`, read off one living spec.md's frontmatter — the one
112
+ * spelling of the marker's test, for the enumeration below and for the adopt
113
+ * brief, which must not call a partial adoption finished. Any value but
114
+ * `partial` reads as absent (SCHEMA.md).
115
+ */
116
+ export function adoptionOf(fm) {
117
+ return stringField(fm, "adoption") === "partial" ? "partial" : null;
118
+ }
119
+ /** `adoptionOf` for a spec.md by path; an absent file is no marker. */
120
+ export async function specAdoption(specPath) {
121
+ return adoptionOf(await readFrontmatter(specPath));
122
+ }
123
+ export async function serviceEntries(tree) {
124
+ const entries = await Promise.all(tree.services.map(async (svc) => {
125
+ const p = servicePathsAt(svc.dir);
126
+ // Both spec axes, because a sample is per FILE: one `--sample 3` run can
127
+ // read a short spec.md in full and stamp a scope on a long arch.spec.md
128
+ // beside it, and a fleet row that reported only spec.md's header would
129
+ // print that service as fully vouched while `loam validate` reported it
130
+ // sampled. `readFrontmatter` answers "absent" for a file that is not
131
+ // there, so a service without the second axis pays one existsSync.
132
+ const [fm, archFm] = await Promise.all([readFrontmatter(p.spec), archHeader(p.archSpec)]);
133
+ const headers = { spec: fm, archSpec: archFm };
134
+ const idProblem = serviceIdProblem(svc.id, "directory name");
135
+ return {
136
+ id: svc.id,
137
+ dir: svc.dir,
138
+ subsystem: svc.subsystem,
139
+ ...(idProblem === null ? {} : { idProblem }),
140
+ has: {
141
+ model: existsSync(p.model),
142
+ spec: existsSync(p.spec),
143
+ openapi: existsSync(p.openapi),
144
+ asyncapi: existsSync(p.asyncapi),
145
+ runbook: existsSync(p.runbook),
146
+ health: existsSync(p.health),
147
+ },
148
+ adrs: await countMarkdown(p.adrsDir),
149
+ status: stringField(fm, "status") ?? null,
150
+ adoption: adoptionOf(fm),
151
+ sources: {
152
+ declared: listField(fm, "sources").length > 0,
153
+ stamped: stringField(fm, "sources_digest") !== undefined,
154
+ },
155
+ // Either axis makes the SERVICE sampled, and presence is the test, not
156
+ // decodability: an unreadable scope is still a stamped partial read
157
+ // (core/provenance/sample/scope.ts's `readVouchScope`), and the fleet
158
+ // listing is the last place a mangled field should be able to buy
159
+ // itself a full-trust row.
160
+ vouchScope: [fm, archFm].some((header) => readVouchScope(header).kind !== "none") ? "sampled" : null,
161
+ // Both axes again, for the scope's reason: a stamp is per FILE, and an
162
+ // arch.spec.md edited under its vouch is a service part of whose
163
+ // documentation nobody has re-read.
164
+ contentStale: await filesMovedUnderVouch(SPEC_AXES.map((axis) => ({ file: axis.file, path: p[axis.key], header: headers[axis.key] }))),
165
+ };
166
+ }));
167
+ return entries.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dir, b.dir));
168
+ }
169
+ /**
170
+ * How many fleet-level ADRs `architecture/adrs/` holds — the same number, by the
171
+ * same rule (`countMarkdown`), that `ServiceEntry.adrs` carries one altitude
172
+ * down. One shape for one question: a second spelling of "count the decisions"
173
+ * is how `list` and `show` once reported different ADR counts for one service.
174
+ *
175
+ * A count and never a finding. The directory is optional, an absent one is 0,
176
+ * and nothing in loam grades either — see `fleetAdrsDir` for why that is the
177
+ * whole design rather than an unfinished half of it. No `FleetContext` overload:
178
+ * one caller asks this once per invocation, and a memo whose key is the docsDir
179
+ * would be a cache nobody reads twice.
180
+ */
181
+ export async function fleetAdrCount(docsDir) {
182
+ return countMarkdown(fleetAdrsDir(docsDir));
183
+ }
184
+ /**
185
+ * What a feature is CALLED, for a person: intent.md's `title:`, else its first
186
+ * `# ` heading with the feature id peeled off the front, else null.
187
+ *
188
+ * Every row that names a feature used to print the id alone, and an id is a
189
+ * key, not a name — a newcomer looking at `ready FEAT-101` could not tell
190
+ * which change it was without opening the directory. Read on demand rather
191
+ * than carried on `FeatureEntry`, because the enumeration runs under every
192
+ * command and only the views a person reads need the words. A missing or
193
+ * unreadable intent.md is simply no title: the row still prints its id, and
194
+ * whether intent.md is owed is `status`'s question, not this one's.
195
+ */
196
+ export async function featureTitle(feature) {
197
+ let fm;
198
+ try {
199
+ fm = await readFrontmatter(featurePaths(feature.dir).intent);
200
+ }
201
+ catch {
202
+ // A directory in intent.md's place, a permission: unreadable is no title.
203
+ // `readFrontmatter` folds only the encoding failure into a flag, and before
204
+ // this read the views that print a title never opened intent.md at all —
205
+ // so letting the error escape would hand `loam status` and `loam list`
206
+ // whole to `repository-unavailable` over a label. Whether intent.md is
207
+ // fine is the intent row's and `validate`'s question.
208
+ return null;
209
+ }
210
+ const declared = stringField(fm, "title")?.trim();
211
+ if (declared !== undefined && declared !== "")
212
+ return declared;
213
+ const heading = fm.body.split(/\r?\n/).find((l) => l.startsWith("# "));
214
+ if (heading === undefined)
215
+ return null;
216
+ const words = heading.slice(2).trim();
217
+ const bare = words.startsWith(feature.id) ? words.slice(feature.id.length).replace(/^[\s:—–-]+/, "") : words;
218
+ return bare === "" ? null : bare;
219
+ }
220
+ async function readFeature(dir, dirName, archived) {
221
+ const p = featurePaths(dir);
222
+ return {
223
+ id: featureIdFromDirName(dirName),
224
+ dirName,
225
+ dir,
226
+ archived,
227
+ services: (await subdirs(p.specsDir)).map(rawServiceId),
228
+ has: { intent: existsSync(p.intent), delta: existsSync(p.delta) },
229
+ };
230
+ }
231
+ /**
232
+ * Features in the docs repo, ordered by id (active and archived interleaved when
233
+ * both are asked for). `features/archive/` is the archive, never a feature.
234
+ */
235
+ export async function listFeatures(docsDir, opts = {}, context) {
236
+ if (context !== undefined)
237
+ return context.listFeatures(docsDir, opts);
238
+ // "no-services" is tolerated here on purpose: a docs repo whose services/ is
239
+ // gone is broken, but it is `listServices` (and `loam doctor`) that says so.
240
+ // Refusing here too would turn one diagnosis into two contradictory ones.
241
+ requireDocsRepo(docsDir, ["ok", "no-services"]);
242
+ const root = featuresDir(docsDir);
243
+ const active = (await subdirs(root)).filter((n) => n !== ARCHIVE_DIR);
244
+ // Branded at the join: the name came off this readdir, onto the features
245
+ // root it was listed under — the provenance `FeatureDir` records.
246
+ const out = await Promise.all(active.map((n) => readFeature(featureDirOf(join(root, n)), n, false)));
247
+ if (opts.includeArchived) {
248
+ const archiveRoot = join(root, ARCHIVE_DIR);
249
+ const archived = await subdirs(archiveRoot);
250
+ out.push(...(await Promise.all(archived.map((n) => readFeature(featureDirOf(join(archiveRoot, n)), n, true)))));
251
+ }
252
+ return out.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));
253
+ }
254
+ /**
255
+ * Resolve a feature argument — a canonical id (`FEAT-5`) or an exact directory
256
+ * name (`FEAT-5-slug`) — to its entry. The entry's `id` is the canonical
257
+ * spelling, and it is the only name a caller may use from here on: tag filters,
258
+ * coherence, and the cross-feature self-exclusion scans all compare against
259
+ * `feature.id`, never against the raw argument.
260
+ *
261
+ * Matching is EXACT, on one of two spellings: the directory name as it is on
262
+ * disk, or the canonical id derived from it. It used to also match any dirName
263
+ * starting with `arg + "-"`, which made the argument a prefix query in
264
+ * disguise: with FEAT-401 and FEAT-402 in flight, `loam archive FEAT` archived
265
+ * whichever sorted first, and `loam delta billing` reached into
266
+ * `billing-7-rewrite`. A destructive command must never pick a target the
267
+ * caller did not name, so a prefix now resolves to nothing at all.
268
+ *
269
+ * An exact directory name still wins over the id spelling (`FEAT-5` the
270
+ * directory over `FEAT-5-slug`, whose id is also `FEAT-5`), and under "include"
271
+ * an active feature wins over an archived one. Ties among equally-exact
272
+ * candidates go to the first by name — deterministic, unlike the raw readdir
273
+ * order this replaces; `featureCandidates` returns every one of them, for a
274
+ * caller that must see the tie (`loam status` names the colliding directories).
275
+ */
276
+ export async function resolveFeature(docsDir, arg, archived, context) {
277
+ return (await featureCandidates(docsDir, arg, archived, context))[0] ?? null;
278
+ }
279
+ /**
280
+ * Every feature the argument names exactly, best first. Split out of
281
+ * `resolveFeature` so a caller that wants to REFUSE an ambiguous argument can
282
+ * see the tie instead of inheriting the winner.
283
+ */
284
+ export async function featureCandidates(docsDir, arg, archived, context) {
285
+ const all = await listFeatures(docsDir, { includeArchived: archived !== "exclude" }, context);
286
+ return all
287
+ .filter((f) => archived === "include" || f.archived === (archived === "only"))
288
+ .filter((f) => f.dirName === arg || f.id === arg)
289
+ .sort((a, b) => Number(b.dirName === arg) - Number(a.dirName === arg) ||
290
+ Number(a.archived) - Number(b.archived) ||
291
+ compareIds(a.dirName, b.dirName));
292
+ }
293
+ /**
294
+ * The message for an exclude-mode miss. When the feature exists under
295
+ * `features/archive/`, "no feature" is a lie the caller would have to debug —
296
+ * the honest answer is "already archived", plus how to look at it. The `--json`
297
+ * code stays `unknown-target` either way: the target is unknown to the command
298
+ * that asked, and the prose carries the diagnosis.
299
+ */
300
+ export async function missingFeatureMessage(docsDir, arg, context) {
301
+ const shipped = await resolveFeature(docsDir, arg, "only", context);
302
+ if (shipped !== null) {
303
+ return (`Feature '${shipped.id}' is already archived (features/archive/${shipped.dirName}) — ` +
304
+ `\`loam show ${shipped.id}\` reads it, \`loam unarchive ${shipped.id}\` re-opens it.`);
305
+ }
306
+ return `No feature '${arg}' under ${featuresDir(docsDir)}.`;
307
+ }
308
+ //# sourceMappingURL=repo.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../../src/core/repo/repo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Read model of the docs repo — enumeration, and only by the filesystem.\n *\n * Files are the source of truth, so `services/` IS the list of services and\n * there is no manifest that can disagree with it. The shapes this hands back\n * live in `entries.ts`, the layout it walks in `paths.ts`, and whether there is\n * a repo to walk at all in `state.ts`.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n contentStamp,\n listField,\n movedUnderVouch,\n readFrontmatter,\n stringField,\n type Frontmatter,\n} from \"../document/frontmatter.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { featureDirOf, type DocsDir, type FeatureDir } from \"../kernel/ids/dirs.js\";\nimport { rawServiceId, serviceIdProblem, type RawServiceId } from \"../kernel/ids/service.js\";\nimport { readVouchScope } from \"../provenance/sample/scope.js\";\nimport { compareIds, featureIdFromDirName, type FeatureEntry, type ServiceEntry } from \"./entries.js\";\nimport {\n ARCHIVE_DIR,\n featurePaths,\n featuresDir,\n fleetAdrsDir,\n isServiceArtifactName,\n servicePathsAt,\n SPEC_AXES,\n} from \"./paths.js\";\nimport { requireDocsRepo } from \"./state.js\";\nimport { countMarkdown, entryIs } from \"./tree/fs.js\";\nimport { walkServicesTree, type FleetTree } from \"./tree/walk.js\";\n\n/* ------------------------------------------------------------------ */\n/* Enumeration */\n/* ------------------------------------------------------------------ */\n\n/**\n * Sorted names of the real subdirectories of `dir` (dot-dirs and files skipped).\n * A missing `dir` is an empty list — the swallow is deliberate but narrow: it\n * only ever runs INSIDE a docs repo that `requireDocsRepo` has already\n * confirmed, where an absent `features/` or `specs/` means \"none yet\" and\n * nothing else.\n */\nasync function subdirs(dir: string): Promise<string[]> {\n if (!existsSync(dir)) return [];\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith(\".\") && entryIs(dir, e, \"dir\"))\n .map((e) => e.name)\n .sort(compareIds);\n}\n\n/** Services a feature carries a delta for, ordered — the subdirs of its specs/. */\nexport async function featureSpecServices(\n featureDir: FeatureDir,\n context?: FleetContext,\n): Promise<RawServiceId[]> {\n if (context !== undefined) return context.featureSpecServices(featureDir);\n return (await subdirs(featurePaths(featureDir).specsDir)).map(rawServiceId);\n}\n\n/**\n * The classified `services/` tree — services at any depth, the subsystems\n * grouping them, and the walk's own findings (`subsystem.*`). The walk itself\n * lives in `./tree/walk.ts` and never imports back into this package; this\n * function is where its two injected dependencies are built — the docs-repo\n * precondition and the artifact-name table `paths.ts` owns.\n */\nexport async function listFleetTree(docsDir: DocsDir, context?: FleetContext): Promise<FleetTree> {\n if (context !== undefined) return context.fleetTree(docsDir);\n requireDocsRepo(docsDir, [\"ok\"]);\n return walkServicesTree({ docsDir, isServiceArtifact: isServiceArtifactName });\n}\n\n/** Every service in the docs repo, at any depth of the tree, ordered by id. */\nexport async function listServices(docsDir: DocsDir, context?: FleetContext): Promise<ServiceEntry[]> {\n if (context !== undefined) return context.listServices(docsDir);\n return serviceEntries(await listFleetTree(docsDir));\n}\n\n/**\n * The full entries for a walked tree — frontmatter, artifact presence, ADR\n * count. Split from `listServices` so `FleetContext` can derive its services\n * memo from its tree memo: one walk per invocation answers both questions.\n * Ordering is `compareIds` over the id wherever the service sits — placement\n * is never part of any identity, and `--json` consumers diff this order — with\n * the directory as the tiebreak so a duplicated id (its own error finding)\n * still lists deterministically.\n */\n/**\n * The second spec axis's header, or an empty one when nobody could read it.\n *\n * `readFrontmatter` folds a decode failure into a flag but still THROWS when\n * the path exists and cannot be read as a file at all — a directory named\n * `arch.spec.md`, which test/gate-command.test.ts builds on purpose. This is\n * the fleet ENUMERATION, where one service's bad byte must cost one subject\n * and not the listing of the other 119, so the throw stops here.\n *\n * The distinction between \"no scope\" and \"nobody could look\" is not lost by\n * swallowing it: a path that exists and cannot be read is `service.unreadable`\n * — an ERROR that fails `loam validate` and `loam gate` — which is a louder\n * signal than any row of a listing, and it names the file this cannot.\n */\nasync function archHeader(path: string): Promise<Frontmatter> {\n try {\n return await readFrontmatter(path);\n } catch {\n return { present: false, malformed: false, data: {}, body: \"\" };\n }\n}\n\n/**\n * The spec files whose body moved under their vouch — `content.stale`'s\n * question, asked through the one predicate `loam validate` grades with\n * (`movedUnderVouch`) so the fleet listing and the finding cannot disagree\n * about one file. Only a header that carries a stamp (`contentStamp`) costs the\n * second read: the frontmatter read already answered whether there is anything\n * to compare, and on a fleet mid-adoption most headers do not. The body is\n * read exactly as the finding reads it, as UTF-8 text, because the stamp is\n * byte-exact.\n */\nasync function filesMovedUnderVouch(\n axes: readonly { file: string; path: string; header: Frontmatter }[],\n): Promise<string[]> {\n const moved = await Promise.all(\n axes.map(async ({ file, path, header }) =>\n contentStamp(header) !== undefined && movedUnderVouch(header, await readFile(path, \"utf8\")) ? [file] : [],\n ),\n );\n return moved.flat();\n}\n\n/**\n * `ServiceEntry.adoption`, read off one living spec.md's frontmatter — the one\n * spelling of the marker's test, for the enumeration below and for the adopt\n * brief, which must not call a partial adoption finished. Any value but\n * `partial` reads as absent (SCHEMA.md).\n */\nexport function adoptionOf(fm: Frontmatter): \"partial\" | null {\n return stringField(fm, \"adoption\") === \"partial\" ? \"partial\" : null;\n}\n\n/** `adoptionOf` for a spec.md by path; an absent file is no marker. */\nexport async function specAdoption(specPath: string): Promise<\"partial\" | null> {\n return adoptionOf(await readFrontmatter(specPath));\n}\n\nexport async function serviceEntries(tree: FleetTree): Promise<ServiceEntry[]> {\n const entries = await Promise.all(\n tree.services.map(async (svc): Promise<ServiceEntry> => {\n const p = servicePathsAt(svc.dir);\n // Both spec axes, because a sample is per FILE: one `--sample 3` run can\n // read a short spec.md in full and stamp a scope on a long arch.spec.md\n // beside it, and a fleet row that reported only spec.md's header would\n // print that service as fully vouched while `loam validate` reported it\n // sampled. `readFrontmatter` answers \"absent\" for a file that is not\n // there, so a service without the second axis pays one existsSync.\n const [fm, archFm] = await Promise.all([readFrontmatter(p.spec), archHeader(p.archSpec)]);\n const headers = { spec: fm, archSpec: archFm };\n const idProblem = serviceIdProblem(svc.id, \"directory name\");\n return {\n id: svc.id,\n dir: svc.dir,\n subsystem: svc.subsystem,\n ...(idProblem === null ? {} : { idProblem }),\n has: {\n model: existsSync(p.model),\n spec: existsSync(p.spec),\n openapi: existsSync(p.openapi),\n asyncapi: existsSync(p.asyncapi),\n runbook: existsSync(p.runbook),\n health: existsSync(p.health),\n },\n adrs: await countMarkdown(p.adrsDir),\n status: stringField(fm, \"status\") ?? null,\n adoption: adoptionOf(fm),\n sources: {\n declared: listField(fm, \"sources\").length > 0,\n stamped: stringField(fm, \"sources_digest\") !== undefined,\n },\n // Either axis makes the SERVICE sampled, and presence is the test, not\n // decodability: an unreadable scope is still a stamped partial read\n // (core/provenance/sample/scope.ts's `readVouchScope`), and the fleet\n // listing is the last place a mangled field should be able to buy\n // itself a full-trust row.\n vouchScope: [fm, archFm].some((header) => readVouchScope(header).kind !== \"none\") ? \"sampled\" : null,\n // Both axes again, for the scope's reason: a stamp is per FILE, and an\n // arch.spec.md edited under its vouch is a service part of whose\n // documentation nobody has re-read.\n contentStale: await filesMovedUnderVouch(\n SPEC_AXES.map((axis) => ({ file: axis.file, path: p[axis.key], header: headers[axis.key] })),\n ),\n };\n }),\n );\n return entries.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dir, b.dir));\n}\n\n/**\n * How many fleet-level ADRs `architecture/adrs/` holds — the same number, by the\n * same rule (`countMarkdown`), that `ServiceEntry.adrs` carries one altitude\n * down. One shape for one question: a second spelling of \"count the decisions\"\n * is how `list` and `show` once reported different ADR counts for one service.\n *\n * A count and never a finding. The directory is optional, an absent one is 0,\n * and nothing in loam grades either — see `fleetAdrsDir` for why that is the\n * whole design rather than an unfinished half of it. No `FleetContext` overload:\n * one caller asks this once per invocation, and a memo whose key is the docsDir\n * would be a cache nobody reads twice.\n */\nexport async function fleetAdrCount(docsDir: DocsDir): Promise<number> {\n return countMarkdown(fleetAdrsDir(docsDir));\n}\n\n/**\n * What a feature is CALLED, for a person: intent.md's `title:`, else its first\n * `# ` heading with the feature id peeled off the front, else null.\n *\n * Every row that names a feature used to print the id alone, and an id is a\n * key, not a name — a newcomer looking at `ready FEAT-101` could not tell\n * which change it was without opening the directory. Read on demand rather\n * than carried on `FeatureEntry`, because the enumeration runs under every\n * command and only the views a person reads need the words. A missing or\n * unreadable intent.md is simply no title: the row still prints its id, and\n * whether intent.md is owed is `status`'s question, not this one's.\n */\nexport async function featureTitle(feature: FeatureEntry): Promise<string | null> {\n let fm: Frontmatter;\n try {\n fm = await readFrontmatter(featurePaths(feature.dir).intent);\n } catch {\n // A directory in intent.md's place, a permission: unreadable is no title.\n // `readFrontmatter` folds only the encoding failure into a flag, and before\n // this read the views that print a title never opened intent.md at all —\n // so letting the error escape would hand `loam status` and `loam list`\n // whole to `repository-unavailable` over a label. Whether intent.md is\n // fine is the intent row's and `validate`'s question.\n return null;\n }\n const declared = stringField(fm, \"title\")?.trim();\n if (declared !== undefined && declared !== \"\") return declared;\n const heading = fm.body.split(/\\r?\\n/).find((l) => l.startsWith(\"# \"));\n if (heading === undefined) return null;\n const words = heading.slice(2).trim();\n const bare = words.startsWith(feature.id) ? words.slice(feature.id.length).replace(/^[\\s:—–-]+/, \"\") : words;\n return bare === \"\" ? null : bare;\n}\n\nasync function readFeature(dir: FeatureDir, dirName: string, archived: boolean): Promise<FeatureEntry> {\n const p = featurePaths(dir);\n return {\n id: featureIdFromDirName(dirName),\n dirName,\n dir,\n archived,\n services: (await subdirs(p.specsDir)).map(rawServiceId),\n has: { intent: existsSync(p.intent), delta: existsSync(p.delta) },\n };\n}\n\n/**\n * Features in the docs repo, ordered by id (active and archived interleaved when\n * both are asked for). `features/archive/` is the archive, never a feature.\n */\nexport async function listFeatures(\n docsDir: DocsDir,\n opts: { includeArchived?: boolean } = {},\n context?: FleetContext,\n): Promise<FeatureEntry[]> {\n if (context !== undefined) return context.listFeatures(docsDir, opts);\n // \"no-services\" is tolerated here on purpose: a docs repo whose services/ is\n // gone is broken, but it is `listServices` (and `loam doctor`) that says so.\n // Refusing here too would turn one diagnosis into two contradictory ones.\n requireDocsRepo(docsDir, [\"ok\", \"no-services\"]);\n const root = featuresDir(docsDir);\n const active = (await subdirs(root)).filter((n) => n !== ARCHIVE_DIR);\n // Branded at the join: the name came off this readdir, onto the features\n // root it was listed under — the provenance `FeatureDir` records.\n const out = await Promise.all(active.map((n) => readFeature(featureDirOf(join(root, n)), n, false)));\n\n if (opts.includeArchived) {\n const archiveRoot = join(root, ARCHIVE_DIR);\n const archived = await subdirs(archiveRoot);\n out.push(...(await Promise.all(archived.map((n) => readFeature(featureDirOf(join(archiveRoot, n)), n, true)))));\n }\n\n return out.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));\n}\n\n/**\n * Which side of `features/archive/` a lookup may land on. The policy is an\n * argument, not a default, so every command's stance on shipped features is\n * visible at its call site: delta/validate/archive work on in-flight features\n * (\"exclude\"), show/verify/new read shipped ones too (\"include\"), unarchive\n * takes back nothing else (\"only\").\n */\nexport type ArchivedPolicy = \"exclude\" | \"include\" | \"only\";\n\n/**\n * Resolve a feature argument — a canonical id (`FEAT-5`) or an exact directory\n * name (`FEAT-5-slug`) — to its entry. The entry's `id` is the canonical\n * spelling, and it is the only name a caller may use from here on: tag filters,\n * coherence, and the cross-feature self-exclusion scans all compare against\n * `feature.id`, never against the raw argument.\n *\n * Matching is EXACT, on one of two spellings: the directory name as it is on\n * disk, or the canonical id derived from it. It used to also match any dirName\n * starting with `arg + \"-\"`, which made the argument a prefix query in\n * disguise: with FEAT-401 and FEAT-402 in flight, `loam archive FEAT` archived\n * whichever sorted first, and `loam delta billing` reached into\n * `billing-7-rewrite`. A destructive command must never pick a target the\n * caller did not name, so a prefix now resolves to nothing at all.\n *\n * An exact directory name still wins over the id spelling (`FEAT-5` the\n * directory over `FEAT-5-slug`, whose id is also `FEAT-5`), and under \"include\"\n * an active feature wins over an archived one. Ties among equally-exact\n * candidates go to the first by name — deterministic, unlike the raw readdir\n * order this replaces; `featureCandidates` returns every one of them, for a\n * caller that must see the tie (`loam status` names the colliding directories).\n */\nexport async function resolveFeature(\n docsDir: DocsDir,\n arg: string,\n archived: ArchivedPolicy,\n context?: FleetContext,\n): Promise<FeatureEntry | null> {\n return (await featureCandidates(docsDir, arg, archived, context))[0] ?? null;\n}\n\n/**\n * Every feature the argument names exactly, best first. Split out of\n * `resolveFeature` so a caller that wants to REFUSE an ambiguous argument can\n * see the tie instead of inheriting the winner.\n */\nexport async function featureCandidates(\n docsDir: DocsDir,\n arg: string,\n archived: ArchivedPolicy,\n context?: FleetContext,\n): Promise<FeatureEntry[]> {\n const all = await listFeatures(docsDir, { includeArchived: archived !== \"exclude\" }, context);\n return all\n .filter((f) => archived === \"include\" || f.archived === (archived === \"only\"))\n .filter((f) => f.dirName === arg || f.id === arg)\n .sort(\n (a, b) =>\n Number(b.dirName === arg) - Number(a.dirName === arg) ||\n Number(a.archived) - Number(b.archived) ||\n compareIds(a.dirName, b.dirName),\n );\n}\n\n/**\n * The message for an exclude-mode miss. When the feature exists under\n * `features/archive/`, \"no feature\" is a lie the caller would have to debug —\n * the honest answer is \"already archived\", plus how to look at it. The `--json`\n * code stays `unknown-target` either way: the target is unknown to the command\n * that asked, and the prose carries the diagnosis.\n */\nexport async function missingFeatureMessage(\n docsDir: DocsDir,\n arg: string,\n context?: FleetContext,\n): Promise<string> {\n const shipped = await resolveFeature(docsDir, arg, \"only\", context);\n if (shipped !== null) {\n return (\n `Feature '${shipped.id}' is already archived (features/archive/${shipped.dirName}) — ` +\n `\\`loam show ${shipped.id}\\` reads it, \\`loam unarchive ${shipped.id}\\` re-opens it.`\n );\n }\n return `No feature '${arg}' under ${featuresDir(docsDir)}.`;\n}\n"]}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Turning a name a caller typed into a name loam may join into a path.
3
+ *
4
+ * `unfiledServicePaths(docsDir, name)` spells `<docsDir>/services/<name>/`,
5
+ * and its parameter is `PathableService`: an unchecked name at that call site
6
+ * no longer compiles, and this module is where a name a caller typed EARNS the
7
+ * type. The history is why it exists. Six commands guard their argument with
8
+ * `assertServiceId` at the boundary; `validate` never did, and both of its
9
+ * entry points — `--service <id>` and the positional `<target>` — reached
10
+ * the path builder with whatever argv held. `--service ../../outside/services/x`
11
+ * resolved ABOVE the docs repo, and where a `spec.md` happened to sit there
12
+ * loam opened it, graded it, and reported its frontmatter through `--json`.
13
+ *
14
+ * The grammar alone is not the answer, and this is the whole reason this module
15
+ * exists rather than a call to `assertServiceId`. `services/Payment Service/`
16
+ * is a directory `loam list` shows, `validate --all` grades, and
17
+ * `service.id-invalid` calls an error nobody can fix without a rename — so it
18
+ * is exactly the directory somebody points `validate --service` at. Refusing on
19
+ * the grammar would make the one service loam complains about the one service
20
+ * loam cannot look at.
21
+ *
22
+ * So the enumeration answers first and the grammar answers second:
23
+ *
24
+ * in `services/` → the enumeration's OWN id, which is a name loam
25
+ * already reads off disk every time it lists the fleet.
26
+ * Legal or not, it exists, and joining it lands where
27
+ * the directory is.
28
+ * not there, legal → the caller's name. Nothing exists yet; the run
29
+ * continues and grades it `service.unknown`, with the
30
+ * near-miss hints that make a typo diagnosable.
31
+ * not there, illegal → refused, before any path is built.
32
+ *
33
+ * `show` and `status` already resolve against the enumeration this way. What
34
+ * they do not do is fall through to the grammar, which is why they answer
35
+ * "no such service" to a name that could never BE a service — a worse sentence
36
+ * for the same input.
37
+ */
38
+ import { listServices } from "./repo.js";
39
+ import { parseServiceId } from "../kernel/ids/service.js";
40
+ import { serviceTreePath } from "../kernel/ids/dirs.js";
41
+ import { servicePathsAt, unfiledServicePaths } from "./paths.js";
42
+ /**
43
+ * The enumerated services, or the empty list when `services/` cannot be
44
+ * enumerated at all. The swallow is deliberate and spelled ONCE: every
45
+ * repository-aware resolver wants "which services exist" as context, and an
46
+ * unenumerable `services/` is that repository's own diagnosis
47
+ * (`services-missing`), never the asking check's. Six call sites each carried
48
+ * this try/catch in their own spelling before it lived here — which is exactly
49
+ * the shape docs/CODE-STYLE.md warns about: an errno fix lands in one copy and
50
+ * the other five keep the old behaviour. The existence probes that used to ask
51
+ * `existsSync(services/<id>/)` ask membership HERE for the same tolerance:
52
+ * `validate --feature` must run in a docs repo with no `services/` at all,
53
+ * where enumerating is a refusal but "does this service exist" still has the
54
+ * honest answer no.
55
+ */
56
+ export async function enumeratedServices(docsDir, fleet) {
57
+ try {
58
+ return await listServices(docsDir, fleet);
59
+ }
60
+ catch {
61
+ return [];
62
+ }
63
+ }
64
+ /** The id projection of `enumeratedServices` — most membership asks want only the names. */
65
+ export async function enumeratedServiceIds(docsDir, fleet) {
66
+ return (await enumeratedServices(docsDir, fleet)).map((s) => s.id);
67
+ }
68
+ /**
69
+ * The artifact paths of a service wherever it lives: the enumeration's own
70
+ * directory when the id exists anywhere in the tree, the unfiled root
71
+ * spelling otherwise — so an absent service still probes, grades
72
+ * (`service.unknown`) and CREATES exactly as it did when the tree was flat.
73
+ * This is the one bridge the ~40 former `servicePaths` call sites resolve
74
+ * through — and it is NOT free: without a `fleet` context every call is a
75
+ * fresh fleet enumeration (one readdir per directory walked plus a
76
+ * frontmatter read and several existence probes per service), which measured
77
+ * ~13 ms per call on a 120-service fleet. A call site inside a loop must
78
+ * thread the command's `FleetContext`; a caller that already holds a
79
+ * `ServiceEntry` should spell `servicePathsAt(entry.dir)` directly and pay
80
+ * nothing.
81
+ */
82
+ /**
83
+ * Where a service sits under `services/`, repo-relative and WITHOUT a trailing
84
+ * slash — for a message that names an existing directory to a reader.
85
+ *
86
+ * The join it replaces is `services/${id}`, which is right for an unfiled
87
+ * service and wrong for every filed one; `paths.ts` states the same rule for
88
+ * artifact paths and this is its display sibling. A name the enumeration does
89
+ * not answer to falls back to the unfiled spelling, which is the only honest
90
+ * answer: there is no directory to point at, and that is usually what the
91
+ * message is about.
92
+ */
93
+ export async function serviceTreePathOf(docsDir, service, fleet) {
94
+ const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);
95
+ return entry === undefined ? `services/${service}` : serviceTreePath(entry);
96
+ }
97
+ export async function locateServicePaths(docsDir, service, fleet) {
98
+ const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);
99
+ return entry === undefined ? unfiledServicePaths(docsDir, service) : servicePathsAt(entry.dir);
100
+ }
101
+ export async function resolveServiceTarget(docsDir, name, label, fleet) {
102
+ // The enumeration is asked first, and its answer is the value that travels
103
+ // on: `entry.id` rather than `name`. They are equal as strings, and only one
104
+ // of them carries the fact that a `readdir` produced it. The resolved `dir`
105
+ // travels too, so a caller that goes on to read artifacts can spell
106
+ // `servicePathsAt(dir)` without a second enumeration; it is absent exactly
107
+ // when the name resolved by grammar alone — nothing exists to point at.
108
+ const entry = (await listServices(docsDir, fleet)).find((s) => s.id === name);
109
+ if (entry !== undefined)
110
+ return { ok: true, id: entry.id, dir: entry.dir };
111
+ return parseServiceId(name, label);
112
+ }
113
+ /**
114
+ * The same resolution for a name a DOCUMENT declared — an edge target's
115
+ * `metadata { service '…' }` binding, or its title standing in for one — where
116
+ * the caller needs an answer instead of a refusal: which enumerated directory,
117
+ * if any, does this text name?
118
+ *
119
+ * The enumeration is the fleet's `services/` plus whatever directory names the
120
+ * caller has already read for itself — a feature's own `specs/<svc>/`, the only
121
+ * place a service the feature INTRODUCES has a directory at all. There is
122
+ * deliberately no grammar arm here, in either direction: `services/Payment
123
+ * Service/` keeps resolving for the banner's reason, and a legal-looking name
124
+ * that matches no directory has no living file anywhere, so the caller's
125
+ * business is to grade it absent — never to build a path from it.
126
+ *
127
+ * The index is built on the first ask, not at construction: coherence asks per
128
+ * op-edge and features routinely carry none, so the enumeration only runs once
129
+ * an answer matters. A repo whose `services/` cannot be enumerated resolves
130
+ * only the caller's own names — every living probe would have found nothing
131
+ * there anyway, and `services-missing` is that repository's diagnosis, not
132
+ * this document's.
133
+ */
134
+ export function enumeratedServiceIndex(docsDir, known, fleet) {
135
+ let index;
136
+ return async (name) => {
137
+ if (index === undefined) {
138
+ index = new Map();
139
+ for (const id of known)
140
+ index.set(id, id);
141
+ try {
142
+ for (const s of await listServices(docsDir, fleet))
143
+ index.set(s.id, s.id);
144
+ }
145
+ catch {
146
+ // The docblock's last paragraph: no enumerable services/ means the
147
+ // fleet half of the index is empty, not that the question is an error.
148
+ }
149
+ }
150
+ return index.get(name);
151
+ };
152
+ }
153
+ //# sourceMappingURL=service-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service-target.js","sourceRoot":"","sources":["../../../src/core/repo/service-target.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turning a name a caller typed into a name loam may join into a path.\n *\n * `unfiledServicePaths(docsDir, name)` spells `<docsDir>/services/<name>/`,\n * and its parameter is `PathableService`: an unchecked name at that call site\n * no longer compiles, and this module is where a name a caller typed EARNS the\n * type. The history is why it exists. Six commands guard their argument with\n * `assertServiceId` at the boundary; `validate` never did, and both of its\n * entry points — `--service <id>` and the positional `<target>` — reached\n * the path builder with whatever argv held. `--service ../../outside/services/x`\n * resolved ABOVE the docs repo, and where a `spec.md` happened to sit there\n * loam opened it, graded it, and reported its frontmatter through `--json`.\n *\n * The grammar alone is not the answer, and this is the whole reason this module\n * exists rather than a call to `assertServiceId`. `services/Payment Service/`\n * is a directory `loam list` shows, `validate --all` grades, and\n * `service.id-invalid` calls an error nobody can fix without a rename — so it\n * is exactly the directory somebody points `validate --service` at. Refusing on\n * the grammar would make the one service loam complains about the one service\n * loam cannot look at.\n *\n * So the enumeration answers first and the grammar answers second:\n *\n * in `services/` → the enumeration's OWN id, which is a name loam\n * already reads off disk every time it lists the fleet.\n * Legal or not, it exists, and joining it lands where\n * the directory is.\n * not there, legal → the caller's name. Nothing exists yet; the run\n * continues and grades it `service.unknown`, with the\n * near-miss hints that make a typo diagnosable.\n * not there, illegal → refused, before any path is built.\n *\n * `show` and `status` already resolve against the enumeration this way. What\n * they do not do is fall through to the grammar, which is why they answer\n * \"no such service\" to a name that could never BE a service — a worse sentence\n * for the same input.\n */\nimport { listServices } from \"./repo.js\";\nimport { parseServiceId, type PathableService, type RawServiceId } from \"../kernel/ids/service.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { serviceTreePath, type DocsDir, type ServiceDir } from \"../kernel/ids/dirs.js\";\nimport { servicePathsAt, unfiledServicePaths, type ServicePaths } from \"./paths.js\";\nimport type { ServiceEntry } from \"./entries.js\";\n\nexport type ServiceTarget =\n | { readonly ok: true; readonly id: RawServiceId; readonly dir?: ServiceDir }\n | { readonly ok: false; readonly problem: string };\n\n/**\n * The enumerated services, or the empty list when `services/` cannot be\n * enumerated at all. The swallow is deliberate and spelled ONCE: every\n * repository-aware resolver wants \"which services exist\" as context, and an\n * unenumerable `services/` is that repository's own diagnosis\n * (`services-missing`), never the asking check's. Six call sites each carried\n * this try/catch in their own spelling before it lived here — which is exactly\n * the shape docs/CODE-STYLE.md warns about: an errno fix lands in one copy and\n * the other five keep the old behaviour. The existence probes that used to ask\n * `existsSync(services/<id>/)` ask membership HERE for the same tolerance:\n * `validate --feature` must run in a docs repo with no `services/` at all,\n * where enumerating is a refusal but \"does this service exist\" still has the\n * honest answer no.\n */\nexport async function enumeratedServices(\n docsDir: DocsDir,\n fleet?: FleetContext,\n): Promise<ServiceEntry[]> {\n try {\n return await listServices(docsDir, fleet);\n } catch {\n return [];\n }\n}\n\n/** The id projection of `enumeratedServices` — most membership asks want only the names. */\nexport async function enumeratedServiceIds(\n docsDir: DocsDir,\n fleet?: FleetContext,\n): Promise<RawServiceId[]> {\n return (await enumeratedServices(docsDir, fleet)).map((s) => s.id);\n}\n\n/**\n * The artifact paths of a service wherever it lives: the enumeration's own\n * directory when the id exists anywhere in the tree, the unfiled root\n * spelling otherwise — so an absent service still probes, grades\n * (`service.unknown`) and CREATES exactly as it did when the tree was flat.\n * This is the one bridge the ~40 former `servicePaths` call sites resolve\n * through — and it is NOT free: without a `fleet` context every call is a\n * fresh fleet enumeration (one readdir per directory walked plus a\n * frontmatter read and several existence probes per service), which measured\n * ~13 ms per call on a 120-service fleet. A call site inside a loop must\n * thread the command's `FleetContext`; a caller that already holds a\n * `ServiceEntry` should spell `servicePathsAt(entry.dir)` directly and pay\n * nothing.\n */\n/**\n * Where a service sits under `services/`, repo-relative and WITHOUT a trailing\n * slash — for a message that names an existing directory to a reader.\n *\n * The join it replaces is `services/${id}`, which is right for an unfiled\n * service and wrong for every filed one; `paths.ts` states the same rule for\n * artifact paths and this is its display sibling. A name the enumeration does\n * not answer to falls back to the unfiled spelling, which is the only honest\n * answer: there is no directory to point at, and that is usually what the\n * message is about.\n */\nexport async function serviceTreePathOf(\n docsDir: DocsDir,\n service: string,\n fleet?: FleetContext,\n): Promise<string> {\n const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);\n return entry === undefined ? `services/${service}` : serviceTreePath(entry);\n}\n\nexport async function locateServicePaths(\n docsDir: DocsDir,\n service: PathableService,\n fleet?: FleetContext,\n): Promise<ServicePaths> {\n const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);\n return entry === undefined ? unfiledServicePaths(docsDir, service) : servicePathsAt(entry.dir);\n}\n\nexport async function resolveServiceTarget(\n docsDir: DocsDir,\n name: string,\n label: string,\n fleet?: FleetContext,\n): Promise<ServiceTarget> {\n // The enumeration is asked first, and its answer is the value that travels\n // on: `entry.id` rather than `name`. They are equal as strings, and only one\n // of them carries the fact that a `readdir` produced it. The resolved `dir`\n // travels too, so a caller that goes on to read artifacts can spell\n // `servicePathsAt(dir)` without a second enumeration; it is absent exactly\n // when the name resolved by grammar alone — nothing exists to point at.\n const entry = (await listServices(docsDir, fleet)).find((s) => s.id === name);\n if (entry !== undefined) return { ok: true, id: entry.id, dir: entry.dir };\n return parseServiceId(name, label);\n}\n\n/**\n * The same resolution for a name a DOCUMENT declared — an edge target's\n * `metadata { service '…' }` binding, or its title standing in for one — where\n * the caller needs an answer instead of a refusal: which enumerated directory,\n * if any, does this text name?\n *\n * The enumeration is the fleet's `services/` plus whatever directory names the\n * caller has already read for itself — a feature's own `specs/<svc>/`, the only\n * place a service the feature INTRODUCES has a directory at all. There is\n * deliberately no grammar arm here, in either direction: `services/Payment\n * Service/` keeps resolving for the banner's reason, and a legal-looking name\n * that matches no directory has no living file anywhere, so the caller's\n * business is to grade it absent — never to build a path from it.\n *\n * The index is built on the first ask, not at construction: coherence asks per\n * op-edge and features routinely carry none, so the enumeration only runs once\n * an answer matters. A repo whose `services/` cannot be enumerated resolves\n * only the caller's own names — every living probe would have found nothing\n * there anyway, and `services-missing` is that repository's diagnosis, not\n * this document's.\n */\nexport function enumeratedServiceIndex(\n docsDir: DocsDir,\n known: readonly RawServiceId[],\n fleet?: FleetContext,\n): (name: string) => Promise<RawServiceId | undefined> {\n let index: Map<string, RawServiceId> | undefined;\n return async (name: string): Promise<RawServiceId | undefined> => {\n if (index === undefined) {\n index = new Map<string, RawServiceId>();\n for (const id of known) index.set(id, id);\n try {\n for (const s of await listServices(docsDir, fleet)) index.set(s.id, s.id);\n } catch {\n // The docblock's last paragraph: no enumerable services/ means the\n // fleet half of the index is empty, not that the question is an error.\n }\n }\n return index.get(name);\n };\n}\n"]}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Is there a docs repo there at all?
3
+ *
4
+ * Three answers, not two: missing, present-but-empty, and ok. The middle one
5
+ * exists because a freshly cloned docs repo whose `services/` git never tracked
6
+ * looks identical to a directory nobody wired — and the fix differs.
7
+ */
8
+ import { existsSync, statSync } from "node:fs";
9
+ import { join } from "node:path";
10
+ export function docsRepoState(docsDir) {
11
+ const path = docsDir;
12
+ let isDir = false;
13
+ try {
14
+ isDir = statSync(path).isDirectory();
15
+ }
16
+ catch {
17
+ isDir = false;
18
+ }
19
+ if (!isDir)
20
+ return { kind: "missing", path };
21
+ return { kind: existsSync(join(path, "services")) ? "ok" : "no-services", path };
22
+ }
23
+ /**
24
+ * The docs repo is not there. Thrown rather than returned because every caller
25
+ * of the enumeration wants the same thing — to stop — and a `[]` return is the
26
+ * bug this closes. `message` is written for a human at a terminal: the CLI's
27
+ * top-level handler prints it verbatim, and commands that catch it report
28
+ * `repository-unavailable`.
29
+ */
30
+ export class DocsRepoUnavailableError extends Error {
31
+ state;
32
+ constructor(state, message) {
33
+ super(message);
34
+ this.state = state;
35
+ this.name = "DocsRepoUnavailableError";
36
+ }
37
+ }
38
+ /**
39
+ * Refuse to enumerate a docs repo that is not one. `allow` names the states the
40
+ * caller can honestly survive: features/ may be absent from a real docs repo
41
+ * (nothing is in flight yet), so feature enumeration only insists the docs repo
42
+ * EXISTS, while service enumeration insists it is shaped like a docs repo — a
43
+ * `services/` directory is what makes it one.
44
+ */
45
+ export function requireDocsRepo(docsDir, allow) {
46
+ const state = docsRepoState(docsDir);
47
+ if (allow.includes(state.kind))
48
+ return;
49
+ if (state.kind === "missing") {
50
+ throw new DocsRepoUnavailableError(state, `The configured docs repo does not exist: ${state.path}. ` +
51
+ "Fix `docsDir` in loam.json, clone the docs repo there, " +
52
+ "or run `loam init --docs <dir> --create` to make a new one.");
53
+ }
54
+ throw new DocsRepoUnavailableError(state, `${state.path} is not a docs repo — it has no services/ directory. ` +
55
+ "Point `docsDir` in loam.json at the shared docs repo, " +
56
+ "or run `loam init --docs <dir> --create` to make one.");
57
+ }
58
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/core/repo/state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA8BjC,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC;IACrB,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,KAAK,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAEtC,KAAK;IADhB,YACW,KAAoB,EAC7B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;qBAHN,KAAK;QAId,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAqB;IACpE,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO;IACvC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,wBAAwB,CAChC,KAAK,EACL,4CAA4C,KAAK,CAAC,IAAI,IAAI;YACxD,yDAAyD;YACzD,6DAA6D,CAChE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,wBAAwB,CAChC,KAAK,EACL,GAAG,KAAK,CAAC,IAAI,uDAAuD;QAClE,wDAAwD;QACxD,uDAAuD,CAC1D,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Is there a docs repo there at all?\n *\n * Three answers, not two: missing, present-but-empty, and ok. The middle one\n * exists because a freshly cloned docs repo whose `services/` git never tracked\n * looks identical to a directory nobody wired — and the fix differs.\n */\nimport { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/* ------------------------------------------------------------------ */\n/* Is there a docs repo there at all? */\n/* ------------------------------------------------------------------ */\n\n/**\n * What is actually at `docsDir`. Three answers, because they point at three\n * different fixes and the enumeration below used to give all of them the same\n * one — an empty list:\n *\n * - `missing` — nothing there (or not a directory): `docsDir` in loam.json\n * is wrong, or the docs repo was never cloned;\n * - `no-services` — a directory, but with no `services/`: it is some other\n * directory, most often the service repo itself after a typo;\n * - `ok` — a docs repo. `services/` may still be EMPTY, and that is a\n * legitimate state: a docs repo before the first `loam adopt`.\n *\n * \"Empty fleet\" and \"wrong path\" are the same output only if nobody asks this\n * question, and a green `loam list` over a docsDir that does not exist is worse\n * than a red one: it says the fleet is fine.\n */\nexport type DocsRepoKind = \"missing\" | \"no-services\" | \"ok\";\n\nexport interface DocsRepoState {\n kind: DocsRepoKind;\n /** The path examined, so a caller can quote it without re-deriving it. */\n path: string;\n}\n\nexport function docsRepoState(docsDir: string): DocsRepoState {\n const path = docsDir;\n let isDir = false;\n try {\n isDir = statSync(path).isDirectory();\n } catch {\n isDir = false;\n }\n if (!isDir) return { kind: \"missing\", path };\n return { kind: existsSync(join(path, \"services\")) ? \"ok\" : \"no-services\", path };\n}\n\n/**\n * The docs repo is not there. Thrown rather than returned because every caller\n * of the enumeration wants the same thing — to stop — and a `[]` return is the\n * bug this closes. `message` is written for a human at a terminal: the CLI's\n * top-level handler prints it verbatim, and commands that catch it report\n * `repository-unavailable`.\n */\nexport class DocsRepoUnavailableError extends Error {\n constructor(\n readonly state: DocsRepoState,\n message: string,\n ) {\n super(message);\n this.name = \"DocsRepoUnavailableError\";\n }\n}\n\n/**\n * Refuse to enumerate a docs repo that is not one. `allow` names the states the\n * caller can honestly survive: features/ may be absent from a real docs repo\n * (nothing is in flight yet), so feature enumeration only insists the docs repo\n * EXISTS, while service enumeration insists it is shaped like a docs repo — a\n * `services/` directory is what makes it one.\n */\nexport function requireDocsRepo(docsDir: string, allow: DocsRepoKind[]): void {\n const state = docsRepoState(docsDir);\n if (allow.includes(state.kind)) return;\n if (state.kind === \"missing\") {\n throw new DocsRepoUnavailableError(\n state,\n `The configured docs repo does not exist: ${state.path}. ` +\n \"Fix `docsDir` in loam.json, clone the docs repo there, \" +\n \"or run `loam init --docs <dir> --create` to make a new one.\",\n );\n }\n throw new DocsRepoUnavailableError(\n state,\n `${state.path} is not a docs repo — it has no services/ directory. ` +\n \"Point `docsDir` in loam.json at the shared docs repo, \" +\n \"or run `loam init --docs <dir> --create` to make one.\",\n );\n}\n"]}