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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2570 -61
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2362 -245
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +82 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/agent/agents-stamp.js +155 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/asyncapi/read.js +239 -0
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +59 -55
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +132 -77
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -291
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -254
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1591
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -343
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2065
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js +0 -68
  970. package/dist/core/agents-stamp.js.map +0 -1
  971. package/dist/core/arch.js +0 -130
  972. package/dist/core/arch.js.map +0 -1
  973. package/dist/core/brief.js +0 -733
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -559
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -479
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -720
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -436
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -481
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1104
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -1,9 +1,17 @@
1
- import { PROTOCOLS, WORKFLOWS, protocolFor } from "../core/agent.js";
2
- import { emitJson, fail } from "../core/json.js";
3
- import { LOAM_VERSION } from "../core/version.js";
1
+ import { PROTOCOLS, REFERENCE_PAGES, SUPPORT_PAGES, WORKFLOWS, placeholderProblems, protocolFor, } from "../core/agent/protocol.js";
2
+ import { emitJson, fail } from "../core/envelope/json.js";
3
+ import { LOAM_VERSION } from "../core/envelope/version.js";
4
+ import { withoutFixTables } from "../core/explain/fix-tables.js";
4
5
  /**
5
- * The workflow protocols, from the binary rather than from a file somebody
6
- * generated once.
6
+ * The workflow protocols and the reference pages, from the binary rather than
7
+ * from a file somebody generated once.
8
+ *
9
+ * The pages are the newer half and the reason this command now has two lists.
10
+ * They are the sections that left the scaffolded AGENTS.md — a file every
11
+ * agents.md-aware host auto-loads on every session, which two hosts truncate
12
+ * silently — and they are printed here instead. That trade only works if they
13
+ * can be FOUND, so the bare menu names them; `core/agent/workflows/reference/
14
+ * reference.ts` carries the rest of the argument.
7
15
  *
8
16
  * This is the only command in loam that reads nothing: no `loam.json`, no docs
9
17
  * repo, no service. That is deliberate and it is the point — an agent runs this
@@ -16,10 +24,25 @@ import { LOAM_VERSION } from "../core/version.js";
16
24
  export function registerInstructions(program) {
17
25
  program
18
26
  .command("instructions")
19
- .argument("[workflow]", "workflow name (loam-adopt, loam-feature, …); omit to list them")
27
+ // Still spelled `workflow`, not `page`: the positional is in every
28
+ // generated command file loam has ever written (`loam instructions
29
+ // loam-adopt $1`) and in `--help` output people have copied. Renaming it
30
+ // buys a more accurate word in one usage line and costs nothing anywhere
31
+ // the rename would be visible, so the accuracy goes in the menu text instead.
32
+ .argument("[workflow]", "workflow or reference page (loam-adopt, loam-codes, …); omit to list them")
20
33
  .argument("[args...]", "values substituted for the protocol's $1, $2, … placeholders")
21
- .description("Print a workflow protocol, version-matched to this binary")
34
+ .description("Print a workflow protocol or reference page, version-matched to this binary")
22
35
  .option("--json", "emit the machine contract instead of the human view")
36
+ // Opt-in, and off by default, so the default page of every lifecycle protocol
37
+ // stays byte-identical: this narrows what an agent CAN ask for, it does not
38
+ // change what it gets when it asks for nothing. The one protocol this is
39
+ // about is /loam-check, whose fix tables are 83 KB of the 84 it prints —
40
+ // about a fifth of a 100k-token window spent before the first check has
41
+ // run — while `loam explain <code>` answers any one of those rows in under
42
+ // 500 bytes. The narrowed page keeps every paragraph that INTRODUCES a
43
+ // table, because that sentence is what says which scope a code was graded
44
+ // in; only the rows go.
45
+ .option("--no-fix-tables", "drop the per-code fix tables; `loam explain <code>` answers any code a run reports")
23
46
  // Every positional here is DATA — a feature id, a service id, a validate
24
47
  // target — and one of those targets is spelled `--all`. Without this,
25
48
  // commander reads a leading-dash argument as an option it does not have and
@@ -31,32 +54,77 @@ export function registerInstructions(program) {
31
54
  const json = opts.json === true;
32
55
  if (workflow === undefined) {
33
56
  if (json) {
34
- emitJson({ command: "instructions", version: LOAM_VERSION, workflows: WORKFLOWS });
57
+ // `support` and `references` are ADDITIVE beside the `workflows` key
58
+ // a consumer already reads. Appending either kind to `workflows`
59
+ // would have been the smaller diff and the wrong one: a caller
60
+ // iterating that array to drive the cycle would start running
61
+ // diagnostics or documentation as steps.
62
+ emitJson({
63
+ command: "instructions",
64
+ version: LOAM_VERSION,
65
+ workflows: WORKFLOWS,
66
+ support: SUPPORT_PAGES,
67
+ references: REFERENCE_PAGES,
68
+ });
35
69
  return;
36
70
  }
71
+ // One column width across all three lists, so the blocks line up as one
72
+ // menu — they are separate KINDS, not separate tables.
73
+ const width = Math.max(...[...WORKFLOWS, ...SUPPORT_PAGES, ...REFERENCE_PAGES].map((w) => w.name.length));
37
74
  console.log(`loam ${LOAM_VERSION} — workflows\n`);
38
- const width = Math.max(...WORKFLOWS.map((w) => w.name.length));
39
75
  for (const w of WORKFLOWS) {
40
76
  console.log(` ${w.name.padEnd(width)} ${w.description}`);
41
77
  }
42
- console.log(`\nloam instructions <workflow> [args...] prints one, placeholders filled in.`);
78
+ console.log(`\nsupport — use when a run or agent integration behaves unexpectedly\n`);
79
+ for (const s of SUPPORT_PAGES) {
80
+ console.log(` ${s.name.padEnd(width)} ${s.description}`);
81
+ }
82
+ // Under their own heading, and never merged into the six above. A page
83
+ // has no steps and is not part of the cycle; a flat list of ten would
84
+ // read as a ten-step process, which is the one thing the cycle must not
85
+ // be confused with. The sentence says what they are FOR, because a name
86
+ // alone does not distinguish "reference" from "seventh step".
87
+ console.log(`\nreference pages — printed whole, no arguments\n`);
88
+ for (const r of REFERENCE_PAGES) {
89
+ console.log(` ${r.name.padEnd(width)} ${r.description}`);
90
+ }
91
+ console.log(`\nloam instructions <workflow> [args...] prints one, placeholders filled in.` +
92
+ `\nloam instructions loam-report prints the local incident-reporting protocol.` +
93
+ `\nloam instructions <page> prints a reference page. The pages carry what AGENTS.md` +
94
+ `\nleaves out; \`loam explain <code>\` answers a single code without opening one.`);
95
+ return;
96
+ }
97
+ // Before the substitution, not after: a rendered protocol is a page of
98
+ // instructions an agent acts on, and a `$1` that cannot be a service id
99
+ // makes every command on that page unrunnable. The refusal reaches the
100
+ // caller in the same shape a mistyped workflow name does.
101
+ const problems = placeholderProblems(workflow, args);
102
+ if (problems !== null) {
103
+ fail(json, "invalid-option", `${problems.join(" ")} Nothing was printed: every command in the ${workflow} protocol ` +
104
+ "interpolates that value, so the page would name a target no loam command can accept.");
43
105
  return;
44
106
  }
45
107
  const body = protocolFor(workflow, args);
46
108
  if (body === null) {
47
109
  // `unknown-target`, the same code `show` uses for a name that resolves
48
110
  // to nothing. The known set is small and closed, so it is listed rather
49
- // than described: a caller that mistyped one of six names should not
50
- // have to run a second command to see them.
111
+ // than described: a caller that mistyped a known name should not have
112
+ // to run a second command to see the choices.
51
113
  fail(json, "unknown-target", `No workflow '${workflow}'. Known: ${Object.keys(PROTOCOLS).join(", ")}.`);
52
114
  return;
53
115
  }
116
+ // The narrowing composes with `--json` rather than forking the envelope:
117
+ // the shorter page rides in the same `body` field, so no key is added or
118
+ // renamed and a consumer that never passes the flag cannot tell the
119
+ // difference. `--json` is the larger of the two views (the whole table is
120
+ // one JSON string), which is exactly why it needs this too.
121
+ const page = opts.fixTables === false ? withoutFixTables(body) : body;
54
122
  if (json) {
55
123
  // `body` is the substituted text, not the template: a consumer that
56
124
  // asked for `loam instructions loam-adopt payment-service --json` wants
57
125
  // the protocol it is about to follow, and re-implementing the
58
126
  // substitution on the other side is a second copy of the rule.
59
- emitJson({ command: "instructions", version: LOAM_VERSION, workflow, args, body });
127
+ emitJson({ command: "instructions", version: LOAM_VERSION, workflow, args, body: page });
60
128
  return;
61
129
  }
62
130
  // `console.log`, like every other command, rather than a raw stdout
@@ -64,7 +132,7 @@ export function registerInstructions(program) {
64
132
  // invisible to it — an untestable print is how a protocol nobody notices
65
133
  // went missing would ship. The body already ends in a newline, so the
66
134
  // one console.log adds is trimmed rather than doubled.
67
- console.log(body.replace(/\n+$/, ""));
135
+ console.log(page.replace(/\n+$/, ""));
68
136
  });
69
137
  }
70
138
  //# sourceMappingURL=instructions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/commands/instructions.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMlD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,OAAO;SACJ,OAAO,CAAC,cAAc,CAAC;SACvB,QAAQ,CAAC,YAAY,EAAE,gEAAgE,CAAC;SACxF,QAAQ,CAAC,WAAW,EAAE,8DAA8D,CAAC;SACrF,WAAW,CAAC,2DAA2D,CAAC;SACxE,MAAM,CAAC,QAAQ,EAAE,qDAAqD,CAAC;QACxE,yEAAyE;QACzE,sEAAsE;QACtE,4EAA4E;QAC5E,2EAA2E;QAC3E,4EAA4E;QAC5E,6EAA6E;SAC5E,kBAAkB,EAAE;SACpB,MAAM,CAAC,CAAC,QAA4B,EAAE,IAAc,EAAE,IAAyB,EAAE,EAAE;QAClF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC;QAEhC,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,IAAI,IAAI,EAAE,CAAC;gBACT,QAAQ,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;gBACnF,OAAO;YACT,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,QAAQ,YAAY,gBAAgB,CAAC,CAAC;YAClD,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/D,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;gBAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,CAAC,GAAG,CAAC,8EAA8E,CAAC,CAAC;YAC5F,OAAO;QACT,CAAC;QAED,MAAM,IAAI,GAAG,WAAW,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QACzC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,uEAAuE;YACvE,wEAAwE;YACxE,qEAAqE;YACrE,4CAA4C;YAC5C,IAAI,CACF,IAAI,EACJ,gBAAgB,EAChB,gBAAgB,QAAQ,aAAa,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAC1E,CAAC;YACF,OAAO;QACT,CAAC;QAED,IAAI,IAAI,EAAE,CAAC;YACT,oEAAoE;YACpE,wEAAwE;YACxE,8DAA8D;YAC9D,+DAA+D;YAC/D,QAAQ,CAAC,EAAE,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;YACnF,OAAO;QACT,CAAC;QACD,oEAAoE;QACpE,qEAAqE;QACrE,yEAAyE;QACzE,sEAAsE;QACtE,uDAAuD;QACvD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACP,CAAC","sourcesContent":["import type { Command } from \"commander\";\nimport { PROTOCOLS, WORKFLOWS, protocolFor } from \"../core/agent.js\";\nimport { emitJson, fail } from \"../core/json.js\";\nimport { LOAM_VERSION } from \"../core/version.js\";\n\ninterface InstructionsOptions {\n json?: boolean;\n}\n\n/**\n * The workflow protocols, from the binary rather than from a file somebody\n * generated once.\n *\n * This is the only command in loam that reads nothing: no `loam.json`, no docs\n * repo, no service. That is deliberate and it is the point — an agent runs this\n * BEFORE the repository is wired, and a protocol that refused with `no-config`\n * would be unreachable exactly when it is most needed, which is the first\n * minute in an unfamiliar repository. `loam-adopt`'s own first step is to run\n * `loam init` when there is no config, and it cannot be the step that requires\n * one.\n */\nexport function registerInstructions(program: Command): void {\n program\n .command(\"instructions\")\n .argument(\"[workflow]\", \"workflow name (loam-adopt, loam-feature, …); omit to list them\")\n .argument(\"[args...]\", \"values substituted for the protocol's $1, $2, … placeholders\")\n .description(\"Print a workflow protocol, version-matched to this binary\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n // Every positional here is DATA — a feature id, a service id, a validate\n // target — and one of those targets is spelled `--all`. Without this,\n // commander reads a leading-dash argument as an option it does not have and\n // refuses the whole invocation, so `/loam-check --all` (the first form the\n // command file's own argument hint offers) got a usage error instead of the\n // protocol. `--json` still parses as the flag it is, because it is declared.\n .allowUnknownOption()\n .action((workflow: string | undefined, args: string[], opts: InstructionsOptions) => {\n const json = opts.json === true;\n\n if (workflow === undefined) {\n if (json) {\n emitJson({ command: \"instructions\", version: LOAM_VERSION, workflows: WORKFLOWS });\n return;\n }\n console.log(`loam ${LOAM_VERSION} — workflows\\n`);\n const width = Math.max(...WORKFLOWS.map((w) => w.name.length));\n for (const w of WORKFLOWS) {\n console.log(` ${w.name.padEnd(width)} ${w.description}`);\n }\n console.log(`\\nloam instructions <workflow> [args...] prints one, placeholders filled in.`);\n return;\n }\n\n const body = protocolFor(workflow, args);\n if (body === null) {\n // `unknown-target`, the same code `show` uses for a name that resolves\n // to nothing. The known set is small and closed, so it is listed rather\n // than described: a caller that mistyped one of six names should not\n // have to run a second command to see them.\n fail(\n json,\n \"unknown-target\",\n `No workflow '${workflow}'. Known: ${Object.keys(PROTOCOLS).join(\", \")}.`,\n );\n return;\n }\n\n if (json) {\n // `body` is the substituted text, not the template: a consumer that\n // asked for `loam instructions loam-adopt payment-service --json` wants\n // the protocol it is about to follow, and re-implementing the\n // substitution on the other side is a second copy of the rule.\n emitJson({ command: \"instructions\", version: LOAM_VERSION, workflow, args, body });\n return;\n }\n // `console.log`, like every other command, rather than a raw stdout\n // write: the test harness captures the console and a direct write is\n // invisible to it — an untestable print is how a protocol nobody notices\n // went missing would ship. The body already ends in a newline, so the\n // one console.log adds is trimmed rather than doubled.\n console.log(body.replace(/\\n+$/, \"\"));\n });\n}\n"]}
