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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1256) hide show
  1. package/CHANGELOG.md +5992 -82
  2. package/COMPARISON.md +168 -63
  3. package/CONTRIBUTING.md +121 -0
  4. package/MIGRATING-from-OpenSpec.md +238 -55
  5. package/QUICKSTART.md +302 -0
  6. package/README.md +653 -144
  7. package/ROADMAP.md +1035 -0
  8. package/SCHEMA.md +3916 -263
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +927 -0
  11. package/dist/cli.js +133 -21
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +204 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +309 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +74 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/closing.js +42 -0
  20. package/dist/commands/archive/closing.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
  22. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  24. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  25. package/dist/commands/archive/plan/contracts/openapi.js +193 -0
  26. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  28. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  29. package/dist/commands/archive/plan/document/head.js +151 -0
  30. package/dist/commands/archive/plan/document/head.js.map +1 -0
  31. package/dist/commands/archive/plan/document/links.js +284 -0
  32. package/dist/commands/archive/plan/document/links.js.map +1 -0
  33. package/dist/commands/archive/plan/document/run.js +136 -0
  34. package/dist/commands/archive/plan/document/run.js.map +1 -0
  35. package/dist/commands/archive/plan/gate.js +319 -0
  36. package/dist/commands/archive/plan/gate.js.map +1 -0
  37. package/dist/commands/archive/plan/landscape.js +298 -0
  38. package/dist/commands/archive/plan/landscape.js.map +1 -0
  39. package/dist/commands/archive/plan/model/extending.js +85 -0
  40. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  41. package/dist/commands/archive/plan/refusal.js +106 -0
  42. package/dist/commands/archive/plan/refusal.js.map +1 -0
  43. package/dist/commands/archive/plan/specs.js +318 -0
  44. package/dist/commands/archive/plan/specs.js.map +1 -0
  45. package/dist/commands/archive/plan/state.js +30 -0
  46. package/dist/commands/archive/plan/state.js.map +1 -0
  47. package/dist/commands/archive/run.js +355 -0
  48. package/dist/commands/archive/run.js.map +1 -0
  49. package/dist/commands/archive/shipped.js +49 -0
  50. package/dist/commands/archive/shipped.js.map +1 -0
  51. package/dist/commands/context/context.js +166 -0
  52. package/dist/commands/context/context.js.map +1 -0
  53. package/dist/commands/context/print.js +305 -0
  54. package/dist/commands/context/print.js.map +1 -0
  55. package/dist/commands/delta/delta.js +367 -0
  56. package/dist/commands/delta/delta.js.map +1 -0
  57. package/dist/commands/delta/print.js +221 -0
  58. package/dist/commands/delta/print.js.map +1 -0
  59. package/dist/commands/dependencies.js +6 -8
  60. package/dist/commands/dependencies.js.map +1 -1
  61. package/dist/commands/diff/diff.js +86 -0
  62. package/dist/commands/diff/diff.js.map +1 -0
  63. package/dist/commands/diff/print.js +38 -0
  64. package/dist/commands/diff/print.js.map +1 -0
  65. package/dist/commands/doctor.js +65 -5
  66. package/dist/commands/doctor.js.map +1 -1
  67. package/dist/commands/explain/explain.js +227 -0
  68. package/dist/commands/explain/explain.js.map +1 -0
  69. package/dist/commands/explore.js +39 -28
  70. package/dist/commands/explore.js.map +1 -1
  71. package/dist/commands/gate/gate.js +152 -0
  72. package/dist/commands/gate/gate.js.map +1 -0
  73. package/dist/commands/gate/print.js +66 -0
  74. package/dist/commands/gate/print.js.map +1 -0
  75. package/dist/commands/gherkin/commit.js +105 -0
  76. package/dist/commands/gherkin/commit.js.map +1 -0
  77. package/dist/commands/gherkin/gherkin.js +262 -0
  78. package/dist/commands/gherkin/gherkin.js.map +1 -0
  79. package/dist/commands/gherkin/reconcile.js +146 -0
  80. package/dist/commands/gherkin/reconcile.js.map +1 -0
  81. package/dist/commands/gherkin/render.js +77 -0
  82. package/dist/commands/gherkin/render.js.map +1 -0
  83. package/dist/commands/init/example.js +204 -0
  84. package/dist/commands/init/example.js.map +1 -0
  85. package/dist/commands/init/first-hour.js +72 -0
  86. package/dist/commands/init/first-hour.js.map +1 -0
  87. package/dist/commands/{init.js → init/init.js} +142 -71
  88. package/dist/commands/init/init.js.map +1 -0
  89. package/dist/commands/init/mcp.js +131 -0
  90. package/dist/commands/init/mcp.js.map +1 -0
  91. package/dist/commands/init/options.js +78 -0
  92. package/dist/commands/init/options.js.map +1 -0
  93. package/dist/commands/instructions.js +72 -14
  94. package/dist/commands/instructions.js.map +1 -1
  95. package/dist/commands/list/campaign/campaign.js +63 -0
  96. package/dist/commands/list/campaign/campaign.js.map +1 -0
  97. package/dist/commands/list/campaign/owners.js +65 -0
  98. package/dist/commands/list/campaign/owners.js.map +1 -0
  99. package/dist/commands/list/json.js +155 -0
  100. package/dist/commands/list/json.js.map +1 -0
  101. package/dist/commands/list/list.js +358 -0
  102. package/dist/commands/list/list.js.map +1 -0
  103. package/dist/commands/list/print.js +344 -0
  104. package/dist/commands/list/print.js.map +1 -0
  105. package/dist/commands/list/review.js +120 -0
  106. package/dist/commands/list/review.js.map +1 -0
  107. package/dist/commands/list/suites/suites.js +140 -0
  108. package/dist/commands/list/suites/suites.js.map +1 -0
  109. package/dist/commands/list/views.js +108 -0
  110. package/dist/commands/list/views.js.map +1 -0
  111. package/dist/commands/mcp/dispatch.js +238 -0
  112. package/dist/commands/mcp/dispatch.js.map +1 -0
  113. package/dist/commands/mcp/mcp.js +75 -0
  114. package/dist/commands/mcp/mcp.js.map +1 -0
  115. package/dist/commands/mcp/serve.js +55 -0
  116. package/dist/commands/mcp/serve.js.map +1 -0
  117. package/dist/commands/migrate-openspec/materialize/active.js +175 -0
  118. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  119. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  120. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  121. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  122. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  123. package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
  124. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  125. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  126. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  127. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  128. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  129. package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
  130. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  131. package/dist/commands/migrate-openspec/openspec/error.js +18 -0
  132. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  133. package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
  134. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  135. package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
  136. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  137. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  138. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  139. package/dist/commands/migrate-openspec/print.js +89 -0
  140. package/dist/commands/migrate-openspec/print.js.map +1 -0
  141. package/dist/commands/new/capability-template.js +118 -0
  142. package/dist/commands/new/capability-template.js.map +1 -0
  143. package/dist/commands/new/commit.js +62 -0
  144. package/dist/commands/new/commit.js.map +1 -0
  145. package/dist/commands/new/modifies.js +206 -0
  146. package/dist/commands/new/modifies.js.map +1 -0
  147. package/dist/commands/new/new.js +328 -0
  148. package/dist/commands/new/new.js.map +1 -0
  149. package/dist/commands/new/templates.js +279 -0
  150. package/dist/commands/new/templates.js.map +1 -0
  151. package/dist/commands/open.js +199 -0
  152. package/dist/commands/open.js.map +1 -0
  153. package/dist/commands/policy/format.js +152 -0
  154. package/dist/commands/policy/format.js.map +1 -0
  155. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
  156. package/dist/commands/policy/gate.js.map +1 -0
  157. package/dist/commands/rebase/edit.js +106 -0
  158. package/dist/commands/rebase/edit.js.map +1 -0
  159. package/dist/commands/rebase/living.js +185 -0
  160. package/dist/commands/rebase/living.js.map +1 -0
  161. package/dist/commands/rebase/plan.js +245 -0
  162. package/dist/commands/rebase/plan.js.map +1 -0
  163. package/dist/commands/rebase/rebase.js +300 -0
  164. package/dist/commands/rebase/rebase.js.map +1 -0
  165. package/dist/commands/seed/commit.js +221 -0
  166. package/dist/commands/seed/commit.js.map +1 -0
  167. package/dist/commands/seed/plan.js +278 -0
  168. package/dist/commands/seed/plan.js.map +1 -0
  169. package/dist/commands/seed/seed.js +174 -0
  170. package/dist/commands/seed/seed.js.map +1 -0
  171. package/dist/commands/show/feature.js +182 -0
  172. package/dist/commands/show/feature.js.map +1 -0
  173. package/dist/commands/show/introduced.js +157 -0
  174. package/dist/commands/show/introduced.js.map +1 -0
  175. package/dist/commands/show/marks.js +53 -0
  176. package/dist/commands/show/marks.js.map +1 -0
  177. package/dist/commands/show/service.js +239 -0
  178. package/dist/commands/show/service.js.map +1 -0
  179. package/dist/commands/show/show.js +87 -0
  180. package/dist/commands/show/show.js.map +1 -0
  181. package/dist/commands/status/fleet-next.js +90 -0
  182. package/dist/commands/status/fleet-next.js.map +1 -0
  183. package/dist/commands/status/json.js +47 -0
  184. package/dist/commands/status/json.js.map +1 -0
  185. package/dist/commands/status/print.js +209 -0
  186. package/dist/commands/status/print.js.map +1 -0
  187. package/dist/commands/status/status.js +115 -0
  188. package/dist/commands/status/status.js.map +1 -0
  189. package/dist/commands/steps/steps.js +269 -0
  190. package/dist/commands/steps/steps.js.map +1 -0
  191. package/dist/commands/subsystem/edit.js +192 -0
  192. package/dist/commands/subsystem/edit.js.map +1 -0
  193. package/dist/commands/subsystem/move.js +325 -0
  194. package/dist/commands/subsystem/move.js.map +1 -0
  195. package/dist/commands/subsystem/query.js +113 -0
  196. package/dist/commands/subsystem/query.js.map +1 -0
  197. package/dist/commands/subsystem/subsystem.js +98 -0
  198. package/dist/commands/subsystem/subsystem.js.map +1 -0
  199. package/dist/commands/subsystem/sync.js +318 -0
  200. package/dist/commands/subsystem/sync.js.map +1 -0
  201. package/dist/commands/subsystem/txn/exclude.js +132 -0
  202. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  203. package/dist/commands/subsystem/txn/links.js +128 -0
  204. package/dist/commands/subsystem/txn/links.js.map +1 -0
  205. package/dist/commands/subsystem/txn/report.js +174 -0
  206. package/dist/commands/subsystem/txn/report.js.map +1 -0
  207. package/dist/commands/subsystem/txn/txn.js +196 -0
  208. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  209. package/dist/commands/subsystem/txn/views.js +249 -0
  210. package/dist/commands/subsystem/txn/views.js.map +1 -0
  211. package/dist/commands/tasks/actions.js +107 -0
  212. package/dist/commands/tasks/actions.js.map +1 -0
  213. package/dist/commands/tasks/render.js +253 -0
  214. package/dist/commands/tasks/render.js.map +1 -0
  215. package/dist/commands/tasks/tasks.js +119 -0
  216. package/dist/commands/tasks/tasks.js.map +1 -0
  217. package/dist/commands/unarchive/manifest.js +176 -0
  218. package/dist/commands/unarchive/manifest.js.map +1 -0
  219. package/dist/commands/unarchive/restore.js +254 -0
  220. package/dist/commands/unarchive/restore.js.map +1 -0
  221. package/dist/commands/unarchive/unarchive.js +59 -0
  222. package/dist/commands/unarchive/unarchive.js.map +1 -0
  223. package/dist/commands/validate/arch-coverage.js +245 -0
  224. package/dist/commands/validate/arch-coverage.js.map +1 -0
  225. package/dist/commands/validate/checks/fleet-shape.js +204 -0
  226. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  227. package/dist/commands/validate/checks/health-deps.js +58 -0
  228. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  229. package/dist/commands/validate/checks/introduced.js +102 -0
  230. package/dist/commands/validate/checks/introduced.js.map +1 -0
  231. package/dist/commands/validate/checks/requirements.js +264 -0
  232. package/dist/commands/validate/checks/requirements.js.map +1 -0
  233. package/dist/commands/validate/checks/sources.js +85 -0
  234. package/dist/commands/validate/checks/sources.js.map +1 -0
  235. package/dist/commands/validate/coverage/covers-after.js +105 -0
  236. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  237. package/dist/commands/validate/feature.js +222 -0
  238. package/dist/commands/validate/feature.js.map +1 -0
  239. package/dist/commands/validate/fleet/census.js +93 -0
  240. package/dist/commands/validate/fleet/census.js.map +1 -0
  241. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  242. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  243. package/dist/commands/validate/fleet/landscape.js +371 -0
  244. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  245. package/dist/commands/validate/fleet/load.js +118 -0
  246. package/dist/commands/validate/fleet/load.js.map +1 -0
  247. package/dist/commands/validate/fleet/map/attest.js +98 -0
  248. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  249. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  250. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  251. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  252. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  253. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  254. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  255. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  256. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  257. package/dist/commands/validate/fleet/obligations.js +266 -0
  258. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  259. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  260. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  261. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  262. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  263. package/dist/commands/validate/fleet/scorecard/print.js +71 -0
  264. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  265. package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
  266. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  267. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  268. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  269. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  270. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  271. package/dist/commands/validate/fleet/views/ids.js +75 -0
  272. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  273. package/dist/commands/validate/fleet/views/projects.js +278 -0
  274. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  275. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  276. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  277. package/dist/commands/validate/fleet/views/stale.js +52 -0
  278. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  279. package/dist/commands/validate/links/corpus.js +89 -0
  280. package/dist/commands/validate/links/corpus.js.map +1 -0
  281. package/dist/commands/validate/links/glossary.js +75 -0
  282. package/dist/commands/validate/links/glossary.js.map +1 -0
  283. package/dist/commands/validate/render/repeats.js +63 -0
  284. package/dist/commands/validate/render/repeats.js.map +1 -0
  285. package/dist/commands/validate/render/rollups.js +115 -0
  286. package/dist/commands/validate/render/rollups.js.map +1 -0
  287. package/dist/commands/validate/render/text.js +199 -0
  288. package/dist/commands/validate/render/text.js.map +1 -0
  289. package/dist/commands/validate/report.js +145 -0
  290. package/dist/commands/validate/report.js.map +1 -0
  291. package/dist/commands/validate/scope.js +113 -0
  292. package/dist/commands/validate/scope.js.map +1 -0
  293. package/dist/commands/validate/service/api.js +252 -0
  294. package/dist/commands/validate/service/api.js.map +1 -0
  295. package/dist/commands/validate/service/contracts/generated.js +134 -0
  296. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  297. package/dist/commands/validate/service/events/events.js +241 -0
  298. package/dist/commands/validate/service/events/events.js.map +1 -0
  299. package/dist/commands/validate/service/events/message-producers.js +77 -0
  300. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  301. package/dist/commands/validate/service/evidence-pins.js +177 -0
  302. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  303. package/dist/commands/validate/service/model/diverged.js +226 -0
  304. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  305. package/dist/commands/validate/service/model/grade.js +163 -0
  306. package/dist/commands/validate/service/model/grade.js.map +1 -0
  307. package/dist/commands/validate/service/service.js +310 -0
  308. package/dist/commands/validate/service/service.js.map +1 -0
  309. package/dist/commands/validate/service/specs.js +279 -0
  310. package/dist/commands/validate/service/specs.js.map +1 -0
  311. package/dist/commands/validate/service/spine.js +148 -0
  312. package/dist/commands/validate/service/spine.js.map +1 -0
  313. package/dist/commands/validate/service/usecases/tags.js +113 -0
  314. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  315. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  316. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  317. package/dist/commands/validate/validate.js +363 -0
  318. package/dist/commands/validate/validate.js.map +1 -0
  319. package/dist/commands/verify/cross/diff.js +178 -0
  320. package/dist/commands/verify/cross/diff.js.map +1 -0
  321. package/dist/commands/verify/evidence/contract.js +32 -0
  322. package/dist/commands/verify/evidence/contract.js.map +1 -0
  323. package/dist/commands/verify/evidence/pins.js +52 -0
  324. package/dist/commands/verify/evidence/pins.js.map +1 -0
  325. package/dist/commands/verify/evidence/read.js +81 -0
  326. package/dist/commands/verify/evidence/read.js.map +1 -0
  327. package/dist/commands/verify/frozen.js +263 -0
  328. package/dist/commands/verify/frozen.js.map +1 -0
  329. package/dist/commands/verify/record.js +278 -0
  330. package/dist/commands/verify/record.js.map +1 -0
  331. package/dist/commands/verify/report.js +206 -0
  332. package/dist/commands/verify/report.js.map +1 -0
  333. package/dist/commands/verify/results.js +328 -0
  334. package/dist/commands/verify/results.js.map +1 -0
  335. package/dist/commands/verify/verify.js +220 -0
  336. package/dist/commands/verify/verify.js.map +1 -0
  337. package/dist/commands/vouch/contract.js +11 -0
  338. package/dist/commands/vouch/contract.js.map +1 -0
  339. package/dist/commands/vouch/pack/contract.js +2 -0
  340. package/dist/commands/vouch/pack/contract.js.map +1 -0
  341. package/dist/commands/vouch/pack/pack.js +266 -0
  342. package/dist/commands/vouch/pack/pack.js.map +1 -0
  343. package/dist/commands/vouch/pack/print.js +266 -0
  344. package/dist/commands/vouch/pack/print.js.map +1 -0
  345. package/dist/commands/vouch/pack/sections.js +141 -0
  346. package/dist/commands/vouch/pack/sections.js.map +1 -0
  347. package/dist/commands/vouch/prompt/confirm.js +46 -0
  348. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  349. package/dist/commands/vouch/report.js +101 -0
  350. package/dist/commands/vouch/report.js.map +1 -0
  351. package/dist/commands/vouch/run.js +230 -0
  352. package/dist/commands/vouch/run.js.map +1 -0
  353. package/dist/commands/vouch/sample/plan.js +111 -0
  354. package/dist/commands/vouch/sample/plan.js.map +1 -0
  355. package/dist/commands/vouch/sample/print.js +109 -0
  356. package/dist/commands/vouch/sample/print.js.map +1 -0
  357. package/dist/commands/vouch/vet/verify.js +155 -0
  358. package/dist/commands/vouch/vet/verify.js.map +1 -0
  359. package/dist/commands/vouch/vouch.js +169 -0
  360. package/dist/commands/vouch/vouch.js.map +1 -0
  361. package/dist/core/agent/agents-md/command-map.js +299 -0
  362. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  363. package/dist/core/agent/agents-md/map/explain.js +46 -0
  364. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  365. package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
  366. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  367. package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
  368. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  369. package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
  370. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  371. package/dist/core/agent/agents-md/map/mcp.js +44 -0
  372. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  373. package/dist/core/agent/agents-md/map/status.js +78 -0
  374. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  375. package/dist/core/agent/agents-md/map/subsystem.js +104 -0
  376. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  377. package/dist/core/agent/agents-md/map/usecases.js +138 -0
  378. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  379. package/dist/core/agent/agents-md/refusals.js +273 -0
  380. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  381. package/dist/core/agent/agents-md.js +203 -0
  382. package/dist/core/agent/agents-md.js.map +1 -0
  383. package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
  384. package/dist/core/agent/agents-stamp.js.map +1 -0
  385. package/dist/core/agent/contract.js +2 -0
  386. package/dist/core/agent/contract.js.map +1 -0
  387. package/dist/core/agent/protocol.js +193 -0
  388. package/dist/core/agent/protocol.js.map +1 -0
  389. package/dist/core/agent/scaffold.js +254 -0
  390. package/dist/core/agent/scaffold.js.map +1 -0
  391. package/dist/core/agent/support/report.js +144 -0
  392. package/dist/core/agent/support/report.js.map +1 -0
  393. package/dist/core/agent/tools/dialects.js +151 -0
  394. package/dist/core/agent/tools/dialects.js.map +1 -0
  395. package/dist/core/agent/tools/registry.js +193 -0
  396. package/dist/core/agent/tools/registry.js.map +1 -0
  397. package/dist/core/agent/workflows/adopt.js +280 -0
  398. package/dist/core/agent/workflows/adopt.js.map +1 -0
  399. package/dist/core/agent/workflows/check.js +373 -0
  400. package/dist/core/agent/workflows/check.js.map +1 -0
  401. package/dist/core/agent/workflows/closing.js +323 -0
  402. package/dist/core/agent/workflows/closing.js.map +1 -0
  403. package/dist/core/agent/workflows/feature.js +220 -0
  404. package/dist/core/agent/workflows/feature.js.map +1 -0
  405. package/dist/core/agent/workflows/implement.js +188 -0
  406. package/dist/core/agent/workflows/implement.js.map +1 -0
  407. package/dist/core/agent/workflows/reference/authoring.js +311 -0
  408. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  409. package/dist/core/agent/workflows/reference/codes.js +67 -0
  410. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  411. package/dist/core/agent/workflows/reference/done-check.js +210 -0
  412. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  413. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  414. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  415. package/dist/core/agent/workflows/reference/reference.js +19 -0
  416. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  417. package/dist/core/agent/workflows/reference/spine.js +338 -0
  418. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  419. package/dist/core/asyncapi/baseline/plan.js +43 -0
  420. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  421. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  422. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  423. package/dist/core/asyncapi/depth.js +164 -0
  424. package/dist/core/asyncapi/depth.js.map +1 -0
  425. package/dist/core/asyncapi/digest.js +146 -0
  426. package/dist/core/asyncapi/digest.js.map +1 -0
  427. package/dist/core/asyncapi/merge/components.js +92 -0
  428. package/dist/core/asyncapi/merge/components.js.map +1 -0
  429. package/dist/core/asyncapi/merge/error.js +38 -0
  430. package/dist/core/asyncapi/merge/error.js.map +1 -0
  431. package/dist/core/asyncapi/merge/markers.js +290 -0
  432. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  433. package/dist/core/asyncapi/merge/merge.js +195 -0
  434. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  435. package/dist/core/asyncapi/merge/pin.js +83 -0
  436. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  437. package/dist/core/asyncapi/model.js +11 -0
  438. package/dist/core/asyncapi/model.js.map +1 -0
  439. package/dist/core/asyncapi/producers.js +50 -0
  440. package/dist/core/asyncapi/producers.js.map +1 -0
  441. package/dist/core/asyncapi/read.js +263 -0
  442. package/dist/core/asyncapi/read.js.map +1 -0
  443. package/dist/core/brief/brief.js +285 -0
  444. package/dist/core/brief/brief.js.map +1 -0
  445. package/dist/core/brief/checks.js +385 -0
  446. package/dist/core/brief/checks.js.map +1 -0
  447. package/dist/core/brief/landscape.js +273 -0
  448. package/dist/core/brief/landscape.js.map +1 -0
  449. package/dist/core/brief/map/extend.js +84 -0
  450. package/dist/core/brief/map/extend.js.map +1 -0
  451. package/dist/core/brief/map/owed.js +266 -0
  452. package/dist/core/brief/map/owed.js.map +1 -0
  453. package/dist/core/brief/targets.js +304 -0
  454. package/dist/core/brief/targets.js.map +1 -0
  455. package/dist/core/brief/unchecked.js +58 -0
  456. package/dist/core/brief/unchecked.js.map +1 -0
  457. package/dist/core/c4/arch.js +190 -0
  458. package/dist/core/c4/arch.js.map +1 -0
  459. package/dist/core/c4/direction/direction.js +114 -0
  460. package/dist/core/c4/direction/direction.js.map +1 -0
  461. package/dist/core/c4/likec4.js +243 -0
  462. package/dist/core/c4/likec4.js.map +1 -0
  463. package/dist/core/c4/locate/unlocated.js +150 -0
  464. package/dist/core/c4/locate/unlocated.js.map +1 -0
  465. package/dist/core/c4/parsed/deployment.js +160 -0
  466. package/dist/core/c4/parsed/deployment.js.map +1 -0
  467. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  468. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  469. package/dist/core/c4/parsed/specification.js +78 -0
  470. package/dist/core/c4/parsed/specification.js.map +1 -0
  471. package/dist/core/c4/parsed/values.js +110 -0
  472. package/dist/core/c4/parsed/values.js.map +1 -0
  473. package/dist/core/c4/parsed/view-ids.js +113 -0
  474. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  475. package/dist/core/c4/prefetch/fleet.js +134 -0
  476. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  477. package/dist/core/c4/project/architecture.js +161 -0
  478. package/dist/core/c4/project/architecture.js.map +1 -0
  479. package/dist/core/c4/project/batch.js +140 -0
  480. package/dist/core/c4/project/batch.js.map +1 -0
  481. package/dist/core/c4/project/documents.js +89 -0
  482. package/dist/core/c4/project/documents.js.map +1 -0
  483. package/dist/core/c4/project/load.js +219 -0
  484. package/dist/core/c4/project/load.js.map +1 -0
  485. package/dist/core/c4/project/staged.js +277 -0
  486. package/dist/core/c4/project/staged.js.map +1 -0
  487. package/dist/core/c4/resolve/attested.js +0 -0
  488. package/dist/core/c4/resolve/attested.js.map +1 -0
  489. package/dist/core/c4/resolve/external.js +51 -0
  490. package/dist/core/c4/resolve/external.js.map +1 -0
  491. package/dist/core/c4/resolve/service.js +174 -0
  492. package/dist/core/c4/resolve/service.js.map +1 -0
  493. package/dist/core/c4/resolve/steps.js +290 -0
  494. package/dist/core/c4/resolve/steps.js.map +1 -0
  495. package/dist/core/c4/resolve/systems.js +154 -0
  496. package/dist/core/c4/resolve/systems.js.map +1 -0
  497. package/dist/core/c4/root-project/exclude.js +352 -0
  498. package/dist/core/c4/root-project/exclude.js.map +1 -0
  499. package/dist/core/c4/seed/fleet-file.js +201 -0
  500. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  501. package/dist/core/c4/seed/items.js +91 -0
  502. package/dist/core/c4/seed/items.js.map +1 -0
  503. package/dist/core/c4/seed/stamp.js +48 -0
  504. package/dist/core/c4/seed/stamp.js.map +1 -0
  505. package/dist/core/c4/seed/template.js +173 -0
  506. package/dist/core/c4/seed/template.js.map +1 -0
  507. package/dist/core/c4/service-model/created/models.js +96 -0
  508. package/dist/core/c4/service-model/created/models.js.map +1 -0
  509. package/dist/core/c4/service-model/documents.js +47 -0
  510. package/dist/core/c4/service-model/documents.js.map +1 -0
  511. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  512. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  513. package/dist/core/c4/service-model/load.js +165 -0
  514. package/dist/core/c4/service-model/load.js.map +1 -0
  515. package/dist/core/c4/service-model/renderer.js +128 -0
  516. package/dist/core/c4/service-model/renderer.js.map +1 -0
  517. package/dist/core/c4/service-model/shape.js +106 -0
  518. package/dist/core/c4/service-model/shape.js.map +1 -0
  519. package/dist/core/c4/service-model/slice.js +188 -0
  520. package/dist/core/c4/service-model/slice.js.map +1 -0
  521. package/dist/core/c4/source-mask.js +369 -0
  522. package/dist/core/c4/source-mask.js.map +1 -0
  523. package/dist/core/c4/source-scan.js +308 -0
  524. package/dist/core/c4/source-scan.js.map +1 -0
  525. package/dist/core/c4/splice/authored-source.js +167 -0
  526. package/dist/core/c4/splice/authored-source.js.map +1 -0
  527. package/dist/core/c4/splice/contract.js +30 -0
  528. package/dist/core/c4/splice/contract.js.map +1 -0
  529. package/dist/core/c4/splice/delta-blocks.js +126 -0
  530. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  531. package/dist/core/c4/splice/identity/declared.js +87 -0
  532. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  533. package/dist/core/c4/splice/identity/edges.js +73 -0
  534. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  535. package/dist/core/c4/splice/identity/existing.js +80 -0
  536. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  537. package/dist/core/c4/splice/identity/interior.js +80 -0
  538. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  539. package/dist/core/c4/splice/identity/owner.js +50 -0
  540. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  541. package/dist/core/c4/splice/landscape-merge.js +337 -0
  542. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  543. package/dist/core/c4/splice/model/merge.js +151 -0
  544. package/dist/core/c4/splice/model/merge.js.map +1 -0
  545. package/dist/core/c4/splice/placement.js +298 -0
  546. package/dist/core/c4/splice/placement.js.map +1 -0
  547. package/dist/core/c4/splice/text/spot.js +131 -0
  548. package/dist/core/c4/splice/text/spot.js.map +1 -0
  549. package/dist/core/c4/workspace.js +166 -0
  550. package/dist/core/c4/workspace.js.map +1 -0
  551. package/dist/core/capabilities/authoring/notes.js +141 -0
  552. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  553. package/dist/core/capabilities/capabilities.js +124 -0
  554. package/dist/core/capabilities/capabilities.js.map +1 -0
  555. package/dist/core/capabilities/delta/doc.js +47 -0
  556. package/dist/core/capabilities/delta/doc.js.map +1 -0
  557. package/dist/core/capabilities/delta/overlay.js +129 -0
  558. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  559. package/dist/core/capabilities/delta/summary.js +57 -0
  560. package/dist/core/capabilities/delta/summary.js.map +1 -0
  561. package/dist/core/capabilities/delta/tree.js +43 -0
  562. package/dist/core/capabilities/delta/tree.js.map +1 -0
  563. package/dist/core/capabilities/delta/uncovered.js +222 -0
  564. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  565. package/dist/core/capabilities/findings.js +338 -0
  566. package/dist/core/capabilities/findings.js.map +1 -0
  567. package/dist/core/capabilities/realizes/findings.js +174 -0
  568. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  569. package/dist/core/capabilities/realizes/join.js +123 -0
  570. package/dist/core/capabilities/realizes/join.js.map +1 -0
  571. package/dist/core/capabilities/rollup.js +205 -0
  572. package/dist/core/capabilities/rollup.js.map +1 -0
  573. package/dist/core/capabilities/tree.js +104 -0
  574. package/dist/core/capabilities/tree.js.map +1 -0
  575. package/dist/core/capabilities/usecase-join.js +267 -0
  576. package/dist/core/capabilities/usecase-join.js.map +1 -0
  577. package/dist/core/coherence/authoring/scaffold.js +185 -0
  578. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  579. package/dist/core/coherence/authoring/sentinels.js +75 -0
  580. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  581. package/dist/core/coherence/calls/called.js +52 -0
  582. package/dist/core/coherence/calls/called.js.map +1 -0
  583. package/dist/core/coherence/coherence.js +332 -0
  584. package/dist/core/coherence/coherence.js.map +1 -0
  585. package/dist/core/coherence/consumed/operations.js +70 -0
  586. package/dist/core/coherence/consumed/operations.js.map +1 -0
  587. package/dist/core/coherence/consumed/refusal.js +38 -0
  588. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  589. package/dist/core/coherence/covers/health.js +85 -0
  590. package/dist/core/coherence/covers/health.js.map +1 -0
  591. package/dist/core/coherence/declared.js +295 -0
  592. package/dist/core/coherence/declared.js.map +1 -0
  593. package/dist/core/coherence/events/declared.js +191 -0
  594. package/dist/core/coherence/events/declared.js.map +1 -0
  595. package/dist/core/coherence/events/events.js +335 -0
  596. package/dist/core/coherence/events/events.js.map +1 -0
  597. package/dist/core/coherence/events/grades.js +189 -0
  598. package/dist/core/coherence/events/grades.js.map +1 -0
  599. package/dist/core/coherence/events/lookups.js +63 -0
  600. package/dist/core/coherence/events/lookups.js.map +1 -0
  601. package/dist/core/coherence/events/produced.js +100 -0
  602. package/dist/core/coherence/events/produced.js.map +1 -0
  603. package/dist/core/coherence/living.js +198 -0
  604. package/dist/core/coherence/living.js.map +1 -0
  605. package/dist/core/coherence/lookups.js +95 -0
  606. package/dist/core/coherence/lookups.js.map +1 -0
  607. package/dist/core/coherence/pending.js +39 -0
  608. package/dist/core/coherence/pending.js.map +1 -0
  609. package/dist/core/coherence/retired/archived.js +285 -0
  610. package/dist/core/coherence/retired/archived.js.map +1 -0
  611. package/dist/core/coherence/retired/event-pair.js +62 -0
  612. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  613. package/dist/core/coherence/retired/merged.js +79 -0
  614. package/dist/core/coherence/retired/merged.js.map +1 -0
  615. package/dist/core/coherence/retired/retirement.js +49 -0
  616. package/dist/core/coherence/retired/retirement.js.map +1 -0
  617. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  618. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  619. package/dist/core/coherence/retired/revival/revived.js +297 -0
  620. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  621. package/dist/core/conflict-markers.js +60 -0
  622. package/dist/core/conflict-markers.js.map +1 -0
  623. package/dist/core/consumers/after.js +113 -0
  624. package/dist/core/consumers/after.js.map +1 -0
  625. package/dist/core/consumers/consumers.js +296 -0
  626. package/dist/core/consumers/consumers.js.map +1 -0
  627. package/dist/core/consumers/current.js +211 -0
  628. package/dist/core/consumers/current.js.map +1 -0
  629. package/dist/core/consumers/scan.js +46 -0
  630. package/dist/core/consumers/scan.js.map +1 -0
  631. package/dist/core/consumers/state.js +27 -0
  632. package/dist/core/consumers/state.js.map +1 -0
  633. package/dist/core/delta/claims.js +73 -0
  634. package/dist/core/delta/claims.js.map +1 -0
  635. package/dist/core/delta/delta.js +341 -0
  636. package/dist/core/delta/delta.js.map +1 -0
  637. package/dist/core/delta/document.js +177 -0
  638. package/dist/core/delta/document.js.map +1 -0
  639. package/dist/core/delta/scope.js +48 -0
  640. package/dist/core/delta/scope.js.map +1 -0
  641. package/dist/core/delta/select.js +237 -0
  642. package/dist/core/delta/select.js.map +1 -0
  643. package/dist/core/dependencies/dependencies.js +141 -0
  644. package/dist/core/dependencies/dependencies.js.map +1 -0
  645. package/dist/core/dependencies/facts.js +165 -0
  646. package/dist/core/dependencies/facts.js.map +1 -0
  647. package/dist/core/dependencies/fanin.js +88 -0
  648. package/dist/core/dependencies/fanin.js.map +1 -0
  649. package/dist/core/dependencies/graph.js +106 -0
  650. package/dist/core/dependencies/graph.js.map +1 -0
  651. package/dist/core/deployment/delta.js +191 -0
  652. package/dist/core/deployment/delta.js.map +1 -0
  653. package/dist/core/deployment/objects.js +145 -0
  654. package/dist/core/deployment/objects.js.map +1 -0
  655. package/dist/core/diff/base-git.js +230 -0
  656. package/dist/core/diff/base-git.js.map +1 -0
  657. package/dist/core/diff/base-state.js +237 -0
  658. package/dist/core/diff/base-state.js.map +1 -0
  659. package/dist/core/diff/joins.js +136 -0
  660. package/dist/core/diff/joins.js.map +1 -0
  661. package/dist/core/diff/scope/changed-paths.js +204 -0
  662. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  663. package/dist/core/diff/scope/edges.js +82 -0
  664. package/dist/core/diff/scope/edges.js.map +1 -0
  665. package/dist/core/diff/semantic.js +312 -0
  666. package/dist/core/diff/semantic.js.map +1 -0
  667. package/dist/core/docs.js +37 -85
  668. package/dist/core/docs.js.map +1 -1
  669. package/dist/core/doctor/agents.js +238 -0
  670. package/dist/core/doctor/agents.js.map +1 -0
  671. package/dist/core/doctor/config.js +139 -0
  672. package/dist/core/doctor/config.js.map +1 -0
  673. package/dist/core/doctor/doctor.js +355 -0
  674. package/dist/core/doctor/doctor.js.map +1 -0
  675. package/dist/core/doctor/report.js +13 -0
  676. package/dist/core/doctor/report.js.map +1 -0
  677. package/dist/core/doctor/reports/scan.js +242 -0
  678. package/dist/core/doctor/reports/scan.js.map +1 -0
  679. package/dist/core/doctor/residue.js +110 -0
  680. package/dist/core/doctor/residue.js.map +1 -0
  681. package/dist/core/document/apply.js +224 -0
  682. package/dist/core/document/apply.js.map +1 -0
  683. package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
  684. package/dist/core/document/frontmatter.js.map +1 -0
  685. package/dist/core/document/grammar/directives.js +143 -0
  686. package/dist/core/document/grammar/directives.js.map +1 -0
  687. package/dist/core/document/parse.js +286 -0
  688. package/dist/core/document/parse.js.map +1 -0
  689. package/dist/core/document/scenarios.js +238 -0
  690. package/dist/core/document/scenarios.js.map +1 -0
  691. package/dist/core/document/spec.js +234 -0
  692. package/dist/core/document/spec.js.map +1 -0
  693. package/dist/core/{config.js → envelope/config.js} +89 -18
  694. package/dist/core/envelope/config.js.map +1 -0
  695. package/dist/core/envelope/json.js +209 -0
  696. package/dist/core/envelope/json.js.map +1 -0
  697. package/dist/core/{version.js → envelope/version.js} +3 -3
  698. package/dist/core/envelope/version.js.map +1 -0
  699. package/dist/core/explain/families.js +180 -0
  700. package/dist/core/explain/families.js.map +1 -0
  701. package/dist/core/explain/fix-tables.js +178 -0
  702. package/dist/core/explain/fix-tables.js.map +1 -0
  703. package/dist/core/explain/lookup.js +194 -0
  704. package/dist/core/explain/lookup.js.map +1 -0
  705. package/dist/core/explain/refusals.js +49 -0
  706. package/dist/core/explain/refusals.js.map +1 -0
  707. package/dist/core/explain/terms/documents.js +227 -0
  708. package/dist/core/explain/terms/documents.js.map +1 -0
  709. package/dist/core/explain/terms/done-check.js +144 -0
  710. package/dist/core/explain/terms/done-check.js.map +1 -0
  711. package/dist/core/explain/terms/entry.js +14 -0
  712. package/dist/core/explain/terms/entry.js.map +1 -0
  713. package/dist/core/explain/terms/stages.js +71 -0
  714. package/dist/core/explain/terms/stages.js.map +1 -0
  715. package/dist/core/explain/terms/tasks.js +97 -0
  716. package/dist/core/explain/terms/tasks.js.map +1 -0
  717. package/dist/core/explain/terms.js +103 -0
  718. package/dist/core/explain/terms.js.map +1 -0
  719. package/dist/core/explore/describe.js +105 -0
  720. package/dist/core/explore/describe.js.map +1 -0
  721. package/dist/core/explore/explore.js +204 -0
  722. package/dist/core/explore/explore.js.map +1 -0
  723. package/dist/core/fleet-context.js +174 -146
  724. package/dist/core/fleet-context.js.map +1 -1
  725. package/dist/core/gate/checks.js +208 -0
  726. package/dist/core/gate/checks.js.map +1 -0
  727. package/dist/core/gate/partners.js +246 -0
  728. package/dist/core/gate/partners.js.map +1 -0
  729. package/dist/core/gate/report.js +47 -0
  730. package/dist/core/gate/report.js.map +1 -0
  731. package/dist/core/gate/verification.js +176 -0
  732. package/dist/core/gate/verification.js.map +1 -0
  733. package/dist/core/gherkin/digest.js +60 -0
  734. package/dist/core/gherkin/digest.js.map +1 -0
  735. package/dist/core/gherkin/emit.js +177 -0
  736. package/dist/core/gherkin/emit.js.map +1 -0
  737. package/dist/core/gherkin/read.js +76 -0
  738. package/dist/core/gherkin/read.js.map +1 -0
  739. package/dist/core/gherkin/stale.js +210 -0
  740. package/dist/core/gherkin/stale.js.map +1 -0
  741. package/dist/core/gherkin/stamp.js +77 -0
  742. package/dist/core/gherkin/stamp.js.map +1 -0
  743. package/dist/core/gherkin/steps/catalogue.js +154 -0
  744. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  745. package/dist/core/gherkin/steps/inventory.js +98 -0
  746. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  747. package/dist/core/gherkin/steps/phrase.js +72 -0
  748. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  749. package/dist/core/glossary/delta.js +109 -0
  750. package/dist/core/glossary/delta.js.map +1 -0
  751. package/dist/core/glossary/tree.js +73 -0
  752. package/dist/core/glossary/tree.js.map +1 -0
  753. package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
  754. package/dist/core/kernel/concurrency.js.map +1 -0
  755. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  756. package/dist/core/kernel/document-bytes.js.map +1 -0
  757. package/dist/core/kernel/fences.js +42 -0
  758. package/dist/core/kernel/fences.js.map +1 -0
  759. package/dist/core/kernel/ids/capability.js +72 -0
  760. package/dist/core/kernel/ids/capability.js.map +1 -0
  761. package/dist/core/kernel/ids/dirs.js +33 -0
  762. package/dist/core/kernel/ids/dirs.js.map +1 -0
  763. package/dist/core/kernel/ids/feature.js +75 -0
  764. package/dist/core/kernel/ids/feature.js.map +1 -0
  765. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  766. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  767. package/dist/core/kernel/ids/service.js +156 -0
  768. package/dist/core/kernel/ids/service.js.map +1 -0
  769. package/dist/core/kernel/ids/subsystem.js +63 -0
  770. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  771. package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
  772. package/dist/core/kernel/path-safety.js.map +1 -0
  773. package/dist/core/{records.js → kernel/records.js} +11 -0
  774. package/dist/core/kernel/records.js.map +1 -0
  775. package/dist/core/links/backlinks.js +66 -0
  776. package/dist/core/links/backlinks.js.map +1 -0
  777. package/dist/core/links/case.js +74 -0
  778. package/dist/core/links/case.js.map +1 -0
  779. package/dist/core/links/corpus.js +118 -0
  780. package/dist/core/links/corpus.js.map +1 -0
  781. package/dist/core/links/findings.js +110 -0
  782. package/dist/core/links/findings.js.map +1 -0
  783. package/dist/core/links/parse.js +265 -0
  784. package/dist/core/links/parse.js.map +1 -0
  785. package/dist/core/mcp/argv.js +212 -0
  786. package/dist/core/mcp/argv.js.map +1 -0
  787. package/dist/core/mcp/author-tools.js +73 -0
  788. package/dist/core/mcp/author-tools.js.map +1 -0
  789. package/dist/core/mcp/framing.js +46 -0
  790. package/dist/core/mcp/framing.js.map +1 -0
  791. package/dist/core/mcp/protocol.js +280 -0
  792. package/dist/core/mcp/protocol.js.map +1 -0
  793. package/dist/core/mcp/tools.js +324 -0
  794. package/dist/core/mcp/tools.js.map +1 -0
  795. package/dist/core/obligations/obligations.js +106 -0
  796. package/dist/core/obligations/obligations.js.map +1 -0
  797. package/dist/core/openapi/baseline/gate.js +207 -0
  798. package/dist/core/openapi/baseline/gate.js.map +1 -0
  799. package/dist/core/openapi/baseline/plan.js +142 -0
  800. package/dist/core/openapi/baseline/plan.js.map +1 -0
  801. package/dist/core/openapi/baseline/record.js +174 -0
  802. package/dist/core/openapi/baseline/record.js.map +1 -0
  803. package/dist/core/openapi/contract-text.js +33 -0
  804. package/dist/core/openapi/contract-text.js.map +1 -0
  805. package/dist/core/openapi/contract-tree.js +301 -0
  806. package/dist/core/openapi/contract-tree.js.map +1 -0
  807. package/dist/core/openapi/depth.js +136 -0
  808. package/dist/core/openapi/depth.js.map +1 -0
  809. package/dist/core/openapi/digest.js +239 -0
  810. package/dist/core/openapi/digest.js.map +1 -0
  811. package/dist/core/{openapi.js → openapi/doc.js} +54 -108
  812. package/dist/core/openapi/doc.js.map +1 -0
  813. package/dist/core/openapi/merge/components.js +199 -0
  814. package/dist/core/openapi/merge/components.js.map +1 -0
  815. package/dist/core/openapi/merge/error.js +16 -0
  816. package/dist/core/openapi/merge/error.js.map +1 -0
  817. package/dist/core/openapi/merge/markers.js +204 -0
  818. package/dist/core/openapi/merge/markers.js.map +1 -0
  819. package/dist/core/openapi/merge/merge.js +232 -0
  820. package/dist/core/openapi/merge/merge.js.map +1 -0
  821. package/dist/core/openapi/merge/pin.js +110 -0
  822. package/dist/core/openapi/merge/pin.js.map +1 -0
  823. package/dist/core/openspec/decide/capabilities.js +244 -0
  824. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  825. package/dist/core/openspec/decide/dispositions.js +63 -0
  826. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  827. package/dist/core/openspec/decide/renames.js +179 -0
  828. package/dist/core/openspec/decide/renames.js.map +1 -0
  829. package/dist/core/openspec/decide/verdict.js +84 -0
  830. package/dist/core/openspec/decide/verdict.js.map +1 -0
  831. package/dist/core/openspec/inventory.js +220 -0
  832. package/dist/core/openspec/inventory.js.map +1 -0
  833. package/dist/core/openspec/model/mapping.js +78 -0
  834. package/dist/core/openspec/model/mapping.js.map +1 -0
  835. package/dist/core/openspec/model/model.js +70 -0
  836. package/dist/core/openspec/model/model.js.map +1 -0
  837. package/dist/core/openspec/scan/changes.js +241 -0
  838. package/dist/core/openspec/scan/changes.js.map +1 -0
  839. package/dist/core/openspec/scan/config.js +191 -0
  840. package/dist/core/openspec/scan/config.js.map +1 -0
  841. package/dist/core/openspec/scan/shape.js +304 -0
  842. package/dist/core/openspec/scan/shape.js.map +1 -0
  843. package/dist/core/openspec/scan/walk.js +116 -0
  844. package/dist/core/openspec/scan/walk.js.map +1 -0
  845. package/dist/core/openspec/scan/workspace.js +71 -0
  846. package/dist/core/openspec/scan/workspace.js.map +1 -0
  847. package/dist/core/owners/codeowners.js +141 -0
  848. package/dist/core/owners/codeowners.js.map +1 -0
  849. package/dist/core/pack/features.js +120 -0
  850. package/dist/core/pack/features.js.map +1 -0
  851. package/dist/core/pack/joins.js +112 -0
  852. package/dist/core/pack/joins.js.map +1 -0
  853. package/dist/core/pack/living.js +157 -0
  854. package/dist/core/pack/living.js.map +1 -0
  855. package/dist/core/pack/pack.js +120 -0
  856. package/dist/core/pack/pack.js.map +1 -0
  857. package/dist/core/permissions/permissions.js +87 -0
  858. package/dist/core/permissions/permissions.js.map +1 -0
  859. package/dist/core/projection/api.js +84 -0
  860. package/dist/core/projection/api.js.map +1 -0
  861. package/dist/core/projection/arch-slice.js +63 -0
  862. package/dist/core/projection/arch-slice.js.map +1 -0
  863. package/dist/core/projection/events.js +34 -0
  864. package/dist/core/projection/events.js.map +1 -0
  865. package/dist/core/projection/introduced.js +14 -0
  866. package/dist/core/projection/introduced.js.map +1 -0
  867. package/dist/core/provenance/findings.js +244 -0
  868. package/dist/core/provenance/findings.js.map +1 -0
  869. package/dist/core/provenance/git.js +201 -0
  870. package/dist/core/provenance/git.js.map +1 -0
  871. package/dist/core/provenance/gitq/moves.js +139 -0
  872. package/dist/core/provenance/gitq/moves.js.map +1 -0
  873. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  874. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  875. package/dist/core/provenance/sample/scope.js +238 -0
  876. package/dist/core/provenance/sample/scope.js.map +1 -0
  877. package/dist/core/provenance/sample/sections.js +61 -0
  878. package/dist/core/provenance/sample/sections.js.map +1 -0
  879. package/dist/core/provenance/sources.js +280 -0
  880. package/dist/core/provenance/sources.js.map +1 -0
  881. package/dist/core/provenance/stamp.js +220 -0
  882. package/dist/core/provenance/stamp.js.map +1 -0
  883. package/dist/core/provenance/walk.js +157 -0
  884. package/dist/core/provenance/walk.js.map +1 -0
  885. package/dist/core/repo/authored/paths.js +210 -0
  886. package/dist/core/repo/authored/paths.js.map +1 -0
  887. package/dist/core/repo/entries.js +126 -0
  888. package/dist/core/repo/entries.js.map +1 -0
  889. package/dist/core/repo/paths.js +322 -0
  890. package/dist/core/repo/paths.js.map +1 -0
  891. package/dist/core/repo/repo.js +308 -0
  892. package/dist/core/repo/repo.js.map +1 -0
  893. package/dist/core/repo/service-target.js +153 -0
  894. package/dist/core/repo/service-target.js.map +1 -0
  895. package/dist/core/repo/state.js +58 -0
  896. package/dist/core/repo/state.js.map +1 -0
  897. package/dist/core/repo/tree/find.js +61 -0
  898. package/dist/core/repo/tree/find.js.map +1 -0
  899. package/dist/core/repo/tree/fs.js +90 -0
  900. package/dist/core/repo/tree/fs.js.map +1 -0
  901. package/dist/core/repo/tree/marker.js +61 -0
  902. package/dist/core/repo/tree/marker.js.map +1 -0
  903. package/dist/core/repo/tree/render/body.js +258 -0
  904. package/dist/core/repo/tree/render/body.js.map +1 -0
  905. package/dist/core/repo/tree/render/projects.js +182 -0
  906. package/dist/core/repo/tree/render/projects.js.map +1 -0
  907. package/dist/core/repo/tree/render/service/header.js +125 -0
  908. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  909. package/dist/core/repo/tree/render/service/peers.js +28 -0
  910. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  911. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  912. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  913. package/dist/core/repo/tree/render/service/views.js +78 -0
  914. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  915. package/dist/core/repo/tree/render/stale.js +42 -0
  916. package/dist/core/repo/tree/render/stale.js.map +1 -0
  917. package/dist/core/repo/tree/render/text.js +84 -0
  918. package/dist/core/repo/tree/render/text.js.map +1 -0
  919. package/dist/core/repo/tree/render/views.js +293 -0
  920. package/dist/core/repo/tree/render/views.js.map +1 -0
  921. package/dist/core/repo/tree/walk.js +255 -0
  922. package/dist/core/repo/tree/walk.js.map +1 -0
  923. package/dist/core/results.js +146 -14
  924. package/dist/core/results.js.map +1 -1
  925. package/dist/core/scaffold/landscape.js +239 -0
  926. package/dist/core/scaffold/landscape.js.map +1 -0
  927. package/dist/core/scaffold/legacy.js +271 -0
  928. package/dist/core/scaffold/legacy.js.map +1 -0
  929. package/dist/core/scaffold/readme.js +84 -0
  930. package/dist/core/scaffold/readme.js.map +1 -0
  931. package/dist/core/staging/commit.js +252 -0
  932. package/dist/core/staging/commit.js.map +1 -0
  933. package/dist/core/staging/interrupted.js +96 -0
  934. package/dist/core/staging/interrupted.js.map +1 -0
  935. package/dist/core/staging/lock.js +268 -0
  936. package/dist/core/staging/lock.js.map +1 -0
  937. package/dist/core/staging/recovery/finding.js +35 -0
  938. package/dist/core/staging/recovery/finding.js.map +1 -0
  939. package/dist/core/staging/recovery/intent.js +95 -0
  940. package/dist/core/staging/recovery/intent.js.map +1 -0
  941. package/dist/core/staging/recovery/recover.js +204 -0
  942. package/dist/core/staging/recovery/recover.js.map +1 -0
  943. package/dist/core/staging/recovery/residue.js +62 -0
  944. package/dist/core/staging/recovery/residue.js.map +1 -0
  945. package/dist/core/staging/snapshot/manifest.js +188 -0
  946. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  947. package/dist/core/staging/snapshot/snapshot.js +196 -0
  948. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  949. package/dist/core/staging/txn/forward.js +181 -0
  950. package/dist/core/staging/txn/forward.js.map +1 -0
  951. package/dist/core/staging/txn/journal.js +139 -0
  952. package/dist/core/staging/txn/journal.js.map +1 -0
  953. package/dist/core/staging/txn/transaction.js +75 -0
  954. package/dist/core/staging/txn/transaction.js.map +1 -0
  955. package/dist/core/staging/writes.js +113 -0
  956. package/dist/core/staging/writes.js.map +1 -0
  957. package/dist/core/status/actions/execution.js +60 -0
  958. package/dist/core/status/actions/execution.js.map +1 -0
  959. package/dist/core/status/contracts.js +126 -0
  960. package/dist/core/status/contracts.js.map +1 -0
  961. package/dist/core/status/feature/artifacts.js +196 -0
  962. package/dist/core/status/feature/artifacts.js.map +1 -0
  963. package/dist/core/status/feature/feature.js +214 -0
  964. package/dist/core/status/feature/feature.js.map +1 -0
  965. package/dist/core/status/feature/next.js +163 -0
  966. package/dist/core/status/feature/next.js.map +1 -0
  967. package/dist/core/status/feature/state.js +21 -0
  968. package/dist/core/status/feature/state.js.map +1 -0
  969. package/dist/core/status/feature/words.js +96 -0
  970. package/dist/core/status/feature/words.js.map +1 -0
  971. package/dist/core/status/fleet/fleet.js +216 -0
  972. package/dist/core/status/fleet/fleet.js.map +1 -0
  973. package/dist/core/status/fleet/next.js +302 -0
  974. package/dist/core/status/fleet/next.js.map +1 -0
  975. package/dist/core/status/interrupted.js +97 -0
  976. package/dist/core/status/interrupted.js.map +1 -0
  977. package/dist/core/status/report.js +31 -0
  978. package/dist/core/status/report.js.map +1 -0
  979. package/dist/core/status/scan.js +41 -0
  980. package/dist/core/status/scan.js.map +1 -0
  981. package/dist/core/status/verification.js +216 -0
  982. package/dist/core/status/verification.js.map +1 -0
  983. package/dist/core/tasks/packet.js +199 -0
  984. package/dist/core/tasks/packet.js.map +1 -0
  985. package/dist/core/tasks/record.js +43 -0
  986. package/dist/core/tasks/record.js.map +1 -0
  987. package/dist/core/tasks/sources.js +181 -0
  988. package/dist/core/tasks/sources.js.map +1 -0
  989. package/dist/core/tasks/stamps.js +76 -0
  990. package/dist/core/tasks/stamps.js.map +1 -0
  991. package/dist/core/tasks/unit.js +0 -0
  992. package/dist/core/tasks/unit.js.map +1 -0
  993. package/dist/core/usecases/capability.js +166 -0
  994. package/dist/core/usecases/capability.js.map +1 -0
  995. package/dist/core/usecases/delta/claims.js +140 -0
  996. package/dist/core/usecases/delta/claims.js.map +1 -0
  997. package/dist/core/usecases/delta/flows.js +101 -0
  998. package/dist/core/usecases/delta/flows.js.map +1 -0
  999. package/dist/core/usecases/delta/modified.js +315 -0
  1000. package/dist/core/usecases/delta/modified.js.map +1 -0
  1001. package/dist/core/usecases/delta/overlay.js +76 -0
  1002. package/dist/core/usecases/delta/overlay.js.map +1 -0
  1003. package/dist/core/usecases/fleet.js +296 -0
  1004. package/dist/core/usecases/fleet.js.map +1 -0
  1005. package/dist/core/usecases/grade/capability-tag.js +93 -0
  1006. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  1007. package/dist/core/usecases/grade/feature.js +88 -0
  1008. package/dist/core/usecases/grade/feature.js.map +1 -0
  1009. package/dist/core/usecases/grade/requirement-tag.js +94 -0
  1010. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  1011. package/dist/core/usecases/grade/steps.js +266 -0
  1012. package/dist/core/usecases/grade/steps.js.map +1 -0
  1013. package/dist/core/usecases/grade/usecases.js +112 -0
  1014. package/dist/core/usecases/grade/usecases.js.map +1 -0
  1015. package/dist/core/usecases/operations.js +123 -0
  1016. package/dist/core/usecases/operations.js.map +1 -0
  1017. package/dist/core/usecases/place.js +44 -0
  1018. package/dist/core/usecases/place.js.map +1 -0
  1019. package/dist/core/usecases/service/exclude.js +119 -0
  1020. package/dist/core/usecases/service/exclude.js.map +1 -0
  1021. package/dist/core/usecases/service/flows.js +164 -0
  1022. package/dist/core/usecases/service/flows.js.map +1 -0
  1023. package/dist/core/usecases/suites/participants.js +83 -0
  1024. package/dist/core/usecases/suites/participants.js.map +1 -0
  1025. package/dist/core/usecases/suites/suites.js +45 -0
  1026. package/dist/core/usecases/suites/suites.js.map +1 -0
  1027. package/dist/core/usecases/touch.js +101 -0
  1028. package/dist/core/usecases/touch.js.map +1 -0
  1029. package/dist/core/verify/answers.js +180 -0
  1030. package/dist/core/verify/answers.js.map +1 -0
  1031. package/dist/core/verify/build.js +170 -0
  1032. package/dist/core/verify/build.js.map +1 -0
  1033. package/dist/core/verify/checklist.js +259 -0
  1034. package/dist/core/verify/checklist.js.map +1 -0
  1035. package/dist/core/verify/claims/identity.js +61 -0
  1036. package/dist/core/verify/claims/identity.js.map +1 -0
  1037. package/dist/core/verify/cross/diff.js +97 -0
  1038. package/dist/core/verify/cross/diff.js.map +1 -0
  1039. package/dist/core/verify/evidence/contract.js +169 -0
  1040. package/dist/core/verify/evidence/contract.js.map +1 -0
  1041. package/dist/core/verify/location.js +67 -0
  1042. package/dist/core/verify/location.js.map +1 -0
  1043. package/dist/core/verify/pins/lint.js +158 -0
  1044. package/dist/core/verify/pins/lint.js.map +1 -0
  1045. package/dist/core/verify/pins/pin.js +95 -0
  1046. package/dist/core/verify/pins/pin.js.map +1 -0
  1047. package/dist/core/verify/read/file.js +224 -0
  1048. package/dist/core/verify/read/file.js.map +1 -0
  1049. package/dist/core/verify/read/shape.js +169 -0
  1050. package/dist/core/verify/read/shape.js.map +1 -0
  1051. package/dist/core/verify/read/union.js +105 -0
  1052. package/dist/core/verify/read/union.js.map +1 -0
  1053. package/dist/core/verify/record.js +165 -0
  1054. package/dist/core/verify/record.js.map +1 -0
  1055. package/dist/core/verify/store/commit.js +99 -0
  1056. package/dist/core/verify/store/commit.js.map +1 -0
  1057. package/dist/core/verify/store/render.js +61 -0
  1058. package/dist/core/verify/store/render.js.map +1 -0
  1059. package/dist/core/vocabulary/health.js +91 -0
  1060. package/dist/core/vocabulary/health.js.map +1 -0
  1061. package/dist/core/vocabulary/issue.js +59 -0
  1062. package/dist/core/vocabulary/issue.js.map +1 -0
  1063. package/dist/core/vocabulary/maturity.js +216 -0
  1064. package/dist/core/vocabulary/maturity.js.map +1 -0
  1065. package/dist/core/vocabulary/report.js +90 -0
  1066. package/dist/core/vocabulary/report.js.map +1 -0
  1067. package/dist/core/vocabulary/steps.js +266 -0
  1068. package/dist/core/vocabulary/steps.js.map +1 -0
  1069. package/dist/core/workspace/discover.js +239 -0
  1070. package/dist/core/workspace/discover.js.map +1 -0
  1071. package/dist/core/workspace/render.js +52 -0
  1072. package/dist/core/workspace/render.js.map +1 -0
  1073. package/examples/README.md +232 -0
  1074. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  1075. package/examples/docs/architecture/capabilities.yaml +31 -0
  1076. package/examples/docs/architecture/landscape.likec4 +336 -0
  1077. package/examples/docs/architecture/obligations.yaml +23 -0
  1078. package/examples/docs/architecture/permissions.yaml +50 -0
  1079. package/examples/docs/architecture/services.likec4 +70 -0
  1080. package/examples/docs/architecture/subsystems.likec4 +18 -0
  1081. package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
  1082. package/examples/docs/capabilities/checkout/spec.md +55 -0
  1083. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  1084. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  1085. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  1086. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  1087. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  1088. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  1089. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
  1090. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  1091. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  1092. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  1093. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  1094. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  1095. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
  1096. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  1097. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  1098. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  1099. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  1100. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  1101. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  1102. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  1103. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  1104. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  1105. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  1106. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
  1107. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  1108. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  1109. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  1110. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  1111. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  1112. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  1113. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  1114. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  1115. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  1116. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  1117. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  1118. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  1119. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  1120. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  1121. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  1122. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  1123. package/examples/docs/glossary/order.md +15 -0
  1124. package/examples/docs/glossary/payments/authorization.md +14 -0
  1125. package/examples/docs/likec4.config.json +8 -0
  1126. package/examples/docs/loam.json +3 -0
  1127. package/examples/docs/services/checkout-web/model.likec4 +92 -0
  1128. package/examples/docs/services/checkout-web/spec.md +91 -0
  1129. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  1130. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  1131. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  1132. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  1133. package/examples/docs/services/order-service/arch.spec.md +134 -0
  1134. package/examples/docs/services/order-service/asyncapi.yaml +109 -0
  1135. package/examples/docs/services/order-service/health.yaml +57 -0
  1136. package/examples/docs/services/order-service/model.likec4 +126 -0
  1137. package/examples/docs/services/order-service/openapi.yaml +257 -0
  1138. package/examples/docs/services/order-service/runbook.md +62 -0
  1139. package/examples/docs/services/order-service/spec.md +134 -0
  1140. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  1141. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  1142. package/examples/docs/services/payment-service/arch.spec.md +76 -0
  1143. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  1144. package/examples/docs/services/payment-service/health.yaml +39 -0
  1145. package/examples/docs/services/payment-service/model.likec4 +68 -0
  1146. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  1147. package/examples/docs/services/payment-service/runbook.md +37 -0
  1148. package/examples/docs/services/payment-service/spec.md +88 -0
  1149. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  1150. package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
  1151. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  1152. package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
  1153. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  1154. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  1155. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  1156. package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
  1157. package/examples/docs/services/platform/notification-service/health.yaml +40 -0
  1158. package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
  1159. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  1160. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  1161. package/examples/docs/services/platform/subsystem.yaml +2 -0
  1162. package/examples/fleet.yaml +57 -0
  1163. package/package.json +19 -6
  1164. package/dist/commands/adopt.js +0 -240
  1165. package/dist/commands/adopt.js.map +0 -1
  1166. package/dist/commands/archive.js +0 -1313
  1167. package/dist/commands/archive.js.map +0 -1
  1168. package/dist/commands/delta.js +0 -388
  1169. package/dist/commands/delta.js.map +0 -1
  1170. package/dist/commands/docs-repo-gate.js.map +0 -1
  1171. package/dist/commands/format.js +0 -17
  1172. package/dist/commands/format.js.map +0 -1
  1173. package/dist/commands/gherkin.js +0 -309
  1174. package/dist/commands/gherkin.js.map +0 -1
  1175. package/dist/commands/init.js.map +0 -1
  1176. package/dist/commands/list.js +0 -295
  1177. package/dist/commands/list.js.map +0 -1
  1178. package/dist/commands/migrate-openspec.js +0 -950
  1179. package/dist/commands/migrate-openspec.js.map +0 -1
  1180. package/dist/commands/new.js +0 -413
  1181. package/dist/commands/new.js.map +0 -1
  1182. package/dist/commands/rebase.js +0 -356
  1183. package/dist/commands/rebase.js.map +0 -1
  1184. package/dist/commands/show.js +0 -320
  1185. package/dist/commands/show.js.map +0 -1
  1186. package/dist/commands/status.js +0 -262
  1187. package/dist/commands/status.js.map +0 -1
  1188. package/dist/commands/unarchive.js +0 -317
  1189. package/dist/commands/unarchive.js.map +0 -1
  1190. package/dist/commands/validate.js +0 -1773
  1191. package/dist/commands/validate.js.map +0 -1
  1192. package/dist/commands/verify.js +0 -775
  1193. package/dist/commands/verify.js.map +0 -1
  1194. package/dist/commands/vouch.js +0 -421
  1195. package/dist/commands/vouch.js.map +0 -1
  1196. package/dist/core/agent.js +0 -2173
  1197. package/dist/core/agent.js.map +0 -1
  1198. package/dist/core/agents-stamp.js.map +0 -1
  1199. package/dist/core/arch.js +0 -130
  1200. package/dist/core/arch.js.map +0 -1
  1201. package/dist/core/asyncapi.js +0 -253
  1202. package/dist/core/asyncapi.js.map +0 -1
  1203. package/dist/core/brief.js +0 -755
  1204. package/dist/core/brief.js.map +0 -1
  1205. package/dist/core/coherence.js +0 -577
  1206. package/dist/core/coherence.js.map +0 -1
  1207. package/dist/core/concurrency.js.map +0 -1
  1208. package/dist/core/config.js.map +0 -1
  1209. package/dist/core/delta.js +0 -476
  1210. package/dist/core/delta.js.map +0 -1
  1211. package/dist/core/dependencies.js +0 -356
  1212. package/dist/core/dependencies.js.map +0 -1
  1213. package/dist/core/doctor.js +0 -596
  1214. package/dist/core/doctor.js.map +0 -1
  1215. package/dist/core/document-bytes.js.map +0 -1
  1216. package/dist/core/explore.js +0 -225
  1217. package/dist/core/explore.js.map +0 -1
  1218. package/dist/core/frontmatter.js.map +0 -1
  1219. package/dist/core/gherkin.js +0 -463
  1220. package/dist/core/gherkin.js.map +0 -1
  1221. package/dist/core/health.js +0 -67
  1222. package/dist/core/health.js.map +0 -1
  1223. package/dist/core/ids.js +0 -122
  1224. package/dist/core/ids.js.map +0 -1
  1225. package/dist/core/issue.js +0 -9
  1226. package/dist/core/issue.js.map +0 -1
  1227. package/dist/core/json.js +0 -74
  1228. package/dist/core/json.js.map +0 -1
  1229. package/dist/core/likec4.js +0 -489
  1230. package/dist/core/likec4.js.map +0 -1
  1231. package/dist/core/maturity.js +0 -66
  1232. package/dist/core/maturity.js.map +0 -1
  1233. package/dist/core/openapi-merge.js +0 -552
  1234. package/dist/core/openapi-merge.js.map +0 -1
  1235. package/dist/core/openapi.js.map +0 -1
  1236. package/dist/core/openspec-inventory.js +0 -1440
  1237. package/dist/core/openspec-inventory.js.map +0 -1
  1238. package/dist/core/path-safety.js.map +0 -1
  1239. package/dist/core/provenance.js +0 -787
  1240. package/dist/core/provenance.js.map +0 -1
  1241. package/dist/core/records.js.map +0 -1
  1242. package/dist/core/repo.js +0 -438
  1243. package/dist/core/repo.js.map +0 -1
  1244. package/dist/core/report.js +0 -47
  1245. package/dist/core/report.js.map +0 -1
  1246. package/dist/core/spec.js +0 -505
  1247. package/dist/core/spec.js.map +0 -1
  1248. package/dist/core/staging.js +0 -890
  1249. package/dist/core/staging.js.map +0 -1
  1250. package/dist/core/status.js +0 -1132
  1251. package/dist/core/status.js.map +0 -1
  1252. package/dist/core/steps.js +0 -72
  1253. package/dist/core/steps.js.map +0 -1
  1254. package/dist/core/verify.js +0 -807
  1255. package/dist/core/verify.js.map +0 -1
  1256. package/dist/core/version.js.map +0 -1
