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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2548 -86
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2355 -256
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +72 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/{asyncapi.js → asyncapi/read.js} +95 -109
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +7 -64
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +120 -78
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -295
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -262
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1773
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -421
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2173
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js.map +0 -1
  970. package/dist/core/arch.js +0 -130
  971. package/dist/core/arch.js.map +0 -1
  972. package/dist/core/asyncapi.js.map +0 -1
  973. package/dist/core/brief.js +0 -755
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -596
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -489
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -787
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -438
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -505
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1132
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The human view of an inventory, shared by both verbs.
3
+ *
4
+ * `audit-openspec` and `migrate-openspec` print the same block and differ only
5
+ * in the word above it, so the renderer takes the mode rather than existing
6
+ * twice — the audit's readiness line and the migration's are the same claim and
7
+ * have to stay the same claim.
8
+ *
9
+ * The local `plural` is not a duplicate of `../format.ts`'s. That one spells
10
+ * the regular English plural only, and says so: an irregular noun belongs at
11
+ * the call site. "capability"/"capabilities" is exactly that noun, so this
12
+ * renderer carries the two-form variant instead of misspelling a count.
13
+ */
14
+ import {} from "../../core/openspec/model/model.js";
15
+ function plural(count, one, many = `${one}s`) {
16
+ return `${count} ${count === 1 ? one : many}`;
17
+ }
18
+ export function printInventory(inventory, mode) {
19
+ const status = inventory.ready
20
+ ? "ready"
21
+ : inventory.mechanicallyCompatible
22
+ ? "compatible; explicit mapping/identity decisions remain"
23
+ : "living or active blockers found";
24
+ console.log(`OpenSpec ${mode} inventory — ${status}`);
25
+ console.log(` root ${inventory.root}`);
26
+ console.log(` baseline release ${inventory.baselines.release.version}@${inventory.baselines.release.commit} · main canary ${inventory.baselines.mainCanary.commit.slice(0, 7)}`);
27
+ console.log(` living ${plural(inventory.living.capabilities.length, "capability", "capabilities")} · ${plural(inventory.living.specFiles, "spec file")} · ${plural(inventory.living.requirements, "requirement")} · ${plural(inventory.living.scenarios, "scenario")}`);
28
+ console.log(` changes ${inventory.changes.counts.active} active · ${inventory.changes.counts.archived} archived`);
29
+ console.log(` readiness living ${inventory.readiness.living.compatible ? "ok" : "blocked"} · active ${inventory.readiness.active.compatible ? "ok" : "blocked"} · source ${inventory.readiness.sourceCurrent ? "current" : "stale"} · capabilities ${inventory.readiness.mappingsResolved ? "resolved" : "open"} · changes ${inventory.readiness.changesResolved ? "resolved" : "open"} · dispositions ${inventory.readiness.dispositionsResolved ? "resolved" : "open"} · archive ${inventory.archiveDiagnostics.length} diagnostic(s)`);
30
+ if (inventory.needsMapping.length > 0) {
31
+ console.log("\n capability → service decisions");
32
+ for (const decision of inventory.needsMapping) {
33
+ console.log(` ? ${decision.capability} → ${decision.suggestedService} [${decision.status}]`);
34
+ }
35
+ }
36
+ if (inventory.needsChangeMapping.length > 0) {
37
+ console.log("\n change → feature decisions");
38
+ for (const decision of inventory.needsChangeMapping) {
39
+ console.log(` ? ${decision.change} → ${decision.suggestedFeature} [${decision.status}]`);
40
+ }
41
+ }
42
+ const activeRenames = inventory.renamed.filter((rename) => rename.scope === "active");
43
+ if (activeRenames.length > 0) {
44
+ console.log("\n RENAMED identity decisions");
45
+ for (const rename of activeRenames) {
46
+ console.log(` ${rename.status === "mapped" ? "✓" : "?"} ${rename.key} ${rename.from ?? "<missing FROM>"} → ${rename.to ?? "<missing TO>"}${rename.requirementId ? ` [${rename.requirementId}]` : ""}`);
47
+ }
48
+ }
49
+ if (inventory.needsDisposition.length > 0) {
50
+ console.log(`\n authored artifact decisions (${inventory.needsDisposition.length})`);
51
+ for (const decision of inventory.needsDisposition.slice(0, 12)) {
52
+ console.log(` ? ${decision.path} → ${decision.suggestedDisposition} [${decision.status}]`);
53
+ }
54
+ if (inventory.needsDisposition.length > 12) {
55
+ console.log(` … ${inventory.needsDisposition.length - 12} more in --json/mapping output`);
56
+ }
57
+ }
58
+ if (inventory.mappingIssues.length > 0) {
59
+ console.log("\n mapping issues");
60
+ for (const item of inventory.mappingIssues)
61
+ console.log(` ✗ ${item.code} ${item.message}`);
62
+ }
63
+ if (inventory.unsupported.length > 0) {
64
+ console.log("\n living/active blockers");
65
+ for (const item of inventory.unsupported) {
66
+ console.log(` ✗ ${item.code} ${item.path} — ${item.message}`);
67
+ }
68
+ }
69
+ if (inventory.archiveDiagnostics.length > 0) {
70
+ console.log(`\n archive diagnostics (non-blocking, ${inventory.archiveDiagnostics.length})`);
71
+ for (const item of inventory.archiveDiagnostics.slice(0, 12)) {
72
+ console.log(` · ${item.code} ${item.path} — ${item.message}`);
73
+ }
74
+ if (inventory.archiveDiagnostics.length > 12) {
75
+ console.log(` … ${inventory.archiveDiagnostics.length - 12} more in --json output`);
76
+ }
77
+ }
78
+ const dispositions = new Map();
79
+ for (const artifact of inventory.artifacts) {
80
+ dispositions.set(artifact.disposition, (dispositions.get(artifact.disposition) ?? 0) + 1);
81
+ }
82
+ if (dispositions.size > 0) {
83
+ console.log("\n artifact disposition");
84
+ for (const [disposition, count] of [...dispositions].sort(([a], [b]) => a.localeCompare(b))) {
85
+ console.log(` · ${disposition} ${count}`);
86
+ }
87
+ }
88
+ }
89
+ //# sourceMappingURL=print.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"print.js","sourceRoot":"","sources":["../../../src/commands/migrate-openspec/print.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The human view of an inventory, shared by both verbs.\n *\n * `audit-openspec` and `migrate-openspec` print the same block and differ only\n * in the word above it, so the renderer takes the mode rather than existing\n * twice — the audit's readiness line and the migration's are the same claim and\n * have to stay the same claim.\n *\n * The local `plural` is not a duplicate of `../format.ts`'s. That one spells\n * the regular English plural only, and says so: an irregular noun belongs at\n * the call site. \"capability\"/\"capabilities\" is exactly that noun, so this\n * renderer carries the two-form variant instead of misspelling a count.\n */\nimport { type OpenSpecInventory } from \"../../core/openspec/model/model.js\";\n\nfunction plural(count: number, one: string, many = `${one}s`): string {\n return `${count} ${count === 1 ? one : many}`;\n}\n\nexport function printInventory(inventory: OpenSpecInventory, mode: \"audit\" | \"migration\"): void {\n const status = inventory.ready\n ? \"ready\"\n : inventory.mechanicallyCompatible\n ? \"compatible; explicit mapping/identity decisions remain\"\n : \"living or active blockers found\";\n console.log(`OpenSpec ${mode} inventory — ${status}`);\n console.log(` root ${inventory.root}`);\n console.log(\n ` baseline release ${inventory.baselines.release.version}@${inventory.baselines.release.commit} · main canary ${inventory.baselines.mainCanary.commit.slice(0, 7)}`,\n );\n console.log(\n ` living ${plural(inventory.living.capabilities.length, \"capability\", \"capabilities\")} · ${plural(inventory.living.specFiles, \"spec file\")} · ${plural(inventory.living.requirements, \"requirement\")} · ${plural(inventory.living.scenarios, \"scenario\")}`,\n );\n console.log(\n ` changes ${inventory.changes.counts.active} active · ${inventory.changes.counts.archived} archived`,\n );\n console.log(\n ` readiness living ${inventory.readiness.living.compatible ? \"ok\" : \"blocked\"} · active ${inventory.readiness.active.compatible ? \"ok\" : \"blocked\"} · source ${inventory.readiness.sourceCurrent ? \"current\" : \"stale\"} · capabilities ${inventory.readiness.mappingsResolved ? \"resolved\" : \"open\"} · changes ${inventory.readiness.changesResolved ? \"resolved\" : \"open\"} · dispositions ${inventory.readiness.dispositionsResolved ? \"resolved\" : \"open\"} · archive ${inventory.archiveDiagnostics.length} diagnostic(s)`,\n );\n\n if (inventory.needsMapping.length > 0) {\n console.log(\"\\n capability → service decisions\");\n for (const decision of inventory.needsMapping) {\n console.log(` ? ${decision.capability} → ${decision.suggestedService} [${decision.status}]`);\n }\n }\n if (inventory.needsChangeMapping.length > 0) {\n console.log(\"\\n change → feature decisions\");\n for (const decision of inventory.needsChangeMapping) {\n console.log(` ? ${decision.change} → ${decision.suggestedFeature} [${decision.status}]`);\n }\n }\n const activeRenames = inventory.renamed.filter((rename) => rename.scope === \"active\");\n if (activeRenames.length > 0) {\n console.log(\"\\n RENAMED identity decisions\");\n for (const rename of activeRenames) {\n console.log(\n ` ${rename.status === \"mapped\" ? \"✓\" : \"?\"} ${rename.key} ${rename.from ?? \"<missing FROM>\"} → ${rename.to ?? \"<missing TO>\"}${rename.requirementId ? ` [${rename.requirementId}]` : \"\"}`,\n );\n }\n }\n if (inventory.needsDisposition.length > 0) {\n console.log(`\\n authored artifact decisions (${inventory.needsDisposition.length})`);\n for (const decision of inventory.needsDisposition.slice(0, 12)) {\n console.log(` ? ${decision.path} → ${decision.suggestedDisposition} [${decision.status}]`);\n }\n if (inventory.needsDisposition.length > 12) {\n console.log(` … ${inventory.needsDisposition.length - 12} more in --json/mapping output`);\n }\n }\n if (inventory.mappingIssues.length > 0) {\n console.log(\"\\n mapping issues\");\n for (const item of inventory.mappingIssues) console.log(` ✗ ${item.code} ${item.message}`);\n }\n if (inventory.unsupported.length > 0) {\n console.log(\"\\n living/active blockers\");\n for (const item of inventory.unsupported) {\n console.log(` ✗ ${item.code} ${item.path} — ${item.message}`);\n }\n }\n if (inventory.archiveDiagnostics.length > 0) {\n console.log(`\\n archive diagnostics (non-blocking, ${inventory.archiveDiagnostics.length})`);\n for (const item of inventory.archiveDiagnostics.slice(0, 12)) {\n console.log(` · ${item.code} ${item.path} — ${item.message}`);\n }\n if (inventory.archiveDiagnostics.length > 12) {\n console.log(` … ${inventory.archiveDiagnostics.length - 12} more in --json output`);\n }\n }\n const dispositions = new Map<string, number>();\n for (const artifact of inventory.artifacts) {\n dispositions.set(artifact.disposition, (dispositions.get(artifact.disposition) ?? 0) + 1);\n }\n if (dispositions.size > 0) {\n console.log(\"\\n artifact disposition\");\n for (const [disposition, count] of [...dispositions].sort(([a], [b]) => a.localeCompare(b))) {\n console.log(` · ${disposition} ${count}`);\n }\n }\n}\n"]}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The scaffold's commit window: lock, recover, the one existence check, the
3
+ * exclusive-create transaction. Split from new.ts on the same seam vouch's
4
+ * commitStamp and gherkin's commitEmission sit on — everything in here holds
5
+ * the docs lock, nothing outside it does — and, as there, the split keeps the
6
+ * window's extent visible in the code shape. This module prints nothing; the
7
+ * caller renders every arm.
8
+ */
9
+ import {} from "../../core/repo/entries.js";
10
+ import {} from "../../core/kernel/ids/dirs.js";
11
+ import { resolveFeature } from "../../core/repo/repo.js";
12
+ import { DocsRepoUnavailableError } from "../../core/repo/state.js";
13
+ import { stageWrites } from "../../core/staging/commit.js";
14
+ import { InterruptedCommitError } from "../../core/staging/interrupted.js";
15
+ import { acquireDocsLockWaiting, DocsBusyError, LOCK_WAIT_MS } from "../../core/staging/lock.js";
16
+ import { recoverInterruptedCommit } from "../../core/staging/recovery/recover.js";
17
+ import { commitStaged } from "../../core/staging/txn/transaction.js";
18
+ import {} from "../../core/staging/writes.js";
19
+ export async function commitScaffold(docsDir, featureId, writes) {
20
+ // The commit window holds the docs lock: two `new`s for one id serialise
21
+ // into a stable already-exists, and a predecessor's interrupted commit is
22
+ // rolled forward (or refused) before this one stages anything.
23
+ let releaseLock;
24
+ try {
25
+ releaseLock = await acquireDocsLockWaiting(docsDir, LOCK_WAIT_MS);
26
+ }
27
+ catch (err) {
28
+ if (err instanceof DocsBusyError)
29
+ return { ok: false, code: "docs-busy", message: err.message };
30
+ throw err;
31
+ }
32
+ try {
33
+ let recovered;
34
+ try {
35
+ recovered = await recoverInterruptedCommit(docsDir);
36
+ }
37
+ catch (err) {
38
+ if (!(err instanceof InterruptedCommitError))
39
+ throw err;
40
+ return { ok: false, code: "commit-interrupted", message: err.message };
41
+ }
42
+ // The one existence check, UNDER the lock and AFTER recovery: two racing
43
+ // runs serialise on it, and a recovered half-scaffold has been completed
44
+ // by the recovery above, so this refusal is truthful.
45
+ let existing;
46
+ try {
47
+ existing = await resolveFeature(docsDir, featureId, "include");
48
+ }
49
+ catch (err) {
50
+ // The command's gate already refused both broken states, so reaching
51
+ // here means the docs repo went away between that check and this read.
52
+ // Same breach, same two codes — the alternative is a stack trace under
53
+ // `internal` that names neither.
54
+ if (!(err instanceof DocsRepoUnavailableError))
55
+ throw err;
56
+ return { ok: false, repoGone: err };
57
+ }
58
+ if (existing)
59
+ return { ok: false, code: "already-exists", existing, recovered };
60
+ const staged = await stageWrites(writes);
61
+ const committed = await commitStaged({ root: docsDir, command: "new", rerun: `loam new ${featureId}`, target: featureId }, staged, "scaffolded");
62
+ if (!committed.ok) {
63
+ // A lost exclusive-create race IS the feature existing: the other `new`
64
+ // won, and this refusal is the same stable answer the check above gives
65
+ // when it sees the winner first.
66
+ return committed.raced
67
+ ? { ok: false, code: "already-exists", existing: null, recovered }
68
+ : { ok: false, code: committed.code, message: committed.message };
69
+ }
70
+ return { ok: true, recovered };
71
+ }
72
+ finally {
73
+ await releaseLock();
74
+ }
75
+ }
76
+ //# sourceMappingURL=commit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../src/commands/new/commit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The scaffold's commit window: lock, recover, the one existence check, the\n * exclusive-create transaction. Split from new.ts on the same seam vouch's\n * commitStamp and gherkin's commitEmission sit on — everything in here holds\n * the docs lock, nothing outside it does — and, as there, the split keeps the\n * window's extent visible in the code shape. This module prints nothing; the\n * caller renders every arm.\n */\nimport { type FeatureEntry } from \"../../core/repo/entries.js\";\nimport { type DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { resolveFeature } from \"../../core/repo/repo.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { stageWrites } from \"../../core/staging/commit.js\";\nimport { type CommitRecovery, InterruptedCommitError } from \"../../core/staging/interrupted.js\";\nimport { acquireDocsLockWaiting, DocsBusyError, LOCK_WAIT_MS } from \"../../core/staging/lock.js\";\nimport { recoverInterruptedCommit } from \"../../core/staging/recovery/recover.js\";\nimport { commitStaged } from \"../../core/staging/txn/transaction.js\";\nimport { type PlannedWrite } from \"../../core/staging/writes.js\";\n\nexport type ScaffoldCommit =\n | { ok: true; recovered: CommitRecovery | null }\n | {\n ok: false;\n code: \"docs-busy\" | \"commit-interrupted\" | \"merge-failed\" | \"rollback-incomplete\";\n message: string;\n }\n /** The feature exists — found by the under-lock check, or by losing the create race. */\n | { ok: false; code: \"already-exists\"; existing: FeatureEntry | null; recovered: CommitRecovery | null }\n /**\n * The docs repo went away between the command's gate and the locked read.\n * Deliberately NOT a `code:` arm: the caller renders it through the shared\n * docs-repo reporter, and the codes-drift collector reads every `code:`\n * literal as a stable emission — which this discriminant is not.\n */\n | { ok: false; repoGone: DocsRepoUnavailableError };\n\nexport async function commitScaffold(\n docsDir: DocsDir,\n featureId: string,\n writes: PlannedWrite[],\n): Promise<ScaffoldCommit> {\n // The commit window holds the docs lock: two `new`s for one id serialise\n // into a stable already-exists, and a predecessor's interrupted commit is\n // rolled forward (or refused) before this one stages anything.\n let releaseLock: () => Promise<void>;\n try {\n releaseLock = await acquireDocsLockWaiting(docsDir, LOCK_WAIT_MS);\n } catch (err) {\n if (err instanceof DocsBusyError) return { ok: false, code: \"docs-busy\", message: err.message };\n throw err;\n }\n try {\n let recovered: CommitRecovery | null;\n try {\n recovered = await recoverInterruptedCommit(docsDir);\n } catch (err) {\n if (!(err instanceof InterruptedCommitError)) throw err;\n return { ok: false, code: \"commit-interrupted\", message: err.message };\n }\n // The one existence check, UNDER the lock and AFTER recovery: two racing\n // runs serialise on it, and a recovered half-scaffold has been completed\n // by the recovery above, so this refusal is truthful.\n let existing: FeatureEntry | null;\n try {\n existing = await resolveFeature(docsDir, featureId, \"include\");\n } catch (err) {\n // The command's gate already refused both broken states, so reaching\n // here means the docs repo went away between that check and this read.\n // Same breach, same two codes — the alternative is a stack trace under\n // `internal` that names neither.\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n return { ok: false, repoGone: err };\n }\n if (existing) return { ok: false, code: \"already-exists\", existing, recovered };\n const staged = await stageWrites(writes);\n const committed = await commitStaged(\n { root: docsDir, command: \"new\", rerun: `loam new ${featureId}`, target: featureId },\n staged,\n \"scaffolded\",\n );\n if (!committed.ok) {\n // A lost exclusive-create race IS the feature existing: the other `new`\n // won, and this refusal is the same stable answer the check above gives\n // when it sees the winner first.\n return committed.raced\n ? { ok: false, code: \"already-exists\", existing: null, recovered }\n : { ok: false, code: committed.code, message: committed.message };\n }\n return { ok: true, recovered };\n } finally {\n await releaseLock();\n }\n}\n"]}
@@ -0,0 +1,283 @@
1
+ import {} from "../../core/staging/writes.js";
2
+ import { commitScaffold } from "./commit.js";
3
+ import { join } from "node:path";
4
+ import { loadConfig } from "../../core/envelope/config.js";
5
+ import { parseFeatureId } from "../../core/kernel/ids/feature.js";
6
+ import { parseServiceIds } from "../../core/kernel/ids/service.js";
7
+ import { emitJson, fail, repoPath, reportNoConfig } from "../../core/envelope/json.js";
8
+ import { UnsafePathError, resolveInside } from "../../core/kernel/path-safety.js";
9
+ import { featureIdFromDirName, nearestIds } from "../../core/repo/entries.js";
10
+ import { featuresDir } from "../../core/repo/paths.js";
11
+ import { DocsRepoUnavailableError } from "../../core/repo/state.js";
12
+ import { listServices } from "../../core/repo/repo.js";
13
+ import { docsRepoReady, reportDocsRepoError } from "../policy/gate.js";
14
+ import { sayRecovered } from "../policy/format.js";
15
+ import { capabilityIdProblem } from "../../core/kernel/ids/capability.js";
16
+ import { capabilityNotes } from "../../core/capabilities/authoring/notes.js";
17
+ import { archSpecTemplate, capabilityDeltaTemplate, deltaTemplate, intentTemplate, openapiTemplate, specTemplate, } from "./templates.js";
18
+ export function registerNew(program) {
19
+ program
20
+ .command("new")
21
+ .argument("<featureId>", "feature id, e.g. FEAT-101")
22
+ .description("Scaffold a feature: intent, C4 delta, a requirement delta per service, a capability delta per promise")
23
+ .option("--title <text>", "human title; also becomes the directory slug")
24
+ // `--touches`, not `--service`: everywhere else `--service` selects the ONE
25
+ // operating target (defaulting to config.service), while this is a repeatable
26
+ // list of services the feature touches — a different arity and a different
27
+ // meaning deserve a different name.
28
+ .option("--touches <id>", "a service this feature touches (repeatable)", collect, [])
29
+ .option("--new-service <id>", "a service this feature introduces (repeatable)", collect, [])
30
+ // The INVERSION of the two flags above, and it composes with them rather
31
+ // than excluding them. `--touches` asks which services change before the
32
+ // business change has been written; `--capability` opens the document that
33
+ // changes and lets the service work be derived from it. A feature that
34
+ // does both — the analyst writes the promise, and one team already knows it
35
+ // owns part of the mechanism — is an ordinary shape, and refusing the
36
+ // combination would fight this axis's own archive gate: `capability.uncovered`
37
+ // refuses a promise nothing in the same feature keeps, so the fix it names
38
+ // is precisely a `--touches` service's `Realizes:` line living beside the
39
+ // capability delta.
40
+ //
41
+ // Repeatable, like both flags above: a business change that moves two
42
+ // promises is as real as a feature touching two services, and the flag that
43
+ // is not repeatable is the one that sends an author to mkdir by hand.
44
+ .option("--capability <id>", "a business capability this feature changes (repeatable)", collect, [])
45
+ .option("--json", "emit the machine contract instead of the human view")
46
+ .action(async (featureId, opts) => {
47
+ const json = opts.json === true;
48
+ // The grammar's verdict arrives as the brand: `featureDirName` demands
49
+ // a FeatureId, so an argv string cannot reach the directory derivation
50
+ // without passing through this parse — the producer the brand was
51
+ // missing while `isFeatureId` narrowed to plain string.
52
+ const parsedId = parseFeatureId(featureId, "feature id");
53
+ if (!parsedId.ok) {
54
+ return fail(json, "invalid-option", parsedId.problem);
55
+ }
56
+ const dirName = featureDirName(parsedId.id, opts.title);
57
+ // The round-trip is checked beside the grammar, not inside it: the
58
+ // grammar is a fact about the id, while `featureIdFromDirName` depends on
59
+ // the TITLE this command is about to slug into the directory name. Only
60
+ // `new` creates that directory, so only `new` owes that second half.
61
+ if (featureIdFromDirName(dirName) !== featureId) {
62
+ return fail(json, "invalid-option", `'${featureId}' does not survive the directory round-trip with this title.`);
63
+ }
64
+ // Service ids are validated BEFORE the config is even loaded, and long
65
+ // before anything is written: every one of them is interpolated into
66
+ // `specs/<id>/` under the new feature directory, so `--touches ../../x`
67
+ // was a writer pointed outside the docs repo. One grammar (core/kernel/ids/service.ts),
68
+ // the same one adopt/init/vouch refuse on, so a service that is legal to
69
+ // create is legal to name here and nowhere the two disagree.
70
+ // The LIST, not each item: a loop narrows the element and leaves the
71
+ // array unbranded, so what reached the writer below was `string[]` no
72
+ // matter how thoroughly each id had been checked. --touches first, so the
73
+ // id reported first is the one it was before.
74
+ const touches = parseServiceIds(opts.touches, "--touches");
75
+ if (!touches.ok)
76
+ return fail(json, "invalid-option", touches.problem);
77
+ const newServices = parseServiceIds(opts.newService, "--new-service");
78
+ if (!newServices.ok)
79
+ return fail(json, "invalid-option", newServices.problem);
80
+ // Same reasoning as the two lists above, one tree over. A capability id
81
+ // becomes `features/<dirName>/capabilities/<id>/` — a chain of
82
+ // directories, one per `/`-separated segment — so `--capability
83
+ // ../../evil` resolves to `features/evil/spec.md`, a directory
84
+ // `listFeatures` then enumerates as a feature, and one `..` further
85
+ // reaches the docs-repo root. `resolveInside` below cannot refuse either:
86
+ // both are still inside the repo. Checked here for that reason, and
87
+ // against the same directory-name grammar a service id passes
88
+ // (core/kernel/ids/capability.ts).
89
+ const capabilities = opts.capability;
90
+ for (const id of capabilities) {
91
+ const problem = capabilityIdProblem(id);
92
+ if (problem !== null)
93
+ return fail(json, "invalid-option", problem);
94
+ }
95
+ const loaded = await loadConfig();
96
+ if (loaded.kind !== "loaded") {
97
+ reportNoConfig(json, loaded);
98
+ return;
99
+ }
100
+ const config = loaded.config;
101
+ const { docsDir } = config;
102
+ // Before a single file is scaffolded: a docsDir that is not a docs repo is
103
+ // refused, never written into. `features/<id>/**` lands happily in any
104
+ // directory, so without this gate `new` reported `ok: true` over a
105
+ // scaffold that no enumeration downstream will ever see — and a docsDir
106
+ // that is simply absent escaped as `internal` (the enumeration below
107
+ // throws) carrying the very sentence `list` and `show` report as
108
+ // `docs-missing`. See docs-repo-gate.ts's docsRepoReady. `services`, not
109
+ // `docs`: every id named by --touches/--new-service is a claim about
110
+ // `services/<id>/`, and the near-miss note below is computed against that
111
+ // directory, so a run without it is guessing.
112
+ if (!docsRepoReady(json, docsDir, "services"))
113
+ return;
114
+ // No unlocked existence fast-path, deliberately: staging creates the
115
+ // feature directory at plan time, so a HALF-scaffold from a killed run
116
+ // resolves like a finished feature — and an unlocked refusal here made
117
+ // \`loam new <id>\` answer already-exists over its own wreckage without
118
+ // ever reaching the recovery that would complete it, while doctor's fix
119
+ // printed exactly that re-run. Existence is asked once, under the lock,
120
+ // after recovery has run.
121
+ // A service named both ways is new — that is the more specific claim.
122
+ const created = new Set(newServices.ids);
123
+ const touched = touches.ids.filter((s) => !created.has(s));
124
+ const dir = join(featuresDir(docsDir), dirName);
125
+ const files = {
126
+ "intent.md": intentTemplate(featureId, opts.title),
127
+ "delta.likec4": deltaTemplate(featureId, touched, [...created]),
128
+ };
129
+ for (const svc of [...touched, ...created]) {
130
+ files[join("specs", svc, "spec.md")] = specTemplate(featureId, svc);
131
+ }
132
+ // The business axis, and the ONE file `--capability` adds. No service
133
+ // spec rides with it, and that is the inversion rather than an omission:
134
+ // the whole point of opening the document that changes first is that the
135
+ // services realizing it are not known until the promise is written.
136
+ // `--touches` is still how a service the author already knows about gets
137
+ // its delta, which is why the two compose.
138
+ //
139
+ // Spelled relative, mirroring `featureCapabilityDeltasDir` +
140
+ // `capabilityDocPathsAt` in core/repo/authored/paths.ts — the path builders take a
141
+ // FeatureDir, whose provenance is an enumeration that read the directory,
142
+ // and this directory is about to be created rather than read. One
143
+ // directory per segment, exactly as the living tree spells nesting.
144
+ for (const cap of capabilities) {
145
+ files[join("capabilities", ...cap.split("/"), "spec.md")] = capabilityDeltaTemplate(featureId, cap);
146
+ }
147
+ for (const svc of created) {
148
+ files[join("specs", svc, "openapi.yaml")] = openapiTemplate(svc);
149
+ // The architecture axis is scaffolded only for a service this feature
150
+ // INTRODUCES, because that is the case where `c4.uncovered` will fire
151
+ // the moment the delta is written: a brand-new tagged element nothing
152
+ // covers. Handing an author a blank page for the outbox/retries/alerts
153
+ // requirement is how that axis stays empty across a whole fleet.
154
+ files[join("specs", svc, "arch.spec.md")] = archSpecTemplate(featureId, svc);
155
+ }
156
+ // The COMPLETE plan in memory before a byte lands on disk: every path
157
+ // resolved (belt and braces over the id grammar — resolveInside proves
158
+ // containment at the moment of the write, symlink cases included), and
159
+ // every write an exclusive create, because the feature must not exist.
160
+ // The sequential writeFile loop this replaces could die mid-scaffold and
161
+ // leave a partial feature the next run refused as already-exists.
162
+ const writes = [];
163
+ for (const [rel, content] of Object.entries(files)) {
164
+ let path;
165
+ try {
166
+ path = resolveInside(docsDir, join("features", dirName, rel), "feature file");
167
+ }
168
+ catch (err) {
169
+ if (!(err instanceof UnsafePathError))
170
+ throw err;
171
+ return fail(json, "invalid-option", err.message);
172
+ }
173
+ writes.push({ path, content, exclusive: true });
174
+ }
175
+ const committed = await commitScaffold(docsDir, featureId, writes);
176
+ if (!committed.ok) {
177
+ if ("repoGone" in committed) {
178
+ reportDocsRepoError(json, committed.repoGone);
179
+ return;
180
+ }
181
+ if (committed.code === "already-exists") {
182
+ // After a recovery the refusal must SAY the repair happened: doctor
183
+ // told the operator to re-run this exact command, and "already
184
+ // exists" alone reads as the fix having failed.
185
+ return fail(json, "already-exists", `Feature '${featureId}' already exists at ${repoPath(docsDir, committed.existing?.dir ?? dir)}.` +
186
+ (committed.recovered === null ? "" : ` (${sayRecovered(committed.recovered)} The scaffold is complete.)`));
187
+ }
188
+ return fail(json, committed.code, committed.message);
189
+ }
190
+ const recovered = committed.recovered;
191
+ const written = writes.map((w) => repoPath(docsDir, w.path));
192
+ // Both note families in ONE list, and the services first so an existing
193
+ // `--touches` consumer reads the same first element it always did. They
194
+ // are the same kind of statement — "the thing you named is not there yet,
195
+ // and here is what that means" — so splitting them into two payload keys
196
+ // would ask a consumer to learn a second shape for one idea.
197
+ const notes = [
198
+ ...(await unknownServiceNotes(docsDir, touched)),
199
+ ...(await capabilityNotes(docsDir, { dirName, ids: capabilities })),
200
+ ];
201
+ if (json) {
202
+ emitJson({
203
+ command: "new",
204
+ feature: featureId,
205
+ path: repoPath(docsDir, dir),
206
+ created: written,
207
+ ...(recovered === null ? {} : { recovered }),
208
+ // Not an error and not a finding: `--touches` on a service that does
209
+ // not exist yet is legal (adopt it later, or say `--new-service`),
210
+ // and `--capability` on a promise nobody has named is the ordinary
211
+ // way a new business area starts. Both are reported because the
212
+ // silent alternative is a delta that will never merge into anything,
213
+ // or a near-miss spelling filed as a second capability.
214
+ notes,
215
+ });
216
+ return;
217
+ }
218
+ console.log(`${featureId} scaffolded at ${repoPath(docsDir, dir)}`);
219
+ for (const w of written)
220
+ console.log(` + ${w}`);
221
+ for (const note of notes)
222
+ console.log(`\n note: ${note}`);
223
+ console.log(`\nNext: fill in the delta, then \`loam validate --feature ${featureId}\`.`);
224
+ console.log("If this feature changes no architecture, delete delta.likec4 — a requirements-only\n" +
225
+ "feature is complete without it, and an empty `model {}` validates clean too.");
226
+ });
227
+ }
228
+ function collect(value, previous) {
229
+ return [...previous, value];
230
+ }
231
+ /* ------------------------------------------------------------------ */
232
+ /* Hints */
233
+ /* ------------------------------------------------------------------ */
234
+ /**
235
+ * `--touches <id>` naming neither a living `services/<id>/` nor a `--new-service`
236
+ * is almost always a typo, and it is silent by construction: the scaffold writes
237
+ * `specs/<id>/spec.md` happily, `loam validate` grades a delta against a living
238
+ * spec that is not there, and the mistake surfaces at archive time as a service
239
+ * appearing from nowhere. A note, not a refusal — naming a service that will be
240
+ * adopted next week is legitimate — but the near-miss is spelled out, because
241
+ * `order-api` vs `orders-api` is exactly the pair a person cannot see.
242
+ */
243
+ async function unknownServiceNotes(docsDir, touched) {
244
+ if (touched.length === 0)
245
+ return [];
246
+ let known;
247
+ try {
248
+ known = (await listServices(docsDir)).map((s) => s.id);
249
+ }
250
+ catch (err) {
251
+ // No docs repo to compare against is a different diagnosis entirely, and
252
+ // `loam doctor` owns it. Saying nothing here beats inventing a typo hint
253
+ // out of an enumeration that never ran.
254
+ if (!(err instanceof DocsRepoUnavailableError))
255
+ throw err;
256
+ return [];
257
+ }
258
+ const notes = [];
259
+ for (const id of touched) {
260
+ if (known.includes(id))
261
+ continue;
262
+ const near = nearestIds(id, known);
263
+ notes.push(`--touches '${id}' matches no services/${id}/ in the docs repo` +
264
+ (near.length === 0 ? "" : ` — did you mean ${near.map((n) => `'${n}'`).join(" or ")}?`) +
265
+ ` If ${id} is introduced by this feature, pass --new-service ${id} instead.`);
266
+ }
267
+ return notes;
268
+ }
269
+ /* ------------------------------------------------------------------ */
270
+ /* Naming */
271
+ /* ------------------------------------------------------------------ */
272
+ function featureDirName(featureId, title) {
273
+ const slug = slugify(title ?? "");
274
+ return slug ? `${featureId}-${slug}` : featureId;
275
+ }
276
+ function slugify(text) {
277
+ return text
278
+ .toLowerCase()
279
+ .replace(/[^a-z0-9]+/g, "-")
280
+ .replace(/^-+|-+$/g, "");
281
+ }
282
+ /** A LikeC4 identifier for a service name: `payment-split-service` -> `paymentSplitService`. */
283
+ //# sourceMappingURL=new.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"new.js","sourceRoot":"","sources":["../../../src/commands/new/new.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport { type PlannedWrite } from \"../../core/staging/writes.js\";\nimport { commitScaffold } from \"./commit.js\";\nimport { join } from \"node:path\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { type FeatureId, parseFeatureId } from \"../../core/kernel/ids/feature.js\";\nimport { parseServiceIds } from \"../../core/kernel/ids/service.js\";\nimport { emitJson, fail, repoPath, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { UnsafePathError, resolveInside } from \"../../core/kernel/path-safety.js\";\nimport { featureIdFromDirName, nearestIds } from \"../../core/repo/entries.js\";\nimport { featuresDir } from \"../../core/repo/paths.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { listServices } from \"../../core/repo/repo.js\";\nimport { docsRepoReady, reportDocsRepoError } from \"../policy/gate.js\";\nimport { sayRecovered } from \"../policy/format.js\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { capabilityIdProblem } from \"../../core/kernel/ids/capability.js\";\nimport { capabilityNotes } from \"../../core/capabilities/authoring/notes.js\";\nimport {\n archSpecTemplate,\n capabilityDeltaTemplate,\n deltaTemplate,\n intentTemplate,\n openapiTemplate,\n specTemplate,\n} from \"./templates.js\";\n\ninterface NewOptions {\n title?: string;\n touches: string[];\n newService: string[];\n capability: string[];\n json?: boolean;\n}\n\nexport function registerNew(program: Command): void {\n program\n .command(\"new\")\n .argument(\"<featureId>\", \"feature id, e.g. FEAT-101\")\n .description(\"Scaffold a feature: intent, C4 delta, a requirement delta per service, a capability delta per promise\")\n .option(\"--title <text>\", \"human title; also becomes the directory slug\")\n // `--touches`, not `--service`: everywhere else `--service` selects the ONE\n // operating target (defaulting to config.service), while this is a repeatable\n // list of services the feature touches — a different arity and a different\n // meaning deserve a different name.\n .option(\"--touches <id>\", \"a service this feature touches (repeatable)\", collect, [])\n .option(\"--new-service <id>\", \"a service this feature introduces (repeatable)\", collect, [])\n // The INVERSION of the two flags above, and it composes with them rather\n // than excluding them. `--touches` asks which services change before the\n // business change has been written; `--capability` opens the document that\n // changes and lets the service work be derived from it. A feature that\n // does both — the analyst writes the promise, and one team already knows it\n // owns part of the mechanism — is an ordinary shape, and refusing the\n // combination would fight this axis's own archive gate: `capability.uncovered`\n // refuses a promise nothing in the same feature keeps, so the fix it names\n // is precisely a `--touches` service's `Realizes:` line living beside the\n // capability delta.\n //\n // Repeatable, like both flags above: a business change that moves two\n // promises is as real as a feature touching two services, and the flag that\n // is not repeatable is the one that sends an author to mkdir by hand.\n .option(\"--capability <id>\", \"a business capability this feature changes (repeatable)\", collect, [])\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (featureId: string, opts: NewOptions) => {\n const json = opts.json === true;\n\n // The grammar's verdict arrives as the brand: `featureDirName` demands\n // a FeatureId, so an argv string cannot reach the directory derivation\n // without passing through this parse — the producer the brand was\n // missing while `isFeatureId` narrowed to plain string.\n const parsedId = parseFeatureId(featureId, \"feature id\");\n if (!parsedId.ok) {\n return fail(json, \"invalid-option\", parsedId.problem);\n }\n const dirName = featureDirName(parsedId.id, opts.title);\n // The round-trip is checked beside the grammar, not inside it: the\n // grammar is a fact about the id, while `featureIdFromDirName` depends on\n // the TITLE this command is about to slug into the directory name. Only\n // `new` creates that directory, so only `new` owes that second half.\n if (featureIdFromDirName(dirName) !== featureId) {\n return fail(\n json,\n \"invalid-option\",\n `'${featureId}' does not survive the directory round-trip with this title.`,\n );\n }\n\n // Service ids are validated BEFORE the config is even loaded, and long\n // before anything is written: every one of them is interpolated into\n // `specs/<id>/` under the new feature directory, so `--touches ../../x`\n // was a writer pointed outside the docs repo. One grammar (core/kernel/ids/service.ts),\n // the same one adopt/init/vouch refuse on, so a service that is legal to\n // create is legal to name here and nowhere the two disagree.\n // The LIST, not each item: a loop narrows the element and leaves the\n // array unbranded, so what reached the writer below was `string[]` no\n // matter how thoroughly each id had been checked. --touches first, so the\n // id reported first is the one it was before.\n const touches = parseServiceIds(opts.touches, \"--touches\");\n if (!touches.ok) return fail(json, \"invalid-option\", touches.problem);\n const newServices = parseServiceIds(opts.newService, \"--new-service\");\n if (!newServices.ok) return fail(json, \"invalid-option\", newServices.problem);\n\n // Same reasoning as the two lists above, one tree over. A capability id\n // becomes `features/<dirName>/capabilities/<id>/` — a chain of\n // directories, one per `/`-separated segment — so `--capability\n // ../../evil` resolves to `features/evil/spec.md`, a directory\n // `listFeatures` then enumerates as a feature, and one `..` further\n // reaches the docs-repo root. `resolveInside` below cannot refuse either:\n // both are still inside the repo. Checked here for that reason, and\n // against the same directory-name grammar a service id passes\n // (core/kernel/ids/capability.ts).\n const capabilities = opts.capability;\n for (const id of capabilities) {\n const problem = capabilityIdProblem(id);\n if (problem !== null) return fail(json, \"invalid-option\", problem);\n }\n\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const config = loaded.config;\n const { docsDir } = config;\n // Before a single file is scaffolded: a docsDir that is not a docs repo is\n // refused, never written into. `features/<id>/**` lands happily in any\n // directory, so without this gate `new` reported `ok: true` over a\n // scaffold that no enumeration downstream will ever see — and a docsDir\n // that is simply absent escaped as `internal` (the enumeration below\n // throws) carrying the very sentence `list` and `show` report as\n // `docs-missing`. See docs-repo-gate.ts's docsRepoReady. `services`, not\n // `docs`: every id named by --touches/--new-service is a claim about\n // `services/<id>/`, and the near-miss note below is computed against that\n // directory, so a run without it is guessing.\n if (!docsRepoReady(json, docsDir, \"services\")) return;\n\n // No unlocked existence fast-path, deliberately: staging creates the\n // feature directory at plan time, so a HALF-scaffold from a killed run\n // resolves like a finished feature — and an unlocked refusal here made\n // \\`loam new <id>\\` answer already-exists over its own wreckage without\n // ever reaching the recovery that would complete it, while doctor's fix\n // printed exactly that re-run. Existence is asked once, under the lock,\n // after recovery has run.\n\n // A service named both ways is new — that is the more specific claim.\n const created = new Set(newServices.ids);\n const touched = touches.ids.filter((s) => !created.has(s));\n const dir = join(featuresDir(docsDir), dirName);\n\n const files: Record<string, string> = {\n \"intent.md\": intentTemplate(featureId, opts.title),\n \"delta.likec4\": deltaTemplate(featureId, touched, [...created]),\n };\n for (const svc of [...touched, ...created]) {\n files[join(\"specs\", svc, \"spec.md\")] = specTemplate(featureId, svc);\n }\n // The business axis, and the ONE file `--capability` adds. No service\n // spec rides with it, and that is the inversion rather than an omission:\n // the whole point of opening the document that changes first is that the\n // services realizing it are not known until the promise is written.\n // `--touches` is still how a service the author already knows about gets\n // its delta, which is why the two compose.\n //\n // Spelled relative, mirroring `featureCapabilityDeltasDir` +\n // `capabilityDocPathsAt` in core/repo/authored/paths.ts — the path builders take a\n // FeatureDir, whose provenance is an enumeration that read the directory,\n // and this directory is about to be created rather than read. One\n // directory per segment, exactly as the living tree spells nesting.\n for (const cap of capabilities) {\n files[join(\"capabilities\", ...cap.split(\"/\"), \"spec.md\")] = capabilityDeltaTemplate(featureId, cap);\n }\n for (const svc of created) {\n files[join(\"specs\", svc, \"openapi.yaml\")] = openapiTemplate(svc);\n // The architecture axis is scaffolded only for a service this feature\n // INTRODUCES, because that is the case where `c4.uncovered` will fire\n // the moment the delta is written: a brand-new tagged element nothing\n // covers. Handing an author a blank page for the outbox/retries/alerts\n // requirement is how that axis stays empty across a whole fleet.\n files[join(\"specs\", svc, \"arch.spec.md\")] = archSpecTemplate(featureId, svc);\n }\n\n // The COMPLETE plan in memory before a byte lands on disk: every path\n // resolved (belt and braces over the id grammar — resolveInside proves\n // containment at the moment of the write, symlink cases included), and\n // every write an exclusive create, because the feature must not exist.\n // The sequential writeFile loop this replaces could die mid-scaffold and\n // leave a partial feature the next run refused as already-exists.\n const writes: PlannedWrite[] = [];\n for (const [rel, content] of Object.entries(files)) {\n let path: string;\n try {\n path = resolveInside(docsDir, join(\"features\", dirName, rel), \"feature file\");\n } catch (err) {\n if (!(err instanceof UnsafePathError)) throw err;\n return fail(json, \"invalid-option\", err.message);\n }\n writes.push({ path, content, exclusive: true });\n }\n\n const committed = await commitScaffold(docsDir, featureId, writes);\n if (!committed.ok) {\n if (\"repoGone\" in committed) {\n reportDocsRepoError(json, committed.repoGone);\n return;\n }\n if (committed.code === \"already-exists\") {\n // After a recovery the refusal must SAY the repair happened: doctor\n // told the operator to re-run this exact command, and \"already\n // exists\" alone reads as the fix having failed.\n return fail(\n json,\n \"already-exists\",\n `Feature '${featureId}' already exists at ${repoPath(docsDir, committed.existing?.dir ?? dir)}.` +\n (committed.recovered === null ? \"\" : ` (${sayRecovered(committed.recovered)} The scaffold is complete.)`),\n );\n }\n return fail(json, committed.code, committed.message);\n }\n const recovered = committed.recovered;\n const written = writes.map((w) => repoPath(docsDir, w.path));\n\n // Both note families in ONE list, and the services first so an existing\n // `--touches` consumer reads the same first element it always did. They\n // are the same kind of statement — \"the thing you named is not there yet,\n // and here is what that means\" — so splitting them into two payload keys\n // would ask a consumer to learn a second shape for one idea.\n const notes = [\n ...(await unknownServiceNotes(docsDir, touched)),\n ...(await capabilityNotes(docsDir, { dirName, ids: capabilities })),\n ];\n\n if (json) {\n emitJson({\n command: \"new\",\n feature: featureId,\n path: repoPath(docsDir, dir),\n created: written,\n ...(recovered === null ? {} : { recovered }),\n // Not an error and not a finding: `--touches` on a service that does\n // not exist yet is legal (adopt it later, or say `--new-service`),\n // and `--capability` on a promise nobody has named is the ordinary\n // way a new business area starts. Both are reported because the\n // silent alternative is a delta that will never merge into anything,\n // or a near-miss spelling filed as a second capability.\n notes,\n });\n return;\n }\n console.log(`${featureId} scaffolded at ${repoPath(docsDir, dir)}`);\n for (const w of written) console.log(` + ${w}`);\n for (const note of notes) console.log(`\\n note: ${note}`);\n console.log(`\\nNext: fill in the delta, then \\`loam validate --feature ${featureId}\\`.`);\n console.log(\n \"If this feature changes no architecture, delete delta.likec4 — a requirements-only\\n\" +\n \"feature is complete without it, and an empty `model {}` validates clean too.\",\n );\n });\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return [...previous, value];\n}\n\n/* ------------------------------------------------------------------ */\n/* Hints */\n/* ------------------------------------------------------------------ */\n\n/**\n * `--touches <id>` naming neither a living `services/<id>/` nor a `--new-service`\n * is almost always a typo, and it is silent by construction: the scaffold writes\n * `specs/<id>/spec.md` happily, `loam validate` grades a delta against a living\n * spec that is not there, and the mistake surfaces at archive time as a service\n * appearing from nowhere. A note, not a refusal — naming a service that will be\n * adopted next week is legitimate — but the near-miss is spelled out, because\n * `order-api` vs `orders-api` is exactly the pair a person cannot see.\n */\nasync function unknownServiceNotes(docsDir: DocsDir, touched: string[]): Promise<string[]> {\n if (touched.length === 0) return [];\n let known: string[];\n try {\n known = (await listServices(docsDir)).map((s) => s.id);\n } catch (err) {\n // No docs repo to compare against is a different diagnosis entirely, and\n // `loam doctor` owns it. Saying nothing here beats inventing a typo hint\n // out of an enumeration that never ran.\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n return [];\n }\n const notes: string[] = [];\n for (const id of touched) {\n if (known.includes(id)) continue;\n const near = nearestIds(id, known);\n notes.push(\n `--touches '${id}' matches no services/${id}/ in the docs repo` +\n (near.length === 0 ? \"\" : ` — did you mean ${near.map((n) => `'${n}'`).join(\" or \")}?`) +\n ` If ${id} is introduced by this feature, pass --new-service ${id} instead.`,\n );\n }\n return notes;\n}\n\n/* ------------------------------------------------------------------ */\n/* Naming */\n/* ------------------------------------------------------------------ */\n\nfunction featureDirName(featureId: FeatureId, title: string | undefined): string {\n const slug = slugify(title ?? \"\");\n return slug ? `${featureId}-${slug}` : featureId;\n}\n\nfunction slugify(text: string): string {\n return text\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-+|-+$/g, \"\");\n}\n\n/** A LikeC4 identifier for a service name: `payment-split-service` -> `paymentSplitService`. */\n"]}