1
+ {"version":3,"file":"instructions.js","sourceRoot":"","sources":["../../src/commands/instructions.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Command } from \"commander\";\nimport {\n PROTOCOLS,\n REFERENCE_PAGES,\n SUPPORT_PAGES,\n WORKFLOWS,\n placeholderProblems,\n protocolFor,\n} from \"../core/agent/protocol.js\";\nimport { emitJson, fail } from \"../core/envelope/json.js\";\nimport { LOAM_VERSION } from \"../core/envelope/version.js\";\nimport { withoutFixTables } from \"../core/explain/fix-tables.js\";\n\ninterface InstructionsOptions {\n json?: boolean;\n /**\n * Commander's negated-boolean shape: absent means `true`, and only\n * `--no-fix-tables` on the command line makes it `false`. Read as\n * `=== false` at the call site so an undefined — a caller constructing the\n * options object itself, in a test — keeps the default page.\n */\n fixTables?: boolean;\n}\n\n/**\n * The workflow protocols and the reference pages, from the binary rather than\n * from a file somebody generated once.\n *\n * The pages are the newer half and the reason this command now has two lists.\n * They are the sections that left the scaffolded AGENTS.md — a file every\n * agents.md-aware host auto-loads on every session, which two hosts truncate\n * silently — and they are printed here instead. That trade only works if they\n * can be FOUND, so the bare menu names them; `core/agent/workflows/reference/\n * reference.ts` carries the rest of the argument.\n *\n * This is the only command in loam that reads nothing: no `loam.json`, no docs\n * repo, no service. That is deliberate and it is the point — an agent runs this\n * BEFORE the repository is wired, and a protocol that refused with `no-config`\n * would be unreachable exactly when it is most needed, which is the first\n * minute in an unfamiliar repository. `loam-adopt`'s own first step is to run\n * `loam init` when there is no config, and it cannot be the step that requires\n * one.\n */\nexport function registerInstructions(program: Command): void {\n program\n .command(\"instructions\")\n // Still spelled `workflow`, not `page`: the positional is in every\n // generated command file loam has ever written (`loam instructions\n // loam-adopt $1`) and in `--help` output people have copied. Renaming it\n // buys a more accurate word in one usage line and costs nothing anywhere\n // the rename would be visible, so the accuracy goes in the menu text instead.\n .argument(\"[workflow]\", \"workflow or reference page (loam-adopt, loam-codes, …); omit to list them\")\n .argument(\"[args...]\", \"values substituted for the protocol's $1, $2, … placeholders\")\n .description(\"Print a workflow protocol or reference page, version-matched to this binary\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n // Opt-in, and off by default, so the default page of every lifecycle protocol\n // stays byte-identical: this narrows what an agent CAN ask for, it does not\n // change what it gets when it asks for nothing. The one protocol this is\n // about is /loam-check, whose fix tables are 83 KB of the 84 it prints —\n // about a fifth of a 100k-token window spent before the first check has\n // run — while `loam explain <code>` answers any one of those rows in under\n // 500 bytes. The narrowed page keeps every paragraph that INTRODUCES a\n // table, because that sentence is what says which scope a code was graded\n // in; only the rows go.\n .option(\n \"--no-fix-tables\",\n \"drop the per-code fix tables; `loam explain <code>` answers any code a run reports\",\n )\n // Every positional here is DATA — a feature id, a service id, a validate\n // target — and one of those targets is spelled `--all`. Without this,\n // commander reads a leading-dash argument as an option it does not have and\n // refuses the whole invocation, so `/loam-check --all` (the first form the\n // command file's own argument hint offers) got a usage error instead of the\n // protocol. `--json` still parses as the flag it is, because it is declared.\n .allowUnknownOption()\n .action((workflow: string | undefined, args: string[], opts: InstructionsOptions) => {\n const json = opts.json === true;\n\n if (workflow === undefined) {\n if (json) {\n // `support` and `references` are ADDITIVE beside the `workflows` key\n // a consumer already reads. Appending either kind to `workflows`\n // would have been the smaller diff and the wrong one: a caller\n // iterating that array to drive the cycle would start running\n // diagnostics or documentation as steps.\n emitJson({\n command: \"instructions\",\n version: LOAM_VERSION,\n workflows: WORKFLOWS,\n support: SUPPORT_PAGES,\n references: REFERENCE_PAGES,\n });\n return;\n }\n // One column width across all three lists, so the blocks line up as one\n // menu — they are separate KINDS, not separate tables.\n const width = Math.max(\n ...[...WORKFLOWS, ...SUPPORT_PAGES, ...REFERENCE_PAGES].map((w) => w.name.length),\n );\n console.log(`loam ${LOAM_VERSION} — workflows\\n`);\n for (const w of WORKFLOWS) {\n console.log(` ${w.name.padEnd(width)} ${w.description}`);\n }\n console.log(`\\nsupport — use when a run or agent integration behaves unexpectedly\\n`);\n for (const s of SUPPORT_PAGES) {\n console.log(` ${s.name.padEnd(width)} ${s.description}`);\n }\n // Under their own heading, and never merged into the six above. A page\n // has no steps and is not part of the cycle; a flat list of ten would\n // read as a ten-step process, which is the one thing the cycle must not\n // be confused with. The sentence says what they are FOR, because a name\n // alone does not distinguish \"reference\" from \"seventh step\".\n console.log(`\\nreference pages — printed whole, no arguments\\n`);\n for (const r of REFERENCE_PAGES) {\n console.log(` ${r.name.padEnd(width)} ${r.description}`);\n }\n console.log(\n `\\nloam instructions <workflow> [args...] prints one, placeholders filled in.` +\n `\\nloam instructions loam-report prints the local incident-reporting protocol.` +\n `\\nloam instructions <page> prints a reference page. The pages carry what AGENTS.md` +\n `\\nleaves out; \\`loam explain <code>\\` answers a single code without opening one.`,\n );\n return;\n }\n\n // Before the substitution, not after: a rendered protocol is a page of\n // instructions an agent acts on, and a `$1` that cannot be a service id\n // makes every command on that page unrunnable. The refusal reaches the\n // caller in the same shape a mistyped workflow name does.\n const problems = placeholderProblems(workflow, args);\n if (problems !== null) {\n fail(\n json,\n \"invalid-option\",\n `${problems.join(\" \")} Nothing was printed: every command in the ${workflow} protocol ` +\n \"interpolates that value, so the page would name a target no loam command can accept.\",\n );\n return;\n }\n\n const body = protocolFor(workflow, args);\n if (body === null) {\n // `unknown-target`, the same code `show` uses for a name that resolves\n // to nothing. The known set is small and closed, so it is listed rather\n // than described: a caller that mistyped a known name should not have\n // to run a second command to see the choices.\n fail(\n json,\n \"unknown-target\",\n `No workflow '${workflow}'. Known: ${Object.keys(PROTOCOLS).join(\", \")}.`,\n );\n return;\n }\n\n // The narrowing composes with `--json` rather than forking the envelope:\n // the shorter page rides in the same `body` field, so no key is added or\n // renamed and a consumer that never passes the flag cannot tell the\n // difference. `--json` is the larger of the two views (the whole table is\n // one JSON string), which is exactly why it needs this too.\n const page = opts.fixTables === false ? withoutFixTables(body) : body;\n\n if (json) {\n // `body` is the substituted text, not the template: a consumer that\n // asked for `loam instructions loam-adopt payment-service --json` wants\n // the protocol it is about to follow, and re-implementing the\n // substitution on the other side is a second copy of the rule.\n emitJson({ command: \"instructions\", version: LOAM_VERSION, workflow, args, body: page });\n return;\n }\n // `console.log`, like every other command, rather than a raw stdout\n // write: the test harness captures the console and a direct write is\n // invisible to it — an untestable print is how a protocol nobody notices\n // went missing would ship. The body already ends in a newline, so the\n // one console.log adds is trimmed rather than doubled.\n console.log(page.replace(/\\n+$/, \"\"));\n });\n}\n"]}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The `--subsystem` slice behind `loam list`: what the flag's name denotes,
3
+ * and which services the filter keeps. A sub-package of list/ because the
4
+ * list package proper stands at its five-file limit (review.ts records
5
+ * that), and the adoption-campaign flag surface is its own subject beside
6
+ * the section renderers. The dependency direction is list → list/campaign,
7
+ * never back — this package imports core only, the same rule repo → repo/tree
8
+ * already keeps.
9
+ *
10
+ * Resolution reuses the tree machinery verbatim (`findInTree`,
11
+ * `servicesUnder`, `nearestTreeNames`), so `list --subsystem` and every
12
+ * `loam subsystem` verb read the flat namespace the same way — two spellings
13
+ * of "what does this name mean" would drift.
14
+ */
15
+ import { fail } from "../../../core/envelope/json.js";
16
+ import { findInTree, nearestTreeNames, servicesUnder, subsystemsUnder } from "../../../core/repo/tree/find.js";
17
+ /**
18
+ * Resolve `--subsystem <name>` against the flat namespace, or report the
19
+ * refusal and return null. The reserved name `unfiled` selects the services
20
+ * filed under no subsystem — the tree's own concept, otherwise unreachable —
21
+ * but only while nothing in the tree claims that name: a REAL subsystem or
22
+ * service spelled `unfiled` wins, the same concrete-name-wins precedence
23
+ * `findInTree` already applies to service/subsystem ties. An unknown name
24
+ * refuses `unknown-target` with close-name hints rather than succeeding
25
+ * emptily — an empty table over a typo would read as a finished campaign —
26
+ * and a service name refuses `invalid-option` exactly as `loam adopt
27
+ * --subsystem` does: a service never contains other services.
28
+ */
29
+ export function resolveSubsystemSlice(tree, name, json) {
30
+ const hit = findInTree(tree, name);
31
+ if (hit === null && name === "unfiled") {
32
+ return {
33
+ members: new Set(tree.services.filter((s) => s.subsystem.length === 0).map((s) => s.dir)),
34
+ subsystems: [],
35
+ label: "unfiled services (directly under services/)",
36
+ };
37
+ }
38
+ if (hit === null) {
39
+ // The Set: a real subsystem named 'unfiled' would otherwise sit in the
40
+ // hint pool twice and could be offered twice in one hint.
41
+ const close = nearestTreeNames(name, [...new Set([...tree.subsystems.map((s) => s.name), "unfiled"])]);
42
+ fail(json, "unknown-target", `No subsystem '${name}' in the tree.` +
43
+ (close.length > 0
44
+ ? ` Close names: ${close.join(", ")}.`
45
+ : " `loam subsystem list` shows what exists; `unfiled` selects the services filed under none."));
46
+ return null;
47
+ }
48
+ if (hit.kind === "service") {
49
+ // With a SERVICE claiming the name 'unfiled' the reserved reading has no
50
+ // spelling at all, so the refusal must say what is shadowed — otherwise
51
+ // the message reads as loam misunderstanding the request.
52
+ const shadowed = name === "unfiled"
53
+ ? " While a service claims this name, the reserved unfiled-services reading is shadowed; rename the service to reach it."
54
+ : "";
55
+ fail(json, "invalid-option", `--subsystem names the service '${name}' — a service never contains other services.${shadowed}`);
56
+ return null;
57
+ }
58
+ const sub = hit.subsystem;
59
+ return {
60
+ members: new Set(servicesUnder(tree, sub).map((s) => s.dir)),
61
+ subsystems: [sub, ...subsystemsUnder(tree, sub)],
62
+ label: `subsystem '${sub.name}' (services/${sub.path.join("/")}/)`,
63
+ };
64
+ }
65
+ //# sourceMappingURL=campaign.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"campaign.js","sourceRoot":"","sources":["../../../../src/commands/list/campaign/campaign.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAqB/G;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAe,EAAE,IAAY,EAAE,IAAa;IAChF,MAAM,GAAG,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,IAAI,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvC,OAAO;YACL,OAAO,EAAE,IAAI,GAAG,CAAS,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YACjG,UAAU,EAAE,EAAE;YACd,KAAK,EAAE,6CAA6C;SACrD,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;QACjB,uEAAuE;QACvE,0DAA0D;QAC1D,MAAM,KAAK,GAAG,gBAAgB,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACvG,IAAI,CACF,IAAI,EACJ,gBAAgB,EAChB,iBAAiB,IAAI,gBAAgB;YACnC,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;gBACf,CAAC,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;gBACtC,CAAC,CAAC,4FAA4F,CAAC,CACpG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC3B,yEAAyE;QACzE,wEAAwE;QACxE,0DAA0D;QAC1D,MAAM,QAAQ,GACZ,IAAI,KAAK,SAAS;YAChB,CAAC,CAAC,uHAAuH;YACzH,CAAC,CAAC,EAAE,CAAC;QACT,IAAI,CACF,IAAI,EACJ,gBAAgB,EAChB,kCAAkC,IAAI,+CAA+C,QAAQ,EAAE,CAChG,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,CAAC;IAC1B,OAAO;QACL,OAAO,EAAE,IAAI,GAAG,CAAS,aAAa,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACpE,UAAU,EAAE,CAAC,GAAG,EAAE,GAAG,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAChD,KAAK,EAAE,cAAc,GAAG,CAAC,IAAI,eAAe,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI;KACnE,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The `--subsystem` slice behind `loam list`: what the flag's name denotes,\n * and which services the filter keeps. A sub-package of list/ because the\n * list package proper stands at its five-file limit (review.ts records\n * that), and the adoption-campaign flag surface is its own subject beside\n * the section renderers. The dependency direction is list → list/campaign,\n * never back — this package imports core only, the same rule repo → repo/tree\n * already keeps.\n *\n * Resolution reuses the tree machinery verbatim (`findInTree`,\n * `servicesUnder`, `nearestTreeNames`), so `list --subsystem` and every\n * `loam subsystem` verb read the flat namespace the same way — two spellings\n * of \"what does this name mean\" would drift.\n */\nimport { fail } from \"../../../core/envelope/json.js\";\nimport { findInTree, nearestTreeNames, servicesUnder, subsystemsUnder } from \"../../../core/repo/tree/find.js\";\nimport type { FleetTree, SubsystemEntry } from \"../../../core/repo/tree/walk.js\";\n\nexport interface SubsystemSlice {\n /**\n * DIRECTORIES of the member services, at any depth beneath the filter\n * target — the directory, not the id, because the id is a leaf name the\n * fleet does not guarantee unique: a `subsystem.name-collision` tree still\n * enumerates both claimants on purpose, and an id-keyed slice would let\n * each of two disjoint slices claim the other's service.\n */\n readonly members: ReadonlySet<string>;\n /**\n * The subsystem rows the filtered payload shows — the named subsystem and\n * its descendants; `[]` for the unfiled slice, which sits under no group.\n */\n readonly subsystems: SubsystemEntry[];\n /** The human filter line's description of what the slice is. */\n readonly label: string;\n}\n\n/**\n * Resolve `--subsystem <name>` against the flat namespace, or report the\n * refusal and return null. The reserved name `unfiled` selects the services\n * filed under no subsystem — the tree's own concept, otherwise unreachable —\n * but only while nothing in the tree claims that name: a REAL subsystem or\n * service spelled `unfiled` wins, the same concrete-name-wins precedence\n * `findInTree` already applies to service/subsystem ties. An unknown name\n * refuses `unknown-target` with close-name hints rather than succeeding\n * emptily — an empty table over a typo would read as a finished campaign —\n * and a service name refuses `invalid-option` exactly as `loam adopt\n * --subsystem` does: a service never contains other services.\n */\nexport function resolveSubsystemSlice(tree: FleetTree, name: string, json: boolean): SubsystemSlice | null {\n const hit = findInTree(tree, name);\n if (hit === null && name === \"unfiled\") {\n return {\n members: new Set<string>(tree.services.filter((s) => s.subsystem.length === 0).map((s) => s.dir)),\n subsystems: [],\n label: \"unfiled services (directly under services/)\",\n };\n }\n if (hit === null) {\n // The Set: a real subsystem named 'unfiled' would otherwise sit in the\n // hint pool twice and could be offered twice in one hint.\n const close = nearestTreeNames(name, [...new Set([...tree.subsystems.map((s) => s.name), \"unfiled\"])]);\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${name}' in the tree.` +\n (close.length > 0\n ? ` Close names: ${close.join(\", \")}.`\n : \" `loam subsystem list` shows what exists; `unfiled` selects the services filed under none.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n // With a SERVICE claiming the name 'unfiled' the reserved reading has no\n // spelling at all, so the refusal must say what is shadowed — otherwise\n // the message reads as loam misunderstanding the request.\n const shadowed =\n name === \"unfiled\"\n ? \" While a service claims this name, the reserved unfiled-services reading is shadowed; rename the service to reach it.\"\n : \"\";\n fail(\n json,\n \"invalid-option\",\n `--subsystem names the service '${name}' — a service never contains other services.${shadowed}`,\n );\n return null;\n }\n const sub = hit.subsystem;\n return {\n members: new Set<string>(servicesUnder(tree, sub).map((s) => s.dir)),\n subsystems: [sub, ...subsystemsUnder(tree, sub)],\n label: `subsystem '${sub.name}' (services/${sub.path.join(\"/\")}/)`,\n };\n}\n"]}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * The `--owners` join behind `loam list`: read the user-named CODEOWNERS
3
+ * file, bucket the CURRENT listing's rows under the teams it names, and
4
+ * refuse — `owners-unreadable` — when the file cannot be read or a line in
5
+ * it cannot be parsed as `pattern owner…`. The parse and the matching are
6
+ * `core/owners/codeowners.ts`'s (pure; its header records the implemented
7
+ * subset and the skip-don't-guess rule); this module owns the filesystem
8
+ * read and the refusal, because core never prints.
9
+ *
10
+ * The join runs over the rows the listing is about to show, in the order it
11
+ * will show them — after `--subsystem`/`--needs-work` filtering and any
12
+ * `--review-order` ranking — so each team's array IS that team's campaign
13
+ * worklist, not a second, differently-ordered opinion of the fleet.
14
+ */
15
+ import { readFile } from "node:fs/promises";
16
+ import { fail } from "../../../core/envelope/json.js";
17
+ import { ownersFor, parseCodeowners } from "../../../core/owners/codeowners.js";
18
+ /**
19
+ * Read, parse and join, or report the refusal and return null. An empty or
20
+ * all-skipped file is NOT a refusal: every row lands in `unowned`, honestly —
21
+ * the file said nothing, and saying so is the answer.
22
+ */
23
+ export async function ownersJoin(req) {
24
+ let content;
25
+ try {
26
+ content = await readFile(req.path, "utf8");
27
+ }
28
+ catch (err) {
29
+ const detail = err instanceof Error ? err.message : String(err);
30
+ fail(req.json, "owners-unreadable", `Cannot read the CODEOWNERS file at ${req.path}: ${detail}. Nothing was joined; re-run with the path of the file the forge actually uses.`);
31
+ return null;
32
+ }
33
+ const parsed = parseCodeowners(content);
34
+ if (!parsed.ok) {
35
+ fail(req.json, "owners-unreadable", `${req.path}:${parsed.line}: ${parsed.problem}. A rule loam cannot read is never guessed at or silently skipped — fix the line, then re-run.`);
36
+ return null;
37
+ }
38
+ const byOwner = new Map();
39
+ const unowned = [];
40
+ for (const row of req.rows) {
41
+ const owners = ownersFor(row.repoDir.split("/"), parsed.rules);
42
+ if (owners.length === 0) {
43
+ unowned.push(row);
44
+ continue;
45
+ }
46
+ // A rule may name several owners; the service files under EACH — a shared
47
+ // directory is two teams' work, not half of either's. The Set: a rule
48
+ // repeating one owner (`@a @a`) must not list the service twice.
49
+ for (const owner of new Set(owners)) {
50
+ byOwner.set(owner, [...(byOwner.get(owner) ?? []), row]);
51
+ }
52
+ }
53
+ return {
54
+ path: req.path,
55
+ // Plain lexicographic on the owner string: deterministic across machines,
56
+ // and owner handles are not ids, so compareIds' numeric tokenizing has
57
+ // nothing to add.
58
+ teams: [...byOwner.entries()]
59
+ .sort(([a], [b]) => (a < b ? -1 : 1))
60
+ .map(([owner, services]) => ({ owner, services })),
61
+ unowned,
62
+ skipped: parsed.skipped,
63
+ };
64
+ }
65
+ //# sourceMappingURL=owners.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"owners.js","sourceRoot":"","sources":["../../../../src/commands/list/campaign/owners.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,gCAAgC,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,eAAe,EAAoB,MAAM,oCAAoC,CAAC;AA4BlG;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAIhC;IACC,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,IAAI,CACF,GAAG,CAAC,IAAI,EACR,mBAAmB,EACnB,sCAAsC,GAAG,CAAC,IAAI,KAAK,MAAM,iFAAiF,CAC3I,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACxC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,IAAI,CACF,GAAG,CAAC,IAAI,EACR,mBAAmB,EACnB,GAAG,GAAG,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,CAAC,OAAO,gGAAgG,CAC9I,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC/D,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YAClB,SAAS;QACX,CAAC;QACD,0EAA0E;QAC1E,sEAAsE;QACtE,iEAAiE;QACjE,KAAK,MAAM,KAAK,IAAI,IAAI,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,0EAA0E;QAC1E,uEAAuE;QACvE,kBAAkB;QAClB,KAAK,EAAE,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;aAC1B,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;aACpC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpD,OAAO;QACP,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The `--owners` join behind `loam list`: read the user-named CODEOWNERS\n * file, bucket the CURRENT listing's rows under the teams it names, and\n * refuse — `owners-unreadable` — when the file cannot be read or a line in\n * it cannot be parsed as `pattern owner…`. The parse and the matching are\n * `core/owners/codeowners.ts`'s (pure; its header records the implemented\n * subset and the skip-don't-guess rule); this module owns the filesystem\n * read and the refusal, because core never prints.\n *\n * The join runs over the rows the listing is about to show, in the order it\n * will show them — after `--subsystem`/`--needs-work` filtering and any\n * `--review-order` ranking — so each team's array IS that team's campaign\n * worklist, not a second, differently-ordered opinion of the fleet.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { fail } from \"../../../core/envelope/json.js\";\nimport { ownersFor, parseCodeowners, type SkippedRule } from \"../../../core/owners/codeowners.js\";\n\n/** One row of the listing, reduced to what the join reads. */\nexport interface OwnedRow {\n readonly id: string;\n /** The service's docs-repo-relative directory, forward slashes (`repoPath`). */\n readonly repoDir: string;\n}\n\nexport interface OwnersJoin {\n /** The path exactly as the user named it — the file is theirs, not loam's. */\n readonly path: string;\n /**\n * One bucket per owning team, sorted by owner; rows in row order. The full\n * row, not the id: leaf ids can collide across a broken tree, and the\n * renderers join back to their views by `repoDir` — the row's identity.\n */\n readonly teams: { readonly owner: string; readonly services: readonly OwnedRow[] }[];\n /**\n * Rows no rule matched, or whose LAST matching rule named no owner —\n * GitHub's ownership-clearing form. Listed explicitly, because a service\n * silently absent from every team's queue reads as somebody else's work.\n */\n readonly unowned: readonly OwnedRow[];\n /** Recognised rules outside the implemented subset — reported, never guessed. */\n readonly skipped: readonly SkippedRule[];\n}\n\n/**\n * Read, parse and join, or report the refusal and return null. An empty or\n * all-skipped file is NOT a refusal: every row lands in `unowned`, honestly —\n * the file said nothing, and saying so is the answer.\n */\nexport async function ownersJoin(req: {\n path: string;\n rows: readonly OwnedRow[];\n json: boolean;\n}): Promise<OwnersJoin | null> {\n let content: string;\n try {\n content = await readFile(req.path, \"utf8\");\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n fail(\n req.json,\n \"owners-unreadable\",\n `Cannot read the CODEOWNERS file at ${req.path}: ${detail}. Nothing was joined; re-run with the path of the file the forge actually uses.`,\n );\n return null;\n }\n const parsed = parseCodeowners(content);\n if (!parsed.ok) {\n fail(\n req.json,\n \"owners-unreadable\",\n `${req.path}:${parsed.line}: ${parsed.problem}. A rule loam cannot read is never guessed at or silently skipped — fix the line, then re-run.`,\n );\n return null;\n }\n const byOwner = new Map<string, OwnedRow[]>();\n const unowned: OwnedRow[] = [];\n for (const row of req.rows) {\n const owners = ownersFor(row.repoDir.split(\"/\"), parsed.rules);\n if (owners.length === 0) {\n unowned.push(row);\n continue;\n }\n // A rule may name several owners; the service files under EACH — a shared\n // directory is two teams' work, not half of either's. The Set: a rule\n // repeating one owner (`@a @a`) must not list the service twice.\n for (const owner of new Set(owners)) {\n byOwner.set(owner, [...(byOwner.get(owner) ?? []), row]);\n }\n }\n return {\n path: req.path,\n // Plain lexicographic on the owner string: deterministic across machines,\n // and owner handles are not ids, so compareIds' numeric tokenizing has\n // nothing to add.\n teams: [...byOwner.entries()]\n .sort(([a], [b]) => (a < b ? -1 : 1))\n .map(([owner, services]) => ({ owner, services })),\n unowned,\n skipped: parsed.skipped,\n };\n}\n"]}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * The `--json` rows. Separate from `./print.ts` because only this side is a
3
+ * contract: the payload keys are frozen, the columns beside them are not.
4
+ */
5
+ import { repoPath } from "../../core/envelope/json.js";
6
+ import {} from "../../core/capabilities/rollup.js";
7
+ import {} from "../../core/repo/entries.js";
8
+ import { servicesUnder } from "../../core/repo/tree/find.js";
9
+ import {} from "./views.js";
10
+ /**
11
+ * The `services[]` rows: ranked and decorated under `--review-order`, plain
12
+ * otherwise — as a VARIANT, so a call carrying both a plain list and a ranked
13
+ * queue is unrepresentable rather than resolved by precedence. `fanIn`/
14
+ * `reviewRank` are ADDITIVE and appear ONLY under the flag — bare
15
+ * `loam list --json` and `--needs-work --json` stay byte-identical and
16
+ * cost-identical, the frozen-default doctrine the explicit-only capabilities
17
+ * section also follows. The spread keeps serviceJson at its two-param
18
+ * contract; `reviewRank` is 1-based and equals the row's position, so the
19
+ * array order IS the queue.
20
+ */
21
+ export function serviceRows(docsDir, rows) {
22
+ if (Array.isArray(rows))
23
+ return rows.map((v) => serviceJson(docsDir, v));
24
+ return rows.queue.map((v, i) => ({
25
+ ...serviceJson(docsDir, v),
26
+ fanIn: rows.fanIn.get(v.entry.id) ?? 0,
27
+ reviewRank: i + 1,
28
+ }));
29
+ }
30
+ export function serviceJson(docsDir, v) {
31
+ const s = v.entry;
32
+ return {
33
+ id: s.id,
34
+ path: repoPath(docsDir, s.dir),
35
+ // Names from services/ down, outermost first; [] = unfiled. `path` above
36
+ // already truthfully reflects placement — this is the same fact as data
37
+ // instead of a string to split.
38
+ subsystem: s.subsystem,
39
+ has: { ...s.has, archSpec: v.archSpec },
40
+ adrs: s.adrs,
41
+ status: s.status,
42
+ maturity: v.maturity,
43
+ missing: v.missing,
44
+ apiExpected: v.apiExpected,
45
+ // Never omitted when true: a consumer that filters this table into a
46
+ // worklist has to be able to tell "checked and fine" from "not checkable
47
+ // from here", and absence reads as the first one.
48
+ ...(v.unverifiableFromHere ? { provenance: "unverifiable-from-here" } : {}),
49
+ // Additive, and only when there IS a scope — omission is the fine case
50
+ // here, exactly as it is for `provenance` above, and `maturity` stays the
51
+ // frozen `vouched` beside it. A dashboard counting `maturity: "vouched"`
52
+ // rows keeps counting them; one that cares whether a person read the
53
+ // document subtracts these.
54
+ ...(s.vouchScope === "sampled" ? { vouchScope: "sampled" } : {}),
55
+ };
56
+ }
57
+ /**
58
+ * The subsystem rows beside the service table, sorted by path. `memberCount`
59
+ * is TRANSITIVE — every service beneath, at any depth — matching the
60
+ * generated views file's membership, so the two numbers a consumer can
61
+ * cross-check never disagree about what "in this group" means.
62
+ */
63
+ export function subsystemsJson(docsDir, tree) {
64
+ return [...tree.subsystems]
65
+ .sort((a, b) => (a.path.join("/") < b.path.join("/") ? -1 : 1))
66
+ .map((sub) => ({
67
+ name: sub.name,
68
+ path: repoPath(docsDir, sub.dir),
69
+ title: sub.meta.title ?? null,
70
+ memberCount: servicesUnder(tree, sub).length,
71
+ }));
72
+ }
73
+ /**
74
+ * The additive `owners` payload key under `--owners` — the join result as a
75
+ * contract: `path` (the file exactly as the user named it), `teams[]` (owner
76
+ * plus that team's services, in the LISTING's own filtered-and-ordered row
77
+ * order, so each array is that team's campaign worklist), `unowned[]` (rows
78
+ * no rule matched — explicit, because absence would read as owned-somewhere),
79
+ * and `skippedRules[]` (recognised rules outside the implemented CODEOWNERS
80
+ * subset, each with its line — reported, never guessed at). Key spellings
81
+ * frozen once shipped; the join itself lives in campaign/owners.ts.
82
+ *
83
+ * The service arrays carry IDS. On a `subsystem.name-collision` fleet —
84
+ * already an error finding — two rows can share an id, so a consumer cannot
85
+ * tell them apart here; if that ever needs disambiguating, the fix is a new
86
+ * ADDITIVE key carrying paths, never a change to these.
87
+ */
88
+ export function ownersJson(join) {
89
+ return {
90
+ path: join.path,
91
+ teams: join.teams.map((team) => ({ owner: team.owner, services: team.services.map((row) => row.id) })),
92
+ unowned: join.unowned.map((row) => row.id),
93
+ skippedRules: join.skipped.map((rule) => ({ line: rule.line, pattern: rule.pattern })),
94
+ };
95
+ }
96
+ /**
97
+ * One `capabilities[]` row — additive payload, explicit `loam list
98
+ * capabilities` only, and diff-stable: the rollup already sorts rows,
99
+ * realizedBy and statuses' keys deterministically, and this projection adds
100
+ * nothing that could vary between machines. Optional keys are omitted rather
101
+ * than nulled so a declaration that never carried a description does not grow
102
+ * one in the diff.
103
+ */
104
+ export function capabilityJson(row) {
105
+ return {
106
+ id: row.id,
107
+ ...(row.description !== undefined ? { description: row.description } : {}),
108
+ ...(row.owner !== undefined ? { owner: row.owner } : {}),
109
+ realizedBy: row.realizedBy,
110
+ services: row.services,
111
+ statuses: row.statuses,
112
+ // Present only for a capability that HAS a document, and absent rather than
113
+ // `[]` for one that does not — the same optional-key rule the two fields
114
+ // above follow, and here it carries a distinction a reader needs: an empty
115
+ // array means the document declares no requirements, while no key at all
116
+ // means there is no document to declare any.
117
+ //
118
+ // Each row inside carries `realizedBy` (the service requirements whose
119
+ // `Realizes:` line names it) and `keptBy` (the flows whose `#cap-`/`#req-`
120
+ // tags resolve to it) — two independent corpora, NEITHER derived from the
121
+ // other, because a cross-service promise can only be kept by a flow and a
122
+ // per-service one is normally kept by a requirement. `keptBy` follows the
123
+ // same three-state rule one level down and `rollup.ts` states it: absent
124
+ // means nobody looked, `[]` means loam looked and no flow keeps it. The
125
+ // payload's own `useCases.unreadable` says which of the two absences it is.
126
+ ...(row.requirements === undefined ? {} : { requirements: row.requirements }),
127
+ };
128
+ }
129
+ export function featureJson(docsDir, f, verification) {
130
+ return {
131
+ id: f.id,
132
+ dirName: f.dirName,
133
+ path: repoPath(docsDir, f.dir),
134
+ archived: f.archived,
135
+ services: f.services,
136
+ has: f.has,
137
+ verification,
138
+ };
139
+ }
140
+ /* ------------------------------------------------------------------ */
141
+ /* Verification */
142
+ /* ------------------------------------------------------------------ */
143
+ /** What the features table says about verification without N `loam verify` runs. */
144
+ /**
145
+ * One `glossary[]` row — additive payload, explicit `loam list glossary` only.
146
+ *
147
+ * `linkedBy` is the whole reason the section exists: "which documents use this
148
+ * term" is a grep today and a join here, and it is the same answer
149
+ * `glossary.unlinked` grades. Repo-relative and sorted by the index itself, so
150
+ * the payload is diff-stable across machines. Empty means loam read every
151
+ * authored document and none of them cites the term — never "nobody looked",
152
+ * which is what the sibling `links.unreadable` list is for.
153
+ */
154
+ export function glossaryJson(term, linkedBy, docsDir) {
155
+ return { id: term.id, path: repoPath(docsDir, term.path), linkedBy };
156
+ }
157
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../../src/commands/list/json.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The `--json` rows. Separate from `./print.ts` because only this side is a\n * contract: the payload keys are frozen, the columns beside them are not.\n */\nimport { repoPath } from \"../../core/envelope/json.js\";\nimport { type CapabilityRow } from \"../../core/capabilities/rollup.js\";\nimport { type FeatureEntry } from \"../../core/repo/entries.js\";\nimport { servicesUnder } from \"../../core/repo/tree/find.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport type { OwnersJoin } from \"./campaign/owners.js\";\nimport { type ServiceView, type VerificationCell } from \"./views.js\";\n\n/**\n * The `services[]` rows: ranked and decorated under `--review-order`, plain\n * otherwise — as a VARIANT, so a call carrying both a plain list and a ranked\n * queue is unrepresentable rather than resolved by precedence. `fanIn`/\n * `reviewRank` are ADDITIVE and appear ONLY under the flag — bare\n * `loam list --json` and `--needs-work --json` stay byte-identical and\n * cost-identical, the frozen-default doctrine the explicit-only capabilities\n * section also follows. The spread keeps serviceJson at its two-param\n * contract; `reviewRank` is 1-based and equals the row's position, so the\n * array order IS the queue.\n */\nexport function serviceRows(\n docsDir: string,\n rows: ServiceView[] | { queue: ServiceView[]; fanIn: ReadonlyMap<string, number> },\n): Record<string, unknown>[] {\n if (Array.isArray(rows)) return rows.map((v) => serviceJson(docsDir, v));\n return rows.queue.map((v, i) => ({\n ...serviceJson(docsDir, v),\n fanIn: rows.fanIn.get(v.entry.id) ?? 0,\n reviewRank: i + 1,\n }));\n}\n\nexport function serviceJson(docsDir: string, v: ServiceView): Record<string, unknown> {\n const s = v.entry;\n return {\n id: s.id,\n path: repoPath(docsDir, s.dir),\n // Names from services/ down, outermost first; [] = unfiled. `path` above\n // already truthfully reflects placement — this is the same fact as data\n // instead of a string to split.\n subsystem: s.subsystem,\n has: { ...s.has, archSpec: v.archSpec },\n adrs: s.adrs,\n status: s.status,\n maturity: v.maturity,\n missing: v.missing,\n apiExpected: v.apiExpected,\n // Never omitted when true: a consumer that filters this table into a\n // worklist has to be able to tell \"checked and fine\" from \"not checkable\n // from here\", and absence reads as the first one.\n ...(v.unverifiableFromHere ? { provenance: \"unverifiable-from-here\" } : {}),\n // Additive, and only when there IS a scope — omission is the fine case\n // here, exactly as it is for `provenance` above, and `maturity` stays the\n // frozen `vouched` beside it. A dashboard counting `maturity: \"vouched\"`\n // rows keeps counting them; one that cares whether a person read the\n // document subtracts these.\n ...(s.vouchScope === \"sampled\" ? { vouchScope: \"sampled\" } : {}),\n };\n}\n\n/**\n * The subsystem rows beside the service table, sorted by path. `memberCount`\n * is TRANSITIVE — every service beneath, at any depth — matching the\n * generated views file's membership, so the two numbers a consumer can\n * cross-check never disagree about what \"in this group\" means.\n */\nexport function subsystemsJson(docsDir: string, tree: FleetTree): Record<string, unknown>[] {\n return [...tree.subsystems]\n .sort((a, b) => (a.path.join(\"/\") < b.path.join(\"/\") ? -1 : 1))\n .map((sub) => ({\n name: sub.name,\n path: repoPath(docsDir, sub.dir),\n title: sub.meta.title ?? null,\n memberCount: servicesUnder(tree, sub).length,\n }));\n}\n\n/**\n * The additive `owners` payload key under `--owners` — the join result as a\n * contract: `path` (the file exactly as the user named it), `teams[]` (owner\n * plus that team's services, in the LISTING's own filtered-and-ordered row\n * order, so each array is that team's campaign worklist), `unowned[]` (rows\n * no rule matched — explicit, because absence would read as owned-somewhere),\n * and `skippedRules[]` (recognised rules outside the implemented CODEOWNERS\n * subset, each with its line — reported, never guessed at). Key spellings\n * frozen once shipped; the join itself lives in campaign/owners.ts.\n *\n * The service arrays carry IDS. On a `subsystem.name-collision` fleet —\n * already an error finding — two rows can share an id, so a consumer cannot\n * tell them apart here; if that ever needs disambiguating, the fix is a new\n * ADDITIVE key carrying paths, never a change to these.\n */\nexport function ownersJson(join: OwnersJoin): Record<string, unknown> {\n return {\n path: join.path,\n teams: join.teams.map((team) => ({ owner: team.owner, services: team.services.map((row) => row.id) })),\n unowned: join.unowned.map((row) => row.id),\n skippedRules: join.skipped.map((rule) => ({ line: rule.line, pattern: rule.pattern })),\n };\n}\n\n/**\n * One `capabilities[]` row — additive payload, explicit `loam list\n * capabilities` only, and diff-stable: the rollup already sorts rows,\n * realizedBy and statuses' keys deterministically, and this projection adds\n * nothing that could vary between machines. Optional keys are omitted rather\n * than nulled so a declaration that never carried a description does not grow\n * one in the diff.\n */\nexport function capabilityJson(row: CapabilityRow): Record<string, unknown> {\n return {\n id: row.id,\n ...(row.description !== undefined ? { description: row.description } : {}),\n ...(row.owner !== undefined ? { owner: row.owner } : {}),\n realizedBy: row.realizedBy,\n services: row.services,\n statuses: row.statuses,\n // Present only for a capability that HAS a document, and absent rather than\n // `[]` for one that does not — the same optional-key rule the two fields\n // above follow, and here it carries a distinction a reader needs: an empty\n // array means the document declares no requirements, while no key at all\n // means there is no document to declare any.\n //\n // Each row inside carries `realizedBy` (the service requirements whose\n // `Realizes:` line names it) and `keptBy` (the flows whose `#cap-`/`#req-`\n // tags resolve to it) — two independent corpora, NEITHER derived from the\n // other, because a cross-service promise can only be kept by a flow and a\n // per-service one is normally kept by a requirement. `keptBy` follows the\n // same three-state rule one level down and `rollup.ts` states it: absent\n // means nobody looked, `[]` means loam looked and no flow keeps it. The\n // payload's own `useCases.unreadable` says which of the two absences it is.\n ...(row.requirements === undefined ? {} : { requirements: row.requirements }),\n };\n}\n\nexport function featureJson(\n docsDir: string,\n f: FeatureEntry,\n verification: VerificationCell | null,\n): Record<string, unknown> {\n return {\n id: f.id,\n dirName: f.dirName,\n path: repoPath(docsDir, f.dir),\n archived: f.archived,\n services: f.services,\n has: f.has,\n verification,\n };\n}\n\n/* ------------------------------------------------------------------ */\n/* Verification */\n/* ------------------------------------------------------------------ */\n\n/** What the features table says about verification without N `loam verify` runs. */\n\n/**\n * One `glossary[]` row — additive payload, explicit `loam list glossary` only.\n *\n * `linkedBy` is the whole reason the section exists: \"which documents use this\n * term\" is a grep today and a join here, and it is the same answer\n * `glossary.unlinked` grades. Repo-relative and sorted by the index itself, so\n * the payload is diff-stable across machines. Empty means loam read every\n * authored document and none of them cites the term — never \"nobody looked\",\n * which is what the sibling `links.unreadable` list is for.\n */\nexport function glossaryJson(term: { id: string; path: string }, linkedBy: string[], docsDir: string): Record<string, unknown> {\n return { id: term.id, path: repoPath(docsDir, term.path), linkedBy };\n}\n"]}