@@ -0,0 +1,266 @@
1
+ /**
2
+ * What counts as a Gherkin step in a scenario body, and what counts as that
3
+ * step's ARGUMENT — the one rule `loam gherkin` emits by and `loam validate`
4
+ * grades by.
5
+ *
6
+ * It lives in a leaf of its own because both of those readers need it and they
7
+ * sit on opposite sides of an import: `spec.ts` parses the markdown a scenario
8
+ * is written in, `gherkin/emit.ts` renders that scenario into a `.feature` file and
9
+ * parses requirements back out of `spec.ts` to do it. With the detector inside
10
+ * `gherkin/emit.ts`, asking "does this scenario have any steps?" from the parser made
11
+ * the two modules import each other, and a module-evaluation cycle is decided by
12
+ * whichever entry point happens to be loaded first.
13
+ *
14
+ * Nothing here reads a file or knows what a requirement is: it is text in, shape
15
+ * out, so both sides can depend on it and neither has to depend on the other.
16
+ * `fenceTracker` comes from `core/kernel/`, the one package below everything, for
17
+ * the same reason — `core/document/` already depends on this file, so borrowing
18
+ * the fence rule from `core/document/parse.ts` would close a package cycle.
19
+ */
20
+ import { fenceTracker } from "../kernel/fences.js";
21
+ const STEP_KEYWORD_RE = /^(given|when|then|and|but)$/i;
22
+ /**
23
+ * Is this scenario body line a step? A step is a LIST BULLET (`-`, `*`, `+`)
24
+ * whose text opens with Given/When/Then/And/But — case-insensitive, so the
25
+ * OpenSpec `- **WHEN** ...` convention counts — where the keyword may be
26
+ * wrapped in `**bold**` and may carry a trailing colon. The keyword must stand
27
+ * alone before the step text (`- Givenx` is prose). Everything that is not a
28
+ * step stays scenario description: prose is never dropped, only steps are
29
+ * promoted.
30
+ */
31
+ export function stepFromLine(line) {
32
+ const bullet = /^\s*[-*+]\s+(.*)$/.exec(line);
33
+ if (!bullet)
34
+ return null;
35
+ const rest = bullet[1];
36
+ const bold = /^\*\*([^*]+?)\*\*\s*(.*)$/.exec(rest);
37
+ let lead;
38
+ let tail;
39
+ if (bold) {
40
+ lead = bold[1].trim();
41
+ tail = bold[2];
42
+ }
43
+ else {
44
+ const sp = /^(\S+)\s*(.*)$/.exec(rest);
45
+ if (!sp)
46
+ return null;
47
+ lead = sp[1];
48
+ tail = sp[2];
49
+ }
50
+ const kw = STEP_KEYWORD_RE.exec(lead.replace(/:$/, ""));
51
+ if (!kw)
52
+ return null;
53
+ const word = kw[1].toLowerCase();
54
+ return { keyword: word[0].toUpperCase() + word.slice(1), text: tail.trim() };
55
+ }
56
+ /**
57
+ * `| a | b |` -> `["a", "b"]`; null when the line is not a pipe row at all.
58
+ *
59
+ * The split honours markdown's `\|` escape, and that is not a nicety: a cell
60
+ * holding a literal pipe — a regex alternation, a Kafka key template, a shell
61
+ * snippet — otherwise splits into two, the row's width stops matching the
62
+ * header's, and the WHOLE table is reported unreadable. The failure lands on the
63
+ * one row that needed the escape and reads as if the author miscounted columns.
64
+ * `\\` unescapes too, so a cell can end in a backslash without eating the
65
+ * delimiter after it.
66
+ */
67
+ function cellsOf(line) {
68
+ const t = line.trim();
69
+ if (!/^\|.*\|$/.test(t))
70
+ return null;
71
+ const cells = [];
72
+ let cur = "";
73
+ for (let i = 1; i < t.length - 1; i += 1) {
74
+ const c = t[i];
75
+ if (c === "\\" && (t[i + 1] === "|" || t[i + 1] === "\\")) {
76
+ cur += t[i + 1];
77
+ i += 1;
78
+ continue;
79
+ }
80
+ if (c === "|") {
81
+ cells.push(cur.trim());
82
+ cur = "";
83
+ continue;
84
+ }
85
+ cur += c;
86
+ }
87
+ cells.push(cur.trim());
88
+ return cells;
89
+ }
90
+ /** `|---|:--:|` — the row markdown puts under a table header. */
91
+ function isSeparator(cells) {
92
+ return cells.length > 0 && cells.every((c) => /^:?-+:?$/.test(c));
93
+ }
94
+ /**
95
+ * The scenario body split into fenced blocks, markdown tables and plain lines,
96
+ * in source order.
97
+ *
98
+ * Fences are recognised FIRST and win outright, which is what stops a pipe row
99
+ * inside a JSON payload from being hoisted out of it. That ordering is not a
100
+ * nicety: before it existed, a scenario carrying a fenced payload that happened
101
+ * to contain a table emitted the payload as trimmed prose and the payload's own
102
+ * table as the scenario's `Examples`, turning one data pass into an outline
103
+ * parameterized by the contents of its own request body — and `loam validate`
104
+ * graded it green, because steps existed and no table was malformed.
105
+ */
106
+ function blocksOf(lines) {
107
+ const out = [];
108
+ const fenced = fenceTracker();
109
+ let open = null;
110
+ for (let i = 0; i < lines.length; i += 1) {
111
+ const line = lines[i];
112
+ const inFence = fenced(line);
113
+ const marker = /^(\s*)(```|~~~)(.*)$/.exec(line);
114
+ if (inFence && marker && open === null) {
115
+ const info = marker[3].trim();
116
+ open = { indent: marker[1].length, lines: [], ...(info.length > 0 ? { contentType: info } : {}) };
117
+ continue;
118
+ }
119
+ if (open !== null) {
120
+ // The tracker still reports the CLOSING marker as fenced content, so the
121
+ // marker line is what ends the block rather than the first unfenced line
122
+ // after it — reading it the other way swallows the line following the
123
+ // fence into the payload.
124
+ if (marker) {
125
+ out.push({ kind: "fence", ...open });
126
+ open = null;
127
+ continue;
128
+ }
129
+ open.lines.push(line);
130
+ continue;
131
+ }
132
+ const table = tableAt(lines, i);
133
+ if (table !== null) {
134
+ out.push({ kind: "table", indent: table.indent, rows: table.rows, lines: lines.slice(i, table.end + 1) });
135
+ i = table.end;
136
+ continue;
137
+ }
138
+ out.push({ kind: "line", text: line });
139
+ }
140
+ // An unterminated fence is the author's typo, not a reason to lose the text:
141
+ // its lines go back as plain lines and land in the description.
142
+ if (open !== null)
143
+ for (const l of open.lines)
144
+ out.push({ kind: "line", text: l });
145
+ return out;
146
+ }
147
+ /**
148
+ * The markdown table starting at `lines[i]`, or null when none does.
149
+ * `rows` is null when a table was clearly intended and its shape cannot be read.
150
+ */
151
+ function tableAt(lines, i) {
152
+ const header = cellsOf(lines[i] ?? "");
153
+ // An unnamed column cannot be referenced by a `<placeholder>`, so a header
154
+ // with an empty cell is not a header — it is prose that contains pipes.
155
+ if (header === null || header.length === 0 || header.some((c) => c.length === 0))
156
+ return null;
157
+ const sep = cellsOf(lines[i + 1] ?? "");
158
+ if (sep === null || !isSeparator(sep))
159
+ return null;
160
+ const indent = /^\s*/.exec(lines[i])[0].length;
161
+ if (sep.length !== header.length)
162
+ return { indent, end: i + 1, rows: null };
163
+ const rows = [];
164
+ let end = i + 1;
165
+ for (let j = i + 2; j < lines.length; j += 1) {
166
+ const row = cellsOf(lines[j]);
167
+ if (row === null)
168
+ break;
169
+ end = j;
170
+ if (row.length !== header.length)
171
+ return { indent, end, rows: null };
172
+ rows.push(row);
173
+ }
174
+ // A header and a separator with nothing under them is a table that carries
175
+ // zero cases — worse than no table, because it reads as coverage.
176
+ if (rows.length === 0)
177
+ return { indent, end, rows: null };
178
+ return { indent, end, rows: [header, ...rows] };
179
+ }
180
+ /**
181
+ * A scenario body split for rendering: bullet lines that read as steps become
182
+ * steps, a fenced block or an INDENTED table under a step becomes that step's
183
+ * argument, a table at the body's own left margin becomes the `Examples` of a
184
+ * `Scenario Outline`, and every other non-blank line is kept (edge-trimmed) as
185
+ * the scenario's description. Description renders BEFORE the steps whatever the
186
+ * source order — Gherkin's grammar ends a description at the first step keyword
187
+ * — so prose survives verbatim but interleaving does not.
188
+ *
189
+ * INDENTATION IS THE WHOLE DISAMBIGUATION, and it is one rule an author can
190
+ * hold in their head: a table written under a step, indented the way markdown
191
+ * already asks you to indent anything belonging to a list item, is that step's
192
+ * data table; a table at the margin is the scenario's case matrix. Before this
193
+ * rule existed there was only the second reading, so `Then the ledger holds:`
194
+ * followed by its expected rows silently became a two-case outline and the step
195
+ * reached the runner with no argument at all.
196
+ *
197
+ * The table matters more than it looks in both roles. A permission matrix, a
198
+ * validation matrix, a status-code table — the shape most of a service's
199
+ * decision layer actually has — is one parameterized test in the code it came
200
+ * from and one outline here. And an expected-state table is how a component
201
+ * test says what a row, a topic or an outbox must hold after one data pass;
202
+ * without it that assertion is prose, and prose asserts nothing.
203
+ *
204
+ * ONLY THE FIRST top-level table is `Examples`. Gherkin permits several
205
+ * `Examples` blocks per outline, and supporting them would make "which table is
206
+ * the outline's" a question with no answer in markdown; a second one keeps its
207
+ * prose exactly as it reads today.
208
+ */
209
+ export function scenarioGherkin(lines) {
210
+ const description = [];
211
+ const steps = [];
212
+ let examples = null;
213
+ let malformedExamples = false;
214
+ let strandedBlocks = false;
215
+ const keep = (raw) => {
216
+ for (const l of raw)
217
+ if (l.trim().length > 0)
218
+ description.push(l.trim());
219
+ };
220
+ for (const block of blocksOf(lines)) {
221
+ if (block.kind === "line") {
222
+ if (block.text.trim().length === 0)
223
+ continue;
224
+ const step = stepFromLine(block.text);
225
+ if (step)
226
+ steps.push({ text: step.text.length > 0 ? `${step.keyword} ${step.text}` : step.keyword });
227
+ else
228
+ description.push(block.text.trim());
229
+ continue;
230
+ }
231
+ const last = steps[steps.length - 1];
232
+ if (block.kind === "fence") {
233
+ if (last === undefined) {
234
+ strandedBlocks = true;
235
+ keep(block.lines);
236
+ continue;
237
+ }
238
+ last.docstring = {
239
+ ...(block.contentType === undefined ? {} : { contentType: block.contentType }),
240
+ lines: block.lines.map((l) => l.slice(0, block.indent).trim().length === 0 ? l.slice(block.indent) : l.trimStart()),
241
+ };
242
+ continue;
243
+ }
244
+ // A table at the margin answers to the scenario; an indented one answers to
245
+ // the step above it. Either can be unreadable, and an unreadable one keeps
246
+ // its prose rather than being guessed at.
247
+ if (block.indent === 0 && examples === null && !malformedExamples) {
248
+ if (block.rows === null) {
249
+ malformedExamples = true;
250
+ keep(block.lines);
251
+ }
252
+ else
253
+ examples = { header: block.rows[0], rows: block.rows.slice(1) };
254
+ continue;
255
+ }
256
+ if (block.indent > 0 && block.rows !== null && last !== undefined) {
257
+ last.table = block.rows;
258
+ continue;
259
+ }
260
+ if (block.indent > 0)
261
+ strandedBlocks = true;
262
+ keep(block.lines);
263
+ }
264
+ return { description, steps, examples, malformedExamples, strandedBlocks };
265
+ }
266
+ //# sourceMappingURL=steps.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steps.js","sourceRoot":"","sources":["../../../src/core/vocabulary/steps.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What counts as a Gherkin step in a scenario body, and what counts as that\n * step's ARGUMENT — the one rule `loam gherkin` emits by and `loam validate`\n * grades by.\n *\n * It lives in a leaf of its own because both of those readers need it and they\n * sit on opposite sides of an import: `spec.ts` parses the markdown a scenario\n * is written in, `gherkin/emit.ts` renders that scenario into a `.feature` file and\n * parses requirements back out of `spec.ts` to do it. With the detector inside\n * `gherkin/emit.ts`, asking \"does this scenario have any steps?\" from the parser made\n * the two modules import each other, and a module-evaluation cycle is decided by\n * whichever entry point happens to be loaded first.\n *\n * Nothing here reads a file or knows what a requirement is: it is text in, shape\n * out, so both sides can depend on it and neither has to depend on the other.\n * `fenceTracker` comes from `core/kernel/`, the one package below everything, for\n * the same reason — `core/document/` already depends on this file, so borrowing\n * the fence rule from `core/document/parse.ts` would close a package cycle.\n */\n\nimport { fenceTracker } from \"../kernel/fences.js\";\n\nconst STEP_KEYWORD_RE = /^(given|when|then|and|but)$/i;\n\nexport interface Step {\n /** Canonical Gherkin keyword: Given / When / Then / And / But. */\n keyword: string;\n /** The rest of the line, trimmed. May be empty. */\n text: string;\n}\n\n/**\n * Is this scenario body line a step? A step is a LIST BULLET (`-`, `*`, `+`)\n * whose text opens with Given/When/Then/And/But — case-insensitive, so the\n * OpenSpec `- **WHEN** ...` convention counts — where the keyword may be\n * wrapped in `**bold**` and may carry a trailing colon. The keyword must stand\n * alone before the step text (`- Givenx` is prose). Everything that is not a\n * step stays scenario description: prose is never dropped, only steps are\n * promoted.\n */\nexport function stepFromLine(line: string): Step | null {\n const bullet = /^\\s*[-*+]\\s+(.*)$/.exec(line);\n if (!bullet) return null;\n const rest = bullet[1]!;\n const bold = /^\\*\\*([^*]+?)\\*\\*\\s*(.*)$/.exec(rest);\n let lead: string;\n let tail: string;\n if (bold) {\n lead = bold[1]!.trim();\n tail = bold[2]!;\n } else {\n const sp = /^(\\S+)\\s*(.*)$/.exec(rest);\n if (!sp) return null;\n lead = sp[1]!;\n tail = sp[2]!;\n }\n const kw = STEP_KEYWORD_RE.exec(lead.replace(/:$/, \"\"));\n if (!kw) return null;\n const word = kw[1]!.toLowerCase();\n return { keyword: word[0]!.toUpperCase() + word.slice(1), text: tail.trim() };\n}\n\n/** A Gherkin `Examples` table: the column names, then one row of values per case. */\nexport interface Examples {\n header: string[];\n rows: string[][];\n}\n\n/**\n * A fenced block written under a step — Gherkin's docstring argument, and the\n * only way to put a request body, an expected JSON document or any other\n * multi-line literal into a scenario.\n *\n * `lines` are NOT trimmed beyond removing the fence's own indentation, and that\n * asymmetry with every other line in this module is the whole point: a payload\n * whose leading whitespace has been eaten is a payload no step definition can\n * compare against, and the loss is invisible because the file still parses.\n */\nexport interface DocString {\n /** The fence's info string (` ```json ` -> \"json\"), absent when it carried none. */\n contentType?: string;\n lines: string[];\n}\n\n/** One step as it will be emitted, with the argument written under it, if any. */\nexport interface EmittedStep {\n /** The rendered step line: keyword then text — `Given a payment of 100.00`. */\n text: string;\n docstring?: DocString;\n /**\n * An INDENTED markdown table written under this step, as Gherkin's data-table\n * argument: every row including the header, with the markdown separator row\n * dropped. Markdown needs the separator to render at all, Gherkin has no such\n * row, and the source stays legible in a pull request either way.\n */\n table?: string[][];\n}\n\nexport interface ScenarioGherkin {\n description: string[];\n steps: EmittedStep[];\n /** The cases a `Scenario Outline` runs, or null for a plain `Scenario`. */\n examples: Examples | null;\n /**\n * A top-level table was clearly intended as `Examples` and could not be read —\n * a row whose width disagrees with the header, or a header with no rows under\n * it.\n *\n * Reported rather than guessed at. The rule this whole module holds is that\n * prose is never dropped, so a table loam cannot read stays in the scenario\n * DESCRIPTION and the emission is still valid Gherkin — which is exactly why\n * silence would be wrong: the author wrote twenty cases, cucumber runs one\n * scenario, and both the file and the report look healthy.\n */\n malformedExamples: boolean;\n /**\n * A fenced block or an indented table was written where it cannot become a\n * step argument — before the scenario's first step, or (for a table) in a\n * shape this module cannot read. It stays in the description, so nothing is\n * lost from the DOCUMENT, and everything is lost from the TEST: the payload\n * reaches no step definition and the runner sees a step with no argument.\n *\n * A separate flag from `malformedExamples` because the fixes are different —\n * one is \"move it under a step\", the other is \"give the table equal columns\" —\n * and a machine must not have to guess which was meant.\n */\n strandedBlocks: boolean;\n}\n\n/**\n * `| a | b |` -> `[\"a\", \"b\"]`; null when the line is not a pipe row at all.\n *\n * The split honours markdown's `\\|` escape, and that is not a nicety: a cell\n * holding a literal pipe — a regex alternation, a Kafka key template, a shell\n * snippet — otherwise splits into two, the row's width stops matching the\n * header's, and the WHOLE table is reported unreadable. The failure lands on the\n * one row that needed the escape and reads as if the author miscounted columns.\n * `\\\\` unescapes too, so a cell can end in a backslash without eating the\n * delimiter after it.\n */\nfunction cellsOf(line: string): string[] | null {\n const t = line.trim();\n if (!/^\\|.*\\|$/.test(t)) return null;\n const cells: string[] = [];\n let cur = \"\";\n for (let i = 1; i < t.length - 1; i += 1) {\n const c = t[i]!;\n if (c === \"\\\\\" && (t[i + 1] === \"|\" || t[i + 1] === \"\\\\\")) {\n cur += t[i + 1]!;\n i += 1;\n continue;\n }\n if (c === \"|\") {\n cells.push(cur.trim());\n cur = \"\";\n continue;\n }\n cur += c;\n }\n cells.push(cur.trim());\n return cells;\n}\n\n/** `|---|:--:|` — the row markdown puts under a table header. */\nfunction isSeparator(cells: string[]): boolean {\n return cells.length > 0 && cells.every((c) => /^:?-+:?$/.test(c));\n}\n\n/** One run of source lines, already classified by {@link blocksOf}. */\ntype Block =\n | { kind: \"line\"; text: string }\n | { kind: \"fence\"; indent: number; contentType?: string; lines: string[] }\n | { kind: \"table\"; indent: number; rows: string[][] | null; lines: string[] };\n\n/**\n * The scenario body split into fenced blocks, markdown tables and plain lines,\n * in source order.\n *\n * Fences are recognised FIRST and win outright, which is what stops a pipe row\n * inside a JSON payload from being hoisted out of it. That ordering is not a\n * nicety: before it existed, a scenario carrying a fenced payload that happened\n * to contain a table emitted the payload as trimmed prose and the payload's own\n * table as the scenario's `Examples`, turning one data pass into an outline\n * parameterized by the contents of its own request body — and `loam validate`\n * graded it green, because steps existed and no table was malformed.\n */\nfunction blocksOf(lines: string[]): Block[] {\n const out: Block[] = [];\n const fenced = fenceTracker();\n let open: { indent: number; contentType?: string; lines: string[] } | null = null;\n for (let i = 0; i < lines.length; i += 1) {\n const line = lines[i]!;\n const inFence = fenced(line);\n const marker = /^(\\s*)(```|~~~)(.*)$/.exec(line);\n if (inFence && marker && open === null) {\n const info = marker[3]!.trim();\n open = { indent: marker[1]!.length, lines: [], ...(info.length > 0 ? { contentType: info } : {}) };\n continue;\n }\n if (open !== null) {\n // The tracker still reports the CLOSING marker as fenced content, so the\n // marker line is what ends the block rather than the first unfenced line\n // after it — reading it the other way swallows the line following the\n // fence into the payload.\n if (marker) {\n out.push({ kind: \"fence\", ...open });\n open = null;\n continue;\n }\n open.lines.push(line);\n continue;\n }\n const table = tableAt(lines, i);\n if (table !== null) {\n out.push({ kind: \"table\", indent: table.indent, rows: table.rows, lines: lines.slice(i, table.end + 1) });\n i = table.end;\n continue;\n }\n out.push({ kind: \"line\", text: line });\n }\n // An unterminated fence is the author's typo, not a reason to lose the text:\n // its lines go back as plain lines and land in the description.\n if (open !== null) for (const l of open.lines) out.push({ kind: \"line\", text: l });\n return out;\n}\n\n/**\n * The markdown table starting at `lines[i]`, or null when none does.\n * `rows` is null when a table was clearly intended and its shape cannot be read.\n */\nfunction tableAt(lines: string[], i: number): { indent: number; end: number; rows: string[][] | null } | null {\n const header = cellsOf(lines[i] ?? \"\");\n // An unnamed column cannot be referenced by a `<placeholder>`, so a header\n // with an empty cell is not a header — it is prose that contains pipes.\n if (header === null || header.length === 0 || header.some((c) => c.length === 0)) return null;\n const sep = cellsOf(lines[i + 1] ?? \"\");\n if (sep === null || !isSeparator(sep)) return null;\n const indent = /^\\s*/.exec(lines[i]!)![0]!.length;\n if (sep.length !== header.length) return { indent, end: i + 1, rows: null };\n const rows: string[][] = [];\n let end = i + 1;\n for (let j = i + 2; j < lines.length; j += 1) {\n const row = cellsOf(lines[j]!);\n if (row === null) break;\n end = j;\n if (row.length !== header.length) return { indent, end, rows: null };\n rows.push(row);\n }\n // A header and a separator with nothing under them is a table that carries\n // zero cases — worse than no table, because it reads as coverage.\n if (rows.length === 0) return { indent, end, rows: null };\n return { indent, end, rows: [header, ...rows] };\n}\n\n/**\n * A scenario body split for rendering: bullet lines that read as steps become\n * steps, a fenced block or an INDENTED table under a step becomes that step's\n * argument, a table at the body's own left margin becomes the `Examples` of a\n * `Scenario Outline`, and every other non-blank line is kept (edge-trimmed) as\n * the scenario's description. Description renders BEFORE the steps whatever the\n * source order — Gherkin's grammar ends a description at the first step keyword\n * — so prose survives verbatim but interleaving does not.\n *\n * INDENTATION IS THE WHOLE DISAMBIGUATION, and it is one rule an author can\n * hold in their head: a table written under a step, indented the way markdown\n * already asks you to indent anything belonging to a list item, is that step's\n * data table; a table at the margin is the scenario's case matrix. Before this\n * rule existed there was only the second reading, so `Then the ledger holds:`\n * followed by its expected rows silently became a two-case outline and the step\n * reached the runner with no argument at all.\n *\n * The table matters more than it looks in both roles. A permission matrix, a\n * validation matrix, a status-code table — the shape most of a service's\n * decision layer actually has — is one parameterized test in the code it came\n * from and one outline here. And an expected-state table is how a component\n * test says what a row, a topic or an outbox must hold after one data pass;\n * without it that assertion is prose, and prose asserts nothing.\n *\n * ONLY THE FIRST top-level table is `Examples`. Gherkin permits several\n * `Examples` blocks per outline, and supporting them would make \"which table is\n * the outline's\" a question with no answer in markdown; a second one keeps its\n * prose exactly as it reads today.\n */\nexport function scenarioGherkin(lines: string[]): ScenarioGherkin {\n const description: string[] = [];\n const steps: EmittedStep[] = [];\n let examples: Examples | null = null;\n let malformedExamples = false;\n let strandedBlocks = false;\n const keep = (raw: string[]): void => {\n for (const l of raw) if (l.trim().length > 0) description.push(l.trim());\n };\n for (const block of blocksOf(lines)) {\n if (block.kind === \"line\") {\n if (block.text.trim().length === 0) continue;\n const step = stepFromLine(block.text);\n if (step) steps.push({ text: step.text.length > 0 ? `${step.keyword} ${step.text}` : step.keyword });\n else description.push(block.text.trim());\n continue;\n }\n const last = steps[steps.length - 1];\n if (block.kind === \"fence\") {\n if (last === undefined) {\n strandedBlocks = true;\n keep(block.lines);\n continue;\n }\n last.docstring = {\n ...(block.contentType === undefined ? {} : { contentType: block.contentType }),\n lines: block.lines.map((l) => l.slice(0, block.indent).trim().length === 0 ? l.slice(block.indent) : l.trimStart()),\n };\n continue;\n }\n // A table at the margin answers to the scenario; an indented one answers to\n // the step above it. Either can be unreadable, and an unreadable one keeps\n // its prose rather than being guessed at.\n if (block.indent === 0 && examples === null && !malformedExamples) {\n if (block.rows === null) {\n malformedExamples = true;\n keep(block.lines);\n } else examples = { header: block.rows[0]!, rows: block.rows.slice(1) };\n continue;\n }\n if (block.indent > 0 && block.rows !== null && last !== undefined) {\n last.table = block.rows;\n continue;\n }\n if (block.indent > 0) strandedBlocks = true;\n keep(block.lines);\n }\n return { description, steps, examples, malformedExamples, strandedBlocks };\n}\n"]}
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Member discovery for `loam open` — pure computation, no printing.
3
+ *
4
+ * The hard problem this module solves is binding DIRECTION: each service
5
+ * repo's committed loam.json points AT the docs repo, and the docs repo knows
6
+ * nothing about who points at it. So membership is a join computed at run
7
+ * time — {candidate directory has a loam.json} ∧ {that config resolves its
8
+ * docsDir to this docs repo} — over a deliberately bounded search: a depth-1
9
+ * readdir of a handful of roots, never a disk walk. Same committed files plus
10
+ * same filesystem always produce the same member set, in the same order.
11
+ */
12
+ import { realpathSync, statSync } from "node:fs";
13
+ import { readFile, readdir } from "node:fs/promises";
14
+ import { basename, dirname, join } from "node:path";
15
+ import { CONFIG_FILENAME, parseConfig } from "../envelope/config.js";
16
+ import { inOrder } from "../kernel/concurrency.js";
17
+ import { DocsRepoUnavailableError } from "../repo/state.js";
18
+ /**
19
+ * One directory's identity for "is this the same checkout?" comparisons.
20
+ *
21
+ * Realpath first, because two spellings of one directory (a symlinked sibling,
22
+ * an 8.3 short name, a `..` route) must not become two workspace folders.
23
+ * Case-folded only on win32, because NTFS resolves names case-insensitively
24
+ * and `realpathSync` does not promise canonical case — without the fold,
25
+ * `C:\Repos` and `c:\repos` read as two checkouts of one service and convict
26
+ * an innocent tree of `binding-duplicate`. The fold is NOT applied elsewhere:
27
+ * on a case-sensitive filesystem two genuinely distinct directories may differ
28
+ * only by case, and folding there would silently merge them.
29
+ *
30
+ * `null` means the path names nothing on this machine — for a candidate's
31
+ * docsDir that is the answer "bound to a missing or foreign fleet", never an
32
+ * error.
33
+ */
34
+ function identityOf(dir) {
35
+ try {
36
+ const real = realpathSync(dir);
37
+ return process.platform === "win32" ? real.toLowerCase() : real;
38
+ }
39
+ catch {
40
+ // Unresolvable is a fact about the filesystem, not a failure of the scan.
41
+ return null;
42
+ }
43
+ }
44
+ /** Read and validate one candidate directory's committed binding. */
45
+ async function readBinding(dir) {
46
+ let raw;
47
+ try {
48
+ // The read stays inside the try that classifies it: a loam.json that is a
49
+ // directory, or one whose permissions refuse us, is "exists but cannot be
50
+ // believed", exactly as loadConfig treats the same failures.
51
+ raw = await readFile(join(dir, CONFIG_FILENAME), "utf8");
52
+ }
53
+ catch (err) {
54
+ const e = err;
55
+ // Not present reads as "not bound to anything" — most siblings of a docs
56
+ // repo are ordinary directories, and silence is the honest answer for them.
57
+ if (e.code === "ENOENT")
58
+ return { kind: "absent" };
59
+ return { kind: "unreadable", problem: err instanceof Error ? err.message : String(err) };
60
+ }
61
+ try {
62
+ // THE config validator — a second opinion here would let `loam open` count
63
+ // a checkout every other command refuses to load, or vice versa.
64
+ return { kind: "config", config: parseConfig(raw, dir) };
65
+ }
66
+ catch (err) {
67
+ return { kind: "unreadable", problem: err instanceof Error ? err.message : String(err) };
68
+ }
69
+ }
70
+ /**
71
+ * Depth-1 candidate directories under one scan root, sorted by name so the
72
+ * member set never depends on readdir order — or the reason the root could
73
+ * not be listed at all. The failure is DATA here, not a degrade: whether an
74
+ * unlistable root reads as empty (a default root a CI sandbox denies) or as a
75
+ * refusal (an explicit `--root` that owes an honest answer) is the caller's
76
+ * decision, and this function deciding it would hide the second case forever.
77
+ */
78
+ async function candidateDirs(root) {
79
+ let entries;
80
+ try {
81
+ entries = await readdir(root, { withFileTypes: true });
82
+ }
83
+ catch (err) {
84
+ return { kind: "unlistable", problem: err instanceof Error ? err.message : String(err) };
85
+ }
86
+ const dirs = [];
87
+ for (const entry of entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {
88
+ const candidate = join(root, entry.name);
89
+ if (entry.isDirectory()) {
90
+ dirs.push(candidate);
91
+ continue;
92
+ }
93
+ if (!entry.isSymbolicLink())
94
+ continue;
95
+ try {
96
+ // A symlinked sibling is a real checkout on its other end — developers
97
+ // link worktrees beside a docs repo — so it is classified by its target.
98
+ if (statSync(candidate).isDirectory())
99
+ dirs.push(candidate);
100
+ }
101
+ catch {
102
+ // A dangling link names nothing; there is no checkout to consider.
103
+ }
104
+ }
105
+ return { kind: "listed", dirs };
106
+ }
107
+ /**
108
+ * Derive the workspace member set from the committed bindings.
109
+ *
110
+ * The docs repo and the current repo are always members — their bindings are
111
+ * the committed facts `loadConfig` already validated. A scanned sibling is a
112
+ * member iff its loam.json parses and resolves its docsDir to this docs repo.
113
+ * Ordering is deterministic: docs repo, current repo, then scan members
114
+ * sorted by folder name and path.
115
+ *
116
+ * Throws `DocsRepoUnavailableError` when the docs repo's own identity cannot
117
+ * be established — it passed the readiness gate moments ago, so an
118
+ * unresolvable realpath here means it vanished mid-run. Failing closed is the
119
+ * doctrine: comparing candidates against a guessed identity would silently
120
+ * drop every member and answer `no-members` about a fleet nobody scanned.
121
+ */
122
+ export async function discoverMembers(req) {
123
+ const docsIdentity = identityOf(req.docsDir);
124
+ if (docsIdentity === null) {
125
+ throw new DocsRepoUnavailableError({ kind: "missing", path: req.docsDir }, `The configured docs repo does not exist: ${req.docsDir}. ` +
126
+ "Fix `docsDir` in loam.json, clone the docs repo there, " +
127
+ "or run `loam init --docs <dir> --create` to make a new one.");
128
+ }
129
+ const seen = new Set([docsIdentity]);
130
+ const docsMember = {
131
+ path: req.docsDir,
132
+ name: basename(req.docsDir),
133
+ service: null,
134
+ via: "docs-repo",
135
+ };
136
+ // Run from the docs repo itself, the current repo IS the docs repo: one
137
+ // member, and it answers as the docs repo — "docs-repo" is the stronger
138
+ // fact. The `?? spelling` fallback only feeds the dedupe key: an
139
+ // unresolvable configRoot still becomes a member, it just dedupes by its
140
+ // own spelling instead of a canonical one.
141
+ const currentIdentity = identityOf(req.configRoot) ?? req.configRoot;
142
+ const currentMember = seen.has(currentIdentity)
143
+ ? null
144
+ : {
145
+ path: req.configRoot,
146
+ name: req.service ?? basename(req.configRoot),
147
+ service: req.service ?? null,
148
+ via: "current-repo",
149
+ };
150
+ if (currentMember !== null)
151
+ seen.add(currentIdentity);
152
+ // Default roots: beside the docs repo and beside the current repo — the
153
+ // side-by-side layout SCHEMA.md's "../docs-repo" example already assumes.
154
+ // Usually one directory; identity-deduped so it is scanned once.
155
+ const scannedRoots = [];
156
+ const rootIds = new Set();
157
+ for (const root of req.roots ?? [dirname(req.docsDir), dirname(req.configRoot)]) {
158
+ const id = identityOf(root) ?? root;
159
+ if (rootIds.has(id))
160
+ continue;
161
+ rootIds.add(id);
162
+ scannedRoots.push(root);
163
+ }
164
+ const unreadableRoots = [];
165
+ const skipped = [];
166
+ const scanMembers = [];
167
+ // The ROOT loop is sequential on purpose: `seen` is a shared accumulator
168
+ // and "the earlier root wins" is the documented tie-break for a checkout
169
+ // reachable under two roots — scanning roots in parallel would make
170
+ // membership depend on I/O timing. The candidates WITHIN a root carry no
171
+ // such ordering, so their bindings are read through the shared pool;
172
+ // `inOrder` returns them in listing order, which keeps the verdicts below
173
+ // deterministic anyway.
174
+ for (const root of scannedRoots) {
175
+ const listing = await candidateDirs(root);
176
+ if (listing.kind === "unlistable") {
177
+ unreadableRoots.push({ root, problem: listing.problem });
178
+ continue;
179
+ }
180
+ const bindings = await inOrder(listing.dirs, async (dir) => ({
181
+ dir,
182
+ binding: await readBinding(dir),
183
+ }));
184
+ for (const { dir, binding } of bindings) {
185
+ // Identity first, before any verdict: a candidate that already IS a
186
+ // member (the docs repo itself, the current repo, a symlink twin from
187
+ // an earlier root) must not be re-reported — least of all as skipped,
188
+ // which would call one checkout both a member and unreadable.
189
+ const id = identityOf(dir) ?? dir;
190
+ if (seen.has(id))
191
+ continue;
192
+ if (binding.kind === "absent")
193
+ continue;
194
+ if (binding.kind === "unreadable") {
195
+ // Reported, never fatal — "a file loam cannot read is reported, never
196
+ // skipped" — but never a member either: an unreadable binding proves
197
+ // nothing about which fleet the checkout belongs to.
198
+ skipped.push({ path: join(dir, CONFIG_FILENAME), problem: binding.problem });
199
+ continue;
200
+ }
201
+ // The join itself: bound to THIS docs repo, or not a member. `null`
202
+ // (docsDir names nothing here) is a checkout of a missing or foreign
203
+ // fleet — silently out, exactly like one bound elsewhere.
204
+ if (identityOf(binding.config.docsDir) !== docsIdentity)
205
+ continue;
206
+ seen.add(id);
207
+ scanMembers.push({
208
+ path: dir,
209
+ name: binding.config.service ?? basename(dir),
210
+ service: binding.config.service ?? null,
211
+ via: "scan",
212
+ root,
213
+ });
214
+ }
215
+ }
216
+ scanMembers.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
217
+ // Two realpath-DISTINCT checkouts declaring one service id: loam cannot know
218
+ // which one speaks for the service, and a workspace is derived, not guessed.
219
+ // The current repo participates — a scanned twin of the repo you are
220
+ // standing in is the commonest way this happens (a second worktree).
221
+ const byService = new Map();
222
+ for (const member of [...(currentMember === null ? [] : [currentMember]), ...scanMembers]) {
223
+ if (member.service === null)
224
+ continue;
225
+ byService.set(member.service, [...(byService.get(member.service) ?? []), member.path]);
226
+ }
227
+ const duplicates = [...byService.entries()]
228
+ .filter(([, paths]) => paths.length > 1)
229
+ .map(([service, paths]) => ({ service, paths }))
230
+ .sort((a, b) => (a.service < b.service ? -1 : a.service > b.service ? 1 : 0));
231
+ return {
232
+ members: [docsMember, ...(currentMember === null ? [] : [currentMember]), ...scanMembers],
233
+ scannedRoots,
234
+ unreadableRoots,
235
+ skipped,
236
+ duplicates,
237
+ };
238
+ }
239
+ //# sourceMappingURL=discover.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discover.js","sourceRoot":"","sources":["../../../src/core/workspace/discover.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Member discovery for `loam open` — pure computation, no printing.\n *\n * The hard problem this module solves is binding DIRECTION: each service\n * repo's committed loam.json points AT the docs repo, and the docs repo knows\n * nothing about who points at it. So membership is a join computed at run\n * time — {candidate directory has a loam.json} ∧ {that config resolves its\n * docsDir to this docs repo} — over a deliberately bounded search: a depth-1\n * readdir of a handful of roots, never a disk walk. Same committed files plus\n * same filesystem always produce the same member set, in the same order.\n */\nimport { realpathSync, statSync } from \"node:fs\";\nimport { readFile, readdir } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { CONFIG_FILENAME, parseConfig, type LoamConfig } from \"../envelope/config.js\";\nimport { inOrder } from \"../kernel/concurrency.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport type { ServiceId } from \"../kernel/ids/service.js\";\nimport { DocsRepoUnavailableError } from \"../repo/state.js\";\n\ninterface MemberFacts {\n /** Absolute path of the member's repository root. */\n path: string;\n /** Folder display name: the member's service id when bound, else its basename. */\n name: string;\n service: ServiceId | null;\n}\n\n/**\n * One folder of the workspace being derived, with where it came from. A\n * variant, not an optional field: `root` exists exactly when the member was\n * found by the scan, and the union makes an always-member carrying a scan\n * root — or a scan member missing one — unrepresentable. One arm per `via`\n * value (not \"docs-repo\" | \"current-repo\" folded into one), because a\n * single-literal discriminant is what the checker's narrowing filters on.\n */\nexport type WorkspaceMember =\n | (MemberFacts & { via: \"docs-repo\" })\n | (MemberFacts & { via: \"current-repo\" })\n | (MemberFacts & { via: \"scan\"; root: string });\n\n/** Everything the scan learned, as data — the command decides what refuses. */\nexport interface Discovery {\n members: WorkspaceMember[];\n /** The roots actually scanned, deduped, in scan order. */\n scannedRoots: string[];\n /**\n * Roots whose depth-1 listing itself failed. Recorded, never swallowed:\n * \"nothing is wrong\" and \"I could not look\" are opposite facts, and only\n * the caller knows whether the root was a degradable default or an explicit\n * `--root` that owes a refusal.\n */\n unreadableRoots: { root: string; problem: string }[];\n /** Candidates whose loam.json exists but cannot be believed — reported, never members. */\n skipped: { path: string; problem: string }[];\n /** Service ids declared by two or more realpath-distinct member checkouts. */\n duplicates: { service: string; paths: string[] }[];\n}\n\nexport interface DiscoverRequest {\n /** Resolved docs repo root — the identity every candidate binding is compared against. */\n docsDir: DocsDir;\n /** Root of the repo whose loam.json governs this invocation (`config.root`). */\n configRoot: string;\n /** The service that repo declares, when it declares one. */\n service?: ServiceId;\n /** Explicit scan roots. When present they REPLACE the defaults — an explicit scan is exactly what was asked. */\n roots?: string[];\n}\n\n/**\n * One directory's identity for \"is this the same checkout?\" comparisons.\n *\n * Realpath first, because two spellings of one directory (a symlinked sibling,\n * an 8.3 short name, a `..` route) must not become two workspace folders.\n * Case-folded only on win32, because NTFS resolves names case-insensitively\n * and `realpathSync` does not promise canonical case — without the fold,\n * `C:\\Repos` and `c:\\repos` read as two checkouts of one service and convict\n * an innocent tree of `binding-duplicate`. The fold is NOT applied elsewhere:\n * on a case-sensitive filesystem two genuinely distinct directories may differ\n * only by case, and folding there would silently merge them.\n *\n * `null` means the path names nothing on this machine — for a candidate's\n * docsDir that is the answer \"bound to a missing or foreign fleet\", never an\n * error.\n */\nfunction identityOf(dir: string): string | null {\n try {\n const real = realpathSync(dir);\n return process.platform === \"win32\" ? real.toLowerCase() : real;\n } catch {\n // Unresolvable is a fact about the filesystem, not a failure of the scan.\n return null;\n }\n}\n\n/** A parsed candidate binding, or the reason it cannot be believed. */\ntype Candidate =\n | { kind: \"config\"; config: LoamConfig }\n | { kind: \"unreadable\"; problem: string }\n | { kind: \"absent\" };\n\n/** Read and validate one candidate directory's committed binding. */\nasync function readBinding(dir: string): Promise<Candidate> {\n let raw: string;\n try {\n // The read stays inside the try that classifies it: a loam.json that is a\n // directory, or one whose permissions refuse us, is \"exists but cannot be\n // believed\", exactly as loadConfig treats the same failures.\n raw = await readFile(join(dir, CONFIG_FILENAME), \"utf8\");\n } catch (err) {\n const e = err as NodeJS.ErrnoException;\n // Not present reads as \"not bound to anything\" — most siblings of a docs\n // repo are ordinary directories, and silence is the honest answer for them.\n if (e.code === \"ENOENT\") return { kind: \"absent\" };\n return { kind: \"unreadable\", problem: err instanceof Error ? err.message : String(err) };\n }\n try {\n // THE config validator — a second opinion here would let `loam open` count\n // a checkout every other command refuses to load, or vice versa.\n return { kind: \"config\", config: parseConfig(raw, dir) };\n } catch (err) {\n return { kind: \"unreadable\", problem: err instanceof Error ? err.message : String(err) };\n }\n}\n\n/**\n * Depth-1 candidate directories under one scan root, sorted by name so the\n * member set never depends on readdir order — or the reason the root could\n * not be listed at all. The failure is DATA here, not a degrade: whether an\n * unlistable root reads as empty (a default root a CI sandbox denies) or as a\n * refusal (an explicit `--root` that owes an honest answer) is the caller's\n * decision, and this function deciding it would hide the second case forever.\n */\nasync function candidateDirs(\n root: string,\n): Promise<{ kind: \"listed\"; dirs: string[] } | { kind: \"unlistable\"; problem: string }> {\n let entries;\n try {\n entries = await readdir(root, { withFileTypes: true });\n } catch (err) {\n return { kind: \"unlistable\", problem: err instanceof Error ? err.message : String(err) };\n }\n const dirs: string[] = [];\n for (const entry of entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))) {\n const candidate = join(root, entry.name);\n if (entry.isDirectory()) {\n dirs.push(candidate);\n continue;\n }\n if (!entry.isSymbolicLink()) continue;\n try {\n // A symlinked sibling is a real checkout on its other end — developers\n // link worktrees beside a docs repo — so it is classified by its target.\n if (statSync(candidate).isDirectory()) dirs.push(candidate);\n } catch {\n // A dangling link names nothing; there is no checkout to consider.\n }\n }\n return { kind: \"listed\", dirs };\n}\n\n/**\n * Derive the workspace member set from the committed bindings.\n *\n * The docs repo and the current repo are always members — their bindings are\n * the committed facts `loadConfig` already validated. A scanned sibling is a\n * member iff its loam.json parses and resolves its docsDir to this docs repo.\n * Ordering is deterministic: docs repo, current repo, then scan members\n * sorted by folder name and path.\n *\n * Throws `DocsRepoUnavailableError` when the docs repo's own identity cannot\n * be established — it passed the readiness gate moments ago, so an\n * unresolvable realpath here means it vanished mid-run. Failing closed is the\n * doctrine: comparing candidates against a guessed identity would silently\n * drop every member and answer `no-members` about a fleet nobody scanned.\n */\nexport async function discoverMembers(req: DiscoverRequest): Promise<Discovery> {\n const docsIdentity = identityOf(req.docsDir);\n if (docsIdentity === null) {\n throw new DocsRepoUnavailableError(\n { kind: \"missing\", path: req.docsDir },\n `The configured docs repo does not exist: ${req.docsDir}. ` +\n \"Fix `docsDir` in loam.json, clone the docs repo there, \" +\n \"or run `loam init --docs <dir> --create` to make a new one.\",\n );\n }\n const seen = new Set<string>([docsIdentity]);\n const docsMember: WorkspaceMember = {\n path: req.docsDir,\n name: basename(req.docsDir),\n service: null,\n via: \"docs-repo\",\n };\n\n // Run from the docs repo itself, the current repo IS the docs repo: one\n // member, and it answers as the docs repo — \"docs-repo\" is the stronger\n // fact. The `?? spelling` fallback only feeds the dedupe key: an\n // unresolvable configRoot still becomes a member, it just dedupes by its\n // own spelling instead of a canonical one.\n const currentIdentity = identityOf(req.configRoot) ?? req.configRoot;\n const currentMember: WorkspaceMember | null = seen.has(currentIdentity)\n ? null\n : {\n path: req.configRoot,\n name: req.service ?? basename(req.configRoot),\n service: req.service ?? null,\n via: \"current-repo\",\n };\n if (currentMember !== null) seen.add(currentIdentity);\n\n // Default roots: beside the docs repo and beside the current repo — the\n // side-by-side layout SCHEMA.md's \"../docs-repo\" example already assumes.\n // Usually one directory; identity-deduped so it is scanned once.\n const scannedRoots: string[] = [];\n const rootIds = new Set<string>();\n for (const root of req.roots ?? [dirname(req.docsDir), dirname(req.configRoot)]) {\n const id = identityOf(root) ?? root;\n if (rootIds.has(id)) continue;\n rootIds.add(id);\n scannedRoots.push(root);\n }\n\n const unreadableRoots: Discovery[\"unreadableRoots\"] = [];\n const skipped: Discovery[\"skipped\"] = [];\n const scanMembers: WorkspaceMember[] = [];\n // The ROOT loop is sequential on purpose: `seen` is a shared accumulator\n // and \"the earlier root wins\" is the documented tie-break for a checkout\n // reachable under two roots — scanning roots in parallel would make\n // membership depend on I/O timing. The candidates WITHIN a root carry no\n // such ordering, so their bindings are read through the shared pool;\n // `inOrder` returns them in listing order, which keeps the verdicts below\n // deterministic anyway.\n for (const root of scannedRoots) {\n const listing = await candidateDirs(root);\n if (listing.kind === \"unlistable\") {\n unreadableRoots.push({ root, problem: listing.problem });\n continue;\n }\n const bindings = await inOrder(listing.dirs, async (dir) => ({\n dir,\n binding: await readBinding(dir),\n }));\n for (const { dir, binding } of bindings) {\n // Identity first, before any verdict: a candidate that already IS a\n // member (the docs repo itself, the current repo, a symlink twin from\n // an earlier root) must not be re-reported — least of all as skipped,\n // which would call one checkout both a member and unreadable.\n const id = identityOf(dir) ?? dir;\n if (seen.has(id)) continue;\n if (binding.kind === \"absent\") continue;\n if (binding.kind === \"unreadable\") {\n // Reported, never fatal — \"a file loam cannot read is reported, never\n // skipped\" — but never a member either: an unreadable binding proves\n // nothing about which fleet the checkout belongs to.\n skipped.push({ path: join(dir, CONFIG_FILENAME), problem: binding.problem });\n continue;\n }\n // The join itself: bound to THIS docs repo, or not a member. `null`\n // (docsDir names nothing here) is a checkout of a missing or foreign\n // fleet — silently out, exactly like one bound elsewhere.\n if (identityOf(binding.config.docsDir) !== docsIdentity) continue;\n seen.add(id);\n scanMembers.push({\n path: dir,\n name: binding.config.service ?? basename(dir),\n service: binding.config.service ?? null,\n via: \"scan\",\n root,\n });\n }\n }\n scanMembers.sort((a, b) =>\n a.name < b.name ? -1 : a.name > b.name ? 1 : a.path < b.path ? -1 : a.path > b.path ? 1 : 0,\n );\n\n // Two realpath-DISTINCT checkouts declaring one service id: loam cannot know\n // which one speaks for the service, and a workspace is derived, not guessed.\n // The current repo participates — a scanned twin of the repo you are\n // standing in is the commonest way this happens (a second worktree).\n const byService = new Map<string, string[]>();\n for (const member of [...(currentMember === null ? [] : [currentMember]), ...scanMembers]) {\n if (member.service === null) continue;\n byService.set(member.service, [...(byService.get(member.service) ?? []), member.path]);\n }\n const duplicates = [...byService.entries()]\n .filter(([, paths]) => paths.length > 1)\n .map(([service, paths]) => ({ service, paths }))\n .sort((a, b) => (a.service < b.service ? -1 : a.service > b.service ? 1 : 0));\n\n return {\n members: [docsMember, ...(currentMember === null ? [] : [currentMember]), ...scanMembers],\n scannedRoots,\n unreadableRoots,\n skipped,\n duplicates,\n };\n}\n"]}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Deterministic `.code-workspace` rendering — pure computation, no printing.
3
+ *
4
+ * The output is a derived file: same members plus same target path must
5
+ * produce the same bytes on every machine, which is why every path is spelled
6
+ * with forward slashes (VS Code and Cursor accept them on Windows too, and
7
+ * they are the one spelling that diffs identically across checkouts) and why
8
+ * the JSON shape follows saveConfig's convention — 2-space indent, trailing
9
+ * newline.
10
+ */
11
+ import { dirname, isAbsolute, relative } from "node:path";
12
+ /**
13
+ * The `path` a folder entry gets, from the already-computed relative and the
14
+ * member's absolute path.
15
+ *
16
+ * Split out of `renderWorkspace` because the fallback decision is win32-only
17
+ * on a win32 host — `relative()` answers a cross-drive pair with the ABSOLUTE
18
+ * target, since no `..` chain crosses drives — and a POSIX test host can
19
+ * therefore never steer the platform `relative()` into producing one. Taking
20
+ * `rel` as data lets the suite exercise the branch with win32-shaped input.
21
+ *
22
+ * The drive-letter test backs up `isAbsolute` because that check is also
23
+ * platform-bound: on POSIX, `D:\other\svc` reads as a relative name. A POSIX
24
+ * directory literally named `D:` would match too and get the absolute
25
+ * spelling instead of the relative one — a stranger workspace file, but a
26
+ * correct one, and the pathological name is not worth a platform fork here.
27
+ */
28
+ export function workspacePathSpelling(rel, absolute) {
29
+ const spelling = rel === "" ? "." : isAbsolute(rel) || /^[A-Za-z]:[\\/]/.test(rel) ? absolute : rel;
30
+ return spelling.split(/[\\/]/).join("/");
31
+ }
32
+ /**
33
+ * Render the workspace document for `members`, targeted at `outPath`.
34
+ *
35
+ * Folder paths are relative to the file's own directory, so the committed
36
+ * side-by-side layout opens on every machine that checks it out; a member on
37
+ * another drive keeps its absolute path, because no relative spelling exists.
38
+ * The folders are returned still attached to their members so the command can
39
+ * echo the exact written spelling into its `--json` payload without joining
40
+ * two arrays by position.
41
+ */
42
+ export function renderWorkspace(members, outPath) {
43
+ const outDir = dirname(outPath);
44
+ const folders = members.map((member) => ({
45
+ member,
46
+ name: member.name,
47
+ path: workspacePathSpelling(relative(outDir, member.path), member.path),
48
+ }));
49
+ const text = JSON.stringify({ folders: folders.map(({ name, path }) => ({ name, path })) }, null, 2) + "\n";
50
+ return { text, folders };
51
+ }
52
+ //# sourceMappingURL=render.js.map