@ybotok/loam 0.2.0-alpha.6 → 0.2.0-alpha.9

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 (691) hide show
  1. package/CHANGELOG.md +1477 -1
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +40 -22
  5. package/QUICKSTART.md +181 -9
  6. package/README.md +256 -57
  7. package/ROADMAP.md +108 -11
  8. package/SCHEMA.md +721 -130
  9. package/WORKFLOW.md +272 -62
  10. package/dist/cli.js +26 -8
  11. package/dist/cli.js.map +1 -1
  12. package/dist/commands/adopt/adopt.js +5 -10
  13. package/dist/commands/adopt/adopt.js.map +1 -1
  14. package/dist/commands/archive/archive.js +15 -18
  15. package/dist/commands/archive/archive.js.map +1 -1
  16. package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
  17. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  18. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  19. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/openapi.js +25 -42
  21. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
  23. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  24. package/dist/commands/archive/plan/gate.js +3 -7
  25. package/dist/commands/archive/plan/gate.js.map +1 -1
  26. package/dist/commands/archive/plan/landscape.js +4 -4
  27. package/dist/commands/archive/plan/landscape.js.map +1 -1
  28. package/dist/commands/archive/plan/refusal.js +8 -18
  29. package/dist/commands/archive/plan/refusal.js.map +1 -1
  30. package/dist/commands/archive/plan/specs.js +134 -25
  31. package/dist/commands/archive/plan/specs.js.map +1 -1
  32. package/dist/commands/archive/plan/state.js +1 -0
  33. package/dist/commands/archive/plan/state.js.map +1 -1
  34. package/dist/commands/archive/run.js +82 -33
  35. package/dist/commands/archive/run.js.map +1 -1
  36. package/dist/commands/archive/shipped.js +49 -0
  37. package/dist/commands/archive/shipped.js.map +1 -0
  38. package/dist/commands/context/context.js +4 -7
  39. package/dist/commands/context/context.js.map +1 -1
  40. package/dist/commands/context/print.js +2 -2
  41. package/dist/commands/context/print.js.map +1 -1
  42. package/dist/commands/delta/delta.js +44 -12
  43. package/dist/commands/delta/delta.js.map +1 -1
  44. package/dist/commands/delta/print.js +1 -1
  45. package/dist/commands/delta/print.js.map +1 -1
  46. package/dist/commands/dependencies.js +3 -7
  47. package/dist/commands/dependencies.js.map +1 -1
  48. package/dist/commands/diff/diff.js +20 -27
  49. package/dist/commands/diff/diff.js.map +1 -1
  50. package/dist/commands/explore.js +4 -8
  51. package/dist/commands/explore.js.map +1 -1
  52. package/dist/commands/gate/gate.js +45 -8
  53. package/dist/commands/gate/gate.js.map +1 -1
  54. package/dist/commands/gate/print.js +15 -3
  55. package/dist/commands/gate/print.js.map +1 -1
  56. package/dist/commands/gherkin/commit.js +13 -54
  57. package/dist/commands/gherkin/commit.js.map +1 -1
  58. package/dist/commands/gherkin/gherkin.js +36 -20
  59. package/dist/commands/gherkin/gherkin.js.map +1 -1
  60. package/dist/commands/gherkin/reconcile.js +10 -13
  61. package/dist/commands/gherkin/reconcile.js.map +1 -1
  62. package/dist/commands/init/first-hour.js +44 -0
  63. package/dist/commands/init/first-hour.js.map +1 -1
  64. package/dist/commands/init/init.js +18 -22
  65. package/dist/commands/init/init.js.map +1 -1
  66. package/dist/commands/list/campaign/campaign.js +4 -6
  67. package/dist/commands/list/campaign/campaign.js.map +1 -1
  68. package/dist/commands/list/json.js +0 -4
  69. package/dist/commands/list/json.js.map +1 -1
  70. package/dist/commands/list/list.js +38 -23
  71. package/dist/commands/list/list.js.map +1 -1
  72. package/dist/commands/list/print.js +38 -6
  73. package/dist/commands/list/print.js.map +1 -1
  74. package/dist/commands/list/suites/suites.js +140 -0
  75. package/dist/commands/list/suites/suites.js.map +1 -0
  76. package/dist/commands/list/views.js +28 -33
  77. package/dist/commands/list/views.js.map +1 -1
  78. package/dist/commands/mcp/dispatch.js +91 -36
  79. package/dist/commands/mcp/dispatch.js.map +1 -1
  80. package/dist/commands/mcp/mcp.js +56 -15
  81. package/dist/commands/mcp/mcp.js.map +1 -1
  82. package/dist/commands/mcp/serve.js.map +1 -1
  83. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  84. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  85. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  86. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  87. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  88. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  89. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  90. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  91. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  92. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  93. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  94. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  95. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  96. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  97. package/dist/commands/new/capability-template.js +118 -0
  98. package/dist/commands/new/capability-template.js.map +1 -0
  99. package/dist/commands/new/commit.js +8 -22
  100. package/dist/commands/new/commit.js.map +1 -1
  101. package/dist/commands/new/modifies.js +206 -0
  102. package/dist/commands/new/modifies.js.map +1 -0
  103. package/dist/commands/new/new.js +59 -14
  104. package/dist/commands/new/new.js.map +1 -1
  105. package/dist/commands/new/templates.js +48 -124
  106. package/dist/commands/new/templates.js.map +1 -1
  107. package/dist/commands/open.js +3 -7
  108. package/dist/commands/open.js.map +1 -1
  109. package/dist/commands/policy/gate.js +27 -0
  110. package/dist/commands/policy/gate.js.map +1 -1
  111. package/dist/commands/rebase/plan.js +2 -2
  112. package/dist/commands/rebase/plan.js.map +1 -1
  113. package/dist/commands/rebase/rebase.js +60 -35
  114. package/dist/commands/rebase/rebase.js.map +1 -1
  115. package/dist/commands/seed/commit.js +55 -26
  116. package/dist/commands/seed/commit.js.map +1 -1
  117. package/dist/commands/seed/plan.js +64 -13
  118. package/dist/commands/seed/plan.js.map +1 -1
  119. package/dist/commands/seed/seed.js +6 -9
  120. package/dist/commands/seed/seed.js.map +1 -1
  121. package/dist/commands/show/show.js +3 -7
  122. package/dist/commands/show/show.js.map +1 -1
  123. package/dist/commands/status/print.js +13 -4
  124. package/dist/commands/status/print.js.map +1 -1
  125. package/dist/commands/status/status.js +3 -7
  126. package/dist/commands/status/status.js.map +1 -1
  127. package/dist/commands/steps/steps.js +3 -7
  128. package/dist/commands/steps/steps.js.map +1 -1
  129. package/dist/commands/subsystem/edit.js +7 -7
  130. package/dist/commands/subsystem/edit.js.map +1 -1
  131. package/dist/commands/subsystem/move.js +60 -25
  132. package/dist/commands/subsystem/move.js.map +1 -1
  133. package/dist/commands/subsystem/query.js +2 -4
  134. package/dist/commands/subsystem/query.js.map +1 -1
  135. package/dist/commands/subsystem/subsystem.js +4 -7
  136. package/dist/commands/subsystem/subsystem.js.map +1 -1
  137. package/dist/commands/subsystem/sync.js +141 -71
  138. package/dist/commands/subsystem/sync.js.map +1 -1
  139. package/dist/commands/subsystem/txn/report.js +55 -5
  140. package/dist/commands/subsystem/txn/report.js.map +1 -1
  141. package/dist/commands/subsystem/txn/txn.js +121 -45
  142. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  143. package/dist/commands/subsystem/txn/views.js +82 -12
  144. package/dist/commands/subsystem/txn/views.js.map +1 -1
  145. package/dist/commands/tasks/render.js +116 -0
  146. package/dist/commands/tasks/render.js.map +1 -0
  147. package/dist/commands/tasks/tasks.js +113 -0
  148. package/dist/commands/tasks/tasks.js.map +1 -0
  149. package/dist/commands/unarchive/manifest.js +6 -9
  150. package/dist/commands/unarchive/manifest.js.map +1 -1
  151. package/dist/commands/unarchive/restore.js +17 -28
  152. package/dist/commands/unarchive/restore.js.map +1 -1
  153. package/dist/commands/unarchive/unarchive.js +22 -30
  154. package/dist/commands/unarchive/unarchive.js.map +1 -1
  155. package/dist/commands/validate/arch-coverage.js +6 -15
  156. package/dist/commands/validate/arch-coverage.js.map +1 -1
  157. package/dist/commands/validate/checks/fleet-shape.js +4 -49
  158. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  159. package/dist/commands/validate/checks/health-deps.js +9 -6
  160. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  161. package/dist/commands/validate/checks/requirements.js +18 -8
  162. package/dist/commands/validate/checks/requirements.js.map +1 -1
  163. package/dist/commands/validate/checks/sources.js +6 -2
  164. package/dist/commands/validate/checks/sources.js.map +1 -1
  165. package/dist/commands/validate/feature.js +23 -19
  166. package/dist/commands/validate/feature.js.map +1 -1
  167. package/dist/commands/validate/fleet/census.js +26 -3
  168. package/dist/commands/validate/fleet/census.js.map +1 -1
  169. package/dist/commands/validate/fleet/landscape.js +35 -32
  170. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  171. package/dist/commands/validate/fleet/map/attest.js +7 -12
  172. package/dist/commands/validate/fleet/map/attest.js.map +1 -1
  173. package/dist/commands/validate/fleet/map/bindings.js +16 -5
  174. package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
  175. package/dist/commands/validate/fleet/map/consumers.js +43 -122
  176. package/dist/commands/validate/fleet/map/consumers.js.map +1 -1
  177. package/dist/commands/validate/fleet/map/usecases.js +5 -11
  178. package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
  179. package/dist/commands/validate/fleet/obligations.js +1 -5
  180. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  181. package/dist/commands/validate/fleet/scorecard/print.js +5 -1
  182. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  183. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  184. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  185. package/dist/commands/validate/fleet/usecases/usecases.js +6 -4
  186. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
  187. package/dist/commands/validate/fleet/views/fleet-project.js +1 -1
  188. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
  189. package/dist/commands/validate/fleet/views/ids.js +33 -7
  190. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  191. package/dist/commands/validate/fleet/views/root-documents.js +17 -35
  192. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -1
  193. package/dist/commands/validate/fleet/views/stale.js +31 -14
  194. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  195. package/dist/commands/validate/links/corpus.js +1 -4
  196. package/dist/commands/validate/links/corpus.js.map +1 -1
  197. package/dist/commands/validate/links/glossary.js.map +1 -1
  198. package/dist/commands/validate/report.js +5 -4
  199. package/dist/commands/validate/report.js.map +1 -1
  200. package/dist/commands/validate/scope.js +113 -0
  201. package/dist/commands/validate/scope.js.map +1 -0
  202. package/dist/commands/validate/service/api.js +16 -104
  203. package/dist/commands/validate/service/api.js.map +1 -1
  204. package/dist/commands/validate/service/contracts/generated.js +134 -0
  205. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  206. package/dist/commands/validate/service/events/events.js +1 -1
  207. package/dist/commands/validate/service/events/events.js.map +1 -1
  208. package/dist/commands/validate/service/events/message-producers.js +1 -1
  209. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  210. package/dist/commands/validate/service/evidence-pins.js +56 -10
  211. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  212. package/dist/commands/validate/service/service.js +16 -26
  213. package/dist/commands/validate/service/service.js.map +1 -1
  214. package/dist/commands/validate/service/specs.js +31 -38
  215. package/dist/commands/validate/service/specs.js.map +1 -1
  216. package/dist/commands/validate/service/spine.js +8 -11
  217. package/dist/commands/validate/service/spine.js.map +1 -1
  218. package/dist/commands/validate/service/usecases/usecases.js +3 -3
  219. package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
  220. package/dist/commands/validate/validate.js +44 -26
  221. package/dist/commands/validate/validate.js.map +1 -1
  222. package/dist/commands/verify/cross/diff.js +2 -6
  223. package/dist/commands/verify/cross/diff.js.map +1 -1
  224. package/dist/commands/verify/evidence/contract.js +1 -1
  225. package/dist/commands/verify/evidence/contract.js.map +1 -1
  226. package/dist/commands/verify/evidence/read.js +12 -3
  227. package/dist/commands/verify/evidence/read.js.map +1 -1
  228. package/dist/commands/verify/frozen.js +45 -23
  229. package/dist/commands/verify/frozen.js.map +1 -1
  230. package/dist/commands/verify/record.js +69 -17
  231. package/dist/commands/verify/record.js.map +1 -1
  232. package/dist/commands/verify/report.js +27 -44
  233. package/dist/commands/verify/report.js.map +1 -1
  234. package/dist/commands/verify/results.js +112 -30
  235. package/dist/commands/verify/results.js.map +1 -1
  236. package/dist/commands/verify/verify.js +54 -51
  237. package/dist/commands/verify/verify.js.map +1 -1
  238. package/dist/commands/vouch/pack/pack.js +2 -2
  239. package/dist/commands/vouch/pack/pack.js.map +1 -1
  240. package/dist/commands/vouch/pack/print.js +1 -6
  241. package/dist/commands/vouch/pack/print.js.map +1 -1
  242. package/dist/commands/vouch/pack/sections.js +1 -2
  243. package/dist/commands/vouch/pack/sections.js.map +1 -1
  244. package/dist/commands/vouch/run.js +26 -81
  245. package/dist/commands/vouch/run.js.map +1 -1
  246. package/dist/commands/vouch/sample/plan.js +20 -34
  247. package/dist/commands/vouch/sample/plan.js.map +1 -1
  248. package/dist/commands/vouch/vet/verify.js +39 -7
  249. package/dist/commands/vouch/vet/verify.js.map +1 -1
  250. package/dist/commands/vouch/vouch.js +10 -17
  251. package/dist/commands/vouch/vouch.js.map +1 -1
  252. package/dist/core/agent/agents-md/command-map.js +57 -102
  253. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  254. package/dist/core/agent/agents-md/map/explain.js +4 -3
  255. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  256. package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
  257. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  258. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  259. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  260. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  261. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  262. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  263. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  264. package/dist/core/agent/agents-md/map/status.js +9 -3
  265. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  266. package/dist/core/agent/agents-md/map/subsystem.js +31 -17
  267. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  268. package/dist/core/agent/agents-md/map/usecases.js +24 -6
  269. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  270. package/dist/core/agent/agents-md/refusals.js +37 -21
  271. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  272. package/dist/core/agent/agents-md.js +25 -10
  273. package/dist/core/agent/agents-md.js.map +1 -1
  274. package/dist/core/agent/agents-stamp.js +10 -0
  275. package/dist/core/agent/agents-stamp.js.map +1 -1
  276. package/dist/core/agent/scaffold.js +10 -15
  277. package/dist/core/agent/scaffold.js.map +1 -1
  278. package/dist/core/agent/tools/dialects.js +1 -0
  279. package/dist/core/agent/tools/dialects.js.map +1 -1
  280. package/dist/core/agent/tools/registry.js +41 -76
  281. package/dist/core/agent/tools/registry.js.map +1 -1
  282. package/dist/core/agent/workflows/adopt.js +5 -3
  283. package/dist/core/agent/workflows/adopt.js.map +1 -1
  284. package/dist/core/agent/workflows/check.js +25 -22
  285. package/dist/core/agent/workflows/check.js.map +1 -1
  286. package/dist/core/agent/workflows/closing.js +54 -21
  287. package/dist/core/agent/workflows/closing.js.map +1 -1
  288. package/dist/core/agent/workflows/feature.js +79 -11
  289. package/dist/core/agent/workflows/feature.js.map +1 -1
  290. package/dist/core/agent/workflows/implement.js +91 -13
  291. package/dist/core/agent/workflows/implement.js.map +1 -1
  292. package/dist/core/agent/workflows/reference/authoring.js +3 -1
  293. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  294. package/dist/core/agent/workflows/reference/codes.js +8 -6
  295. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  296. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  297. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  298. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  299. package/dist/core/agent/workflows/reference/spine.js +62 -24
  300. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  301. package/dist/core/asyncapi/baseline/plan.js +14 -81
  302. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  303. package/dist/core/asyncapi/digest.js +30 -25
  304. package/dist/core/asyncapi/digest.js.map +1 -1
  305. package/dist/core/asyncapi/merge/components.js +5 -4
  306. package/dist/core/asyncapi/merge/components.js.map +1 -1
  307. package/dist/core/asyncapi/merge/error.js +7 -2
  308. package/dist/core/asyncapi/merge/error.js.map +1 -1
  309. package/dist/core/asyncapi/merge/markers.js +30 -50
  310. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  311. package/dist/core/asyncapi/merge/merge.js +31 -53
  312. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  313. package/dist/core/asyncapi/merge/pin.js +10 -36
  314. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  315. package/dist/core/asyncapi/model.js.map +1 -1
  316. package/dist/core/asyncapi/read.js +36 -12
  317. package/dist/core/asyncapi/read.js.map +1 -1
  318. package/dist/core/brief/brief.js +30 -25
  319. package/dist/core/brief/brief.js.map +1 -1
  320. package/dist/core/brief/landscape.js +8 -12
  321. package/dist/core/brief/landscape.js.map +1 -1
  322. package/dist/core/brief/map/extend.js +8 -5
  323. package/dist/core/brief/map/extend.js.map +1 -1
  324. package/dist/core/brief/map/owed.js +8 -26
  325. package/dist/core/brief/map/owed.js.map +1 -1
  326. package/dist/core/brief/targets.js +79 -5
  327. package/dist/core/brief/targets.js.map +1 -1
  328. package/dist/core/brief/unchecked.js +1 -1
  329. package/dist/core/brief/unchecked.js.map +1 -1
  330. package/dist/core/c4/likec4.js +147 -16
  331. package/dist/core/c4/likec4.js.map +1 -1
  332. package/dist/core/c4/locate/unlocated.js +150 -0
  333. package/dist/core/c4/locate/unlocated.js.map +1 -0
  334. package/dist/core/c4/parsed/values.js +54 -1
  335. package/dist/core/c4/parsed/values.js.map +1 -1
  336. package/dist/core/c4/prefetch/fleet.js +1 -9
  337. package/dist/core/c4/prefetch/fleet.js.map +1 -1
  338. package/dist/core/c4/project/architecture.js +31 -9
  339. package/dist/core/c4/project/architecture.js.map +1 -1
  340. package/dist/core/c4/project/documents.js +36 -10
  341. package/dist/core/c4/project/documents.js.map +1 -1
  342. package/dist/core/c4/project/load.js +14 -21
  343. package/dist/core/c4/project/load.js.map +1 -1
  344. package/dist/core/c4/project/staged.js +7 -3
  345. package/dist/core/c4/project/staged.js.map +1 -1
  346. package/dist/core/c4/resolve/external.js +51 -0
  347. package/dist/core/c4/resolve/external.js.map +1 -0
  348. package/dist/core/c4/resolve/service.js +25 -1
  349. package/dist/core/c4/resolve/service.js.map +1 -1
  350. package/dist/core/c4/seed/template.js +15 -1
  351. package/dist/core/c4/seed/template.js.map +1 -1
  352. package/dist/core/c4/service-model/shape.js +2 -22
  353. package/dist/core/c4/service-model/shape.js.map +1 -1
  354. package/dist/core/c4/source-mask.js +288 -4
  355. package/dist/core/c4/source-mask.js.map +1 -1
  356. package/dist/core/c4/source-scan.js +203 -147
  357. package/dist/core/c4/source-scan.js.map +1 -1
  358. package/dist/core/c4/splice/authored-source.js +19 -0
  359. package/dist/core/c4/splice/authored-source.js.map +1 -1
  360. package/dist/core/c4/splice/delta-blocks.js +5 -18
  361. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  362. package/dist/core/c4/splice/landscape-merge.js +13 -8
  363. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  364. package/dist/core/c4/splice/model/merge.js +10 -6
  365. package/dist/core/c4/splice/model/merge.js.map +1 -1
  366. package/dist/core/c4/splice/placement.js +108 -18
  367. package/dist/core/c4/splice/placement.js.map +1 -1
  368. package/dist/core/c4/workspace.js +13 -22
  369. package/dist/core/c4/workspace.js.map +1 -1
  370. package/dist/core/capabilities/capabilities.js +6 -6
  371. package/dist/core/capabilities/capabilities.js.map +1 -1
  372. package/dist/core/capabilities/delta/doc.js +7 -10
  373. package/dist/core/capabilities/delta/doc.js.map +1 -1
  374. package/dist/core/capabilities/findings.js +15 -20
  375. package/dist/core/capabilities/findings.js.map +1 -1
  376. package/dist/core/capabilities/realizes/findings.js +12 -19
  377. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  378. package/dist/core/capabilities/realizes/join.js +0 -20
  379. package/dist/core/capabilities/realizes/join.js.map +1 -1
  380. package/dist/core/capabilities/rollup.js +6 -0
  381. package/dist/core/capabilities/rollup.js.map +1 -1
  382. package/dist/core/capabilities/tree.js +6 -28
  383. package/dist/core/capabilities/tree.js.map +1 -1
  384. package/dist/core/capabilities/usecase-join.js +3 -13
  385. package/dist/core/capabilities/usecase-join.js.map +1 -1
  386. package/dist/core/coherence/authoring/scaffold.js +11 -3
  387. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  388. package/dist/core/coherence/authoring/sentinels.js +2 -1
  389. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  390. package/dist/core/coherence/coherence.js +30 -16
  391. package/dist/core/coherence/coherence.js.map +1 -1
  392. package/dist/core/coherence/consumed/operations.js +70 -0
  393. package/dist/core/coherence/consumed/operations.js.map +1 -0
  394. package/dist/core/coherence/consumed/refusal.js +38 -0
  395. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  396. package/dist/core/coherence/declared.js +60 -34
  397. package/dist/core/coherence/declared.js.map +1 -1
  398. package/dist/core/coherence/events/declared.js +44 -59
  399. package/dist/core/coherence/events/declared.js.map +1 -1
  400. package/dist/core/coherence/events/events.js +119 -8
  401. package/dist/core/coherence/events/events.js.map +1 -1
  402. package/dist/core/coherence/events/grades.js +31 -8
  403. package/dist/core/coherence/events/grades.js.map +1 -1
  404. package/dist/core/coherence/events/lookups.js +14 -82
  405. package/dist/core/coherence/events/lookups.js.map +1 -1
  406. package/dist/core/coherence/lookups.js +18 -78
  407. package/dist/core/coherence/lookups.js.map +1 -1
  408. package/dist/core/coherence/retired/archived.js +285 -0
  409. package/dist/core/coherence/retired/archived.js.map +1 -0
  410. package/dist/core/coherence/retired/event-pair.js +62 -0
  411. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  412. package/dist/core/coherence/retired/merged.js +79 -0
  413. package/dist/core/coherence/retired/merged.js.map +1 -0
  414. package/dist/core/coherence/retired/retirement.js +49 -0
  415. package/dist/core/coherence/retired/retirement.js.map +1 -0
  416. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  417. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  418. package/dist/core/coherence/retired/revival/revived.js +297 -0
  419. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  420. package/dist/core/consumers/after.js +113 -0
  421. package/dist/core/consumers/after.js.map +1 -0
  422. package/dist/core/consumers/consumers.js +296 -0
  423. package/dist/core/consumers/consumers.js.map +1 -0
  424. package/dist/core/consumers/current.js +211 -0
  425. package/dist/core/consumers/current.js.map +1 -0
  426. package/dist/core/consumers/scan.js +46 -0
  427. package/dist/core/consumers/scan.js.map +1 -0
  428. package/dist/core/consumers/state.js +27 -0
  429. package/dist/core/consumers/state.js.map +1 -0
  430. package/dist/core/delta/delta.js +1 -1
  431. package/dist/core/delta/delta.js.map +1 -1
  432. package/dist/core/deployment/delta.js +15 -16
  433. package/dist/core/deployment/delta.js.map +1 -1
  434. package/dist/core/diff/base-git.js +94 -12
  435. package/dist/core/diff/base-git.js.map +1 -1
  436. package/dist/core/diff/base-state.js +28 -16
  437. package/dist/core/diff/base-state.js.map +1 -1
  438. package/dist/core/diff/joins.js +136 -0
  439. package/dist/core/diff/joins.js.map +1 -0
  440. package/dist/core/diff/scope/changed-paths.js +22 -6
  441. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  442. package/dist/core/diff/scope/edges.js +82 -0
  443. package/dist/core/diff/scope/edges.js.map +1 -0
  444. package/dist/core/diff/semantic.js +100 -31
  445. package/dist/core/diff/semantic.js.map +1 -1
  446. package/dist/core/doctor/agents.js +34 -18
  447. package/dist/core/doctor/agents.js.map +1 -1
  448. package/dist/core/doctor/report.js.map +1 -1
  449. package/dist/core/document/apply.js +10 -2
  450. package/dist/core/document/apply.js.map +1 -1
  451. package/dist/core/document/frontmatter.js +55 -0
  452. package/dist/core/document/frontmatter.js.map +1 -1
  453. package/dist/core/document/parse.js +29 -6
  454. package/dist/core/document/parse.js.map +1 -1
  455. package/dist/core/document/scenarios.js +17 -0
  456. package/dist/core/document/scenarios.js.map +1 -1
  457. package/dist/core/document/spec.js +4 -11
  458. package/dist/core/document/spec.js.map +1 -1
  459. package/dist/core/envelope/config.js +10 -0
  460. package/dist/core/envelope/config.js.map +1 -1
  461. package/dist/core/envelope/json.js +34 -0
  462. package/dist/core/envelope/json.js.map +1 -1
  463. package/dist/core/explain/families.js +17 -12
  464. package/dist/core/explain/families.js.map +1 -1
  465. package/dist/core/explain/refusals.js +3 -3
  466. package/dist/core/explain/refusals.js.map +1 -1
  467. package/dist/core/explain/terms.js +18 -9
  468. package/dist/core/explain/terms.js.map +1 -1
  469. package/dist/core/explore/explore.js +2 -7
  470. package/dist/core/explore/explore.js.map +1 -1
  471. package/dist/core/fleet-context.js +34 -95
  472. package/dist/core/fleet-context.js.map +1 -1
  473. package/dist/core/gate/checks.js +10 -3
  474. package/dist/core/gate/checks.js.map +1 -1
  475. package/dist/core/gate/partners.js +64 -19
  476. package/dist/core/gate/partners.js.map +1 -1
  477. package/dist/core/gate/report.js.map +1 -1
  478. package/dist/core/gate/verification.js +75 -12
  479. package/dist/core/gate/verification.js.map +1 -1
  480. package/dist/core/gherkin/stale.js +13 -37
  481. package/dist/core/gherkin/stale.js.map +1 -1
  482. package/dist/core/glossary/tree.js +6 -19
  483. package/dist/core/glossary/tree.js.map +1 -1
  484. package/dist/core/kernel/concurrency.js +19 -0
  485. package/dist/core/kernel/concurrency.js.map +1 -1
  486. package/dist/core/kernel/records.js +11 -0
  487. package/dist/core/kernel/records.js.map +1 -1
  488. package/dist/core/links/backlinks.js +1 -3
  489. package/dist/core/links/backlinks.js.map +1 -1
  490. package/dist/core/links/corpus.js +5 -36
  491. package/dist/core/links/corpus.js.map +1 -1
  492. package/dist/core/mcp/argv.js +101 -0
  493. package/dist/core/mcp/argv.js.map +1 -1
  494. package/dist/core/mcp/author-tools.js +2 -1
  495. package/dist/core/mcp/author-tools.js.map +1 -1
  496. package/dist/core/mcp/protocol.js +2 -2
  497. package/dist/core/mcp/protocol.js.map +1 -1
  498. package/dist/core/mcp/tools.js +43 -33
  499. package/dist/core/mcp/tools.js.map +1 -1
  500. package/dist/core/openapi/baseline/gate.js +53 -12
  501. package/dist/core/openapi/baseline/gate.js.map +1 -1
  502. package/dist/core/openapi/baseline/plan.js +22 -8
  503. package/dist/core/openapi/baseline/plan.js.map +1 -1
  504. package/dist/core/openapi/baseline/record.js +0 -1
  505. package/dist/core/openapi/baseline/record.js.map +1 -1
  506. package/dist/core/openapi/contract-text.js +33 -0
  507. package/dist/core/openapi/contract-text.js.map +1 -0
  508. package/dist/core/openapi/contract-tree.js +56 -0
  509. package/dist/core/openapi/contract-tree.js.map +1 -0
  510. package/dist/core/openapi/depth.js +38 -24
  511. package/dist/core/openapi/depth.js.map +1 -1
  512. package/dist/core/openapi/digest.js +52 -2
  513. package/dist/core/openapi/digest.js.map +1 -1
  514. package/dist/core/openapi/doc.js +12 -4
  515. package/dist/core/openapi/doc.js.map +1 -1
  516. package/dist/core/openapi/merge/components.js +25 -60
  517. package/dist/core/openapi/merge/components.js.map +1 -1
  518. package/dist/core/openapi/merge/error.js +3 -13
  519. package/dist/core/openapi/merge/error.js.map +1 -1
  520. package/dist/core/openapi/merge/markers.js +26 -30
  521. package/dist/core/openapi/merge/markers.js.map +1 -1
  522. package/dist/core/openapi/merge/merge.js +26 -52
  523. package/dist/core/openapi/merge/merge.js.map +1 -1
  524. package/dist/core/openapi/merge/pin.js +15 -35
  525. package/dist/core/openapi/merge/pin.js.map +1 -1
  526. package/dist/core/openspec/decide/verdict.js.map +1 -1
  527. package/dist/core/openspec/inventory.js +4 -5
  528. package/dist/core/openspec/inventory.js.map +1 -1
  529. package/dist/core/openspec/model/mapping.js +30 -28
  530. package/dist/core/openspec/model/mapping.js.map +1 -1
  531. package/dist/core/openspec/model/model.js +12 -7
  532. package/dist/core/openspec/model/model.js.map +1 -1
  533. package/dist/core/openspec/scan/changes.js +10 -4
  534. package/dist/core/openspec/scan/changes.js.map +1 -1
  535. package/dist/core/openspec/scan/config.js +7 -16
  536. package/dist/core/openspec/scan/config.js.map +1 -1
  537. package/dist/core/openspec/scan/shape.js +63 -19
  538. package/dist/core/openspec/scan/shape.js.map +1 -1
  539. package/dist/core/openspec/scan/walk.js +21 -38
  540. package/dist/core/openspec/scan/walk.js.map +1 -1
  541. package/dist/core/pack/living.js +2 -16
  542. package/dist/core/pack/living.js.map +1 -1
  543. package/dist/core/provenance/findings.js +48 -12
  544. package/dist/core/provenance/findings.js.map +1 -1
  545. package/dist/core/provenance/git.js +33 -57
  546. package/dist/core/provenance/git.js.map +1 -1
  547. package/dist/core/provenance/gitq/moves.js +71 -114
  548. package/dist/core/provenance/gitq/moves.js.map +1 -1
  549. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  550. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  551. package/dist/core/provenance/sources.js +23 -6
  552. package/dist/core/provenance/sources.js.map +1 -1
  553. package/dist/core/provenance/stamp.js +5 -17
  554. package/dist/core/provenance/stamp.js.map +1 -1
  555. package/dist/core/repo/entries.js.map +1 -1
  556. package/dist/core/repo/paths.js +34 -29
  557. package/dist/core/repo/paths.js.map +1 -1
  558. package/dist/core/repo/repo.js +24 -14
  559. package/dist/core/repo/repo.js.map +1 -1
  560. package/dist/core/repo/tree/find.js +12 -3
  561. package/dist/core/repo/tree/find.js.map +1 -1
  562. package/dist/core/repo/tree/fs.js +27 -1
  563. package/dist/core/repo/tree/fs.js.map +1 -1
  564. package/dist/core/repo/tree/render/body.js +45 -6
  565. package/dist/core/repo/tree/render/body.js.map +1 -1
  566. package/dist/core/repo/tree/render/service/header.js +125 -0
  567. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  568. package/dist/core/repo/tree/render/service/peers.js +28 -0
  569. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  570. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  571. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  572. package/dist/core/repo/tree/render/service/views.js +78 -0
  573. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  574. package/dist/core/repo/tree/render/stale.js +19 -2
  575. package/dist/core/repo/tree/render/stale.js.map +1 -1
  576. package/dist/core/repo/tree/render/views.js +102 -33
  577. package/dist/core/repo/tree/render/views.js.map +1 -1
  578. package/dist/core/repo/tree/walk.js +8 -30
  579. package/dist/core/repo/tree/walk.js.map +1 -1
  580. package/dist/core/results.js +47 -12
  581. package/dist/core/results.js.map +1 -1
  582. package/dist/core/staging/commit.js +10 -12
  583. package/dist/core/staging/commit.js.map +1 -1
  584. package/dist/core/staging/lock.js +74 -12
  585. package/dist/core/staging/lock.js.map +1 -1
  586. package/dist/core/staging/recovery/intent.js +2 -5
  587. package/dist/core/staging/recovery/intent.js.map +1 -1
  588. package/dist/core/staging/recovery/recover.js +60 -1
  589. package/dist/core/staging/recovery/recover.js.map +1 -1
  590. package/dist/core/staging/snapshot/manifest.js +152 -0
  591. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  592. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
  593. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  594. package/dist/core/status/actions/execution.js +11 -0
  595. package/dist/core/status/actions/execution.js.map +1 -1
  596. package/dist/core/status/feature/artifacts.js +2 -2
  597. package/dist/core/status/feature/artifacts.js.map +1 -1
  598. package/dist/core/status/feature/feature.js +5 -11
  599. package/dist/core/status/feature/feature.js.map +1 -1
  600. package/dist/core/status/fleet/fleet.js +6 -2
  601. package/dist/core/status/fleet/fleet.js.map +1 -1
  602. package/dist/core/status/fleet/next.js +26 -3
  603. package/dist/core/status/fleet/next.js.map +1 -1
  604. package/dist/core/status/report.js.map +1 -1
  605. package/dist/core/status/verification.js +30 -15
  606. package/dist/core/status/verification.js.map +1 -1
  607. package/dist/core/tasks/packet.js +174 -0
  608. package/dist/core/tasks/packet.js.map +1 -0
  609. package/dist/core/tasks/record.js +43 -0
  610. package/dist/core/tasks/record.js.map +1 -0
  611. package/dist/core/tasks/sources.js +181 -0
  612. package/dist/core/tasks/sources.js.map +1 -0
  613. package/dist/core/tasks/stamps.js +76 -0
  614. package/dist/core/tasks/stamps.js.map +1 -0
  615. package/dist/core/tasks/unit.js +0 -0
  616. package/dist/core/tasks/unit.js.map +1 -0
  617. package/dist/core/usecases/capability.js +11 -14
  618. package/dist/core/usecases/capability.js.map +1 -1
  619. package/dist/core/usecases/delta/flows.js +5 -7
  620. package/dist/core/usecases/delta/flows.js.map +1 -1
  621. package/dist/core/usecases/fleet.js +178 -31
  622. package/dist/core/usecases/fleet.js.map +1 -1
  623. package/dist/core/usecases/operations.js +5 -4
  624. package/dist/core/usecases/operations.js.map +1 -1
  625. package/dist/core/usecases/service/flows.js +9 -6
  626. package/dist/core/usecases/service/flows.js.map +1 -1
  627. package/dist/core/usecases/suites/participants.js +83 -0
  628. package/dist/core/usecases/suites/participants.js.map +1 -0
  629. package/dist/core/usecases/suites/suites.js +45 -0
  630. package/dist/core/usecases/suites/suites.js.map +1 -0
  631. package/dist/core/verify/answers.js +12 -5
  632. package/dist/core/verify/answers.js.map +1 -1
  633. package/dist/core/verify/build.js +102 -82
  634. package/dist/core/verify/build.js.map +1 -1
  635. package/dist/core/verify/checklist.js +45 -10
  636. package/dist/core/verify/checklist.js.map +1 -1
  637. package/dist/core/verify/location.js +67 -0
  638. package/dist/core/verify/location.js.map +1 -0
  639. package/dist/core/verify/pins/lint.js +3 -2
  640. package/dist/core/verify/pins/lint.js.map +1 -1
  641. package/dist/core/verify/pins/pin.js +1 -1
  642. package/dist/core/verify/pins/pin.js.map +1 -1
  643. package/dist/core/verify/read/file.js +224 -0
  644. package/dist/core/verify/read/file.js.map +1 -0
  645. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  646. package/dist/core/verify/read/shape.js.map +1 -0
  647. package/dist/core/verify/read/union.js +105 -0
  648. package/dist/core/verify/read/union.js.map +1 -0
  649. package/dist/core/verify/record.js +35 -12
  650. package/dist/core/verify/record.js.map +1 -1
  651. package/dist/core/verify/store/commit.js +40 -30
  652. package/dist/core/verify/store/commit.js.map +1 -1
  653. package/dist/core/verify/store/render.js +8 -4
  654. package/dist/core/verify/store/render.js.map +1 -1
  655. package/dist/core/vocabulary/issue.js +1 -0
  656. package/dist/core/vocabulary/issue.js.map +1 -1
  657. package/dist/core/vocabulary/maturity.js +53 -3
  658. package/dist/core/vocabulary/maturity.js.map +1 -1
  659. package/examples/README.md +28 -9
  660. package/examples/docs/architecture/landscape.likec4 +21 -7
  661. package/examples/docs/architecture/services.likec4 +70 -0
  662. package/examples/docs/architecture/subsystems.likec4 +3 -0
  663. package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
  664. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  665. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  666. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  667. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  668. package/examples/docs/services/order-service/model.likec4 +10 -8
  669. package/examples/docs/services/payment-service/model.likec4 +6 -4
  670. package/examples/docs/services/platform/identity-service/model.likec4 +9 -7
  671. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  672. package/examples/docs/services/platform/notification-service/model.likec4 +4 -5
  673. package/package.json +1 -1
  674. package/dist/commands/validate/checks/vocabulary.js +0 -16
  675. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  676. package/dist/core/agent/agents-md/artifacts.js +0 -221
  677. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  678. package/dist/core/agent/agents-md/cycle.js +0 -180
  679. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  680. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  681. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  682. package/dist/core/agent/agents-md/spine.js +0 -40
  683. package/dist/core/agent/agents-md/spine.js.map +0 -1
  684. package/dist/core/coherence/events/merged.js +0 -40
  685. package/dist/core/coherence/events/merged.js.map +0 -1
  686. package/dist/core/diff/current-state.js +0 -96
  687. package/dist/core/diff/current-state.js.map +0 -1
  688. package/dist/core/diff/victims.js +0 -256
  689. package/dist/core/diff/victims.js.map +0 -1
  690. package/dist/core/staging/snapshot.js.map +0 -1
  691. package/dist/core/verify/file.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/commands/subsystem/edit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two verbs that create and remove GROUPS: `subsystem new` and\n * `subsystem rm`. Both commit the marker AND the regenerated views file in\n * one journaled transaction, because a marker without its view (or a view\n * outliving its marker) is exactly the `subsystem.views-stale` state the\n * generated file's contract refuses to leave behind.\n *\n * `rm` refuses a subsystem with members — services, child subsystems, or any\n * stray non-dot entry beside the marker the tree does not already count —\n * naming each once, as what it is (`subsystem-not-empty`):\n * a destructive command never picks targets the caller did not name, and a\n * directory emptied of its marker but not of its contents would re-enter the\n * walk as a phantom service.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir, rmdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { parseSubsystemName } from \"../../core/kernel/ids/subsystem.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { servicesDir, subsystemPathUnder } from \"../../core/repo/paths.js\";\nimport { findInTree, nearestTreeNames, servicesUnder, subsystemsUnder } from \"../../core/repo/tree/find.js\";\nimport { entryIs } from \"../../core/repo/tree/fs.js\";\nimport { SUBSYSTEM_MARKER } from \"../../core/repo/tree/marker.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport { planWrite } from \"../../core/staging/writes.js\";\nimport { commitWindow, reportViews, type SubsystemTxn } from \"./txn/txn.js\";\nimport type { SubsystemOptions } from \"./subsystem.js\";\n\n/** `subsystem new <name> [--under <parent>] [--title …] [--description …] [--owner …]` */\nexport async function runNew(\n docsDir: DocsDir,\n name: string,\n opts: SubsystemOptions,\n json: boolean,\n): Promise<void> {\n const parsed = parseSubsystemName(name, \"subsystem name\");\n if (!parsed.ok) {\n fail(json, \"invalid-option\", parsed.problem);\n return;\n }\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n // The flat namespace: one name, one meaning, at any depth — a `new` that\n // collides with ANY service or subsystem would be the exact state\n // `subsystem.name-collision` refuses after the fact.\n const taken = findInTree(tree, name);\n if (taken !== null) {\n const where = taken.kind === \"service\" ? taken.service.dir : taken.subsystem.dir;\n fail(\n json,\n \"already-exists\",\n `'${name}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — ` +\n `service ids and subsystem names share one flat namespace, unique at any depth. Pick another name.`,\n );\n return null;\n }\n let parentDir = servicesDir(docsDir);\n let parentPath: string[] = [];\n if (opts.under !== undefined) {\n const parent = findInTree(tree, opts.under);\n if (parent === null) {\n const close = nearestTreeNames(opts.under, tree.subsystems.map((s) => s.name));\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${opts.under}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n if (parent.kind === \"service\") {\n fail(json, \"invalid-option\", `--under names the service '${opts.under}' — a service never contains subsystems.`);\n return null;\n }\n parentDir = parent.subsystem.dir;\n parentPath = parent.subsystem.path;\n }\n const dir = subsystemPathUnder(parentDir, parsed.name);\n // The flat-namespace check above compares exact strings; the FILESYSTEM\n // may not. On a case-folding volume (macOS APFS by default) `Billing`\n // and an existing `services/billing` are one directory, so the marker\n // write below would land subsystem.yaml INSIDE the live service — the\n // exact marker-beside-artifacts state `subsystem.marker-misplaced`\n // refuses after the fact, created by a blessed command. A plain file of\n // the same name reaches here too (files at the root are not walked). So\n // the disk is probed directly and anything already there refuses closed.\n if (existsSync(dir)) {\n fail(\n json,\n \"already-exists\",\n `${repoPath(docsDir, dir)} already exists on disk — the tree resolves no entry by that exact name, ` +\n `so either this filesystem folds case (the directory answers to another spelling of the name) ` +\n `or something non-loam created it. Pick another name, or move what is there first. Nothing was created.`,\n );\n return null;\n }\n const meta = {\n ...(opts.title === undefined ? {} : { title: opts.title }),\n ...(opts.description === undefined ? {} : { description: opts.description }),\n ...(opts.owner === undefined ? {} : { owner: opts.owner }),\n };\n // An empty file is a valid marker — presence classifies, content is metadata.\n const marker = Object.keys(meta).length === 0 ? \"\" : stringify(meta);\n const after: FleetTree = {\n ...tree,\n subsystems: [...tree.subsystems, { name, path: [...parentPath, name], dir, meta }],\n };\n return {\n target: name,\n writes: [planWrite(join(dir, SUBSYSTEM_MARKER), marker)],\n tree: after,\n // A lost exclusive-create race on the marker IS the name being taken.\n racedCode: \"already-exists\",\n what: \"created\",\n report: (views, recovered) => {\n if (json) {\n emitJson({\n command: \"subsystem\",\n created: name,\n path: repoPath(docsDir, dir),\n views,\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`created ${repoPath(docsDir, dir)}/ (${SUBSYSTEM_MARKER} written)${reportViews(views)}`);\n },\n };\n });\n}\n\n/** `subsystem rm <name>` — refuses anything but an empty group. */\nexport async function runRm(docsDir: DocsDir, name: string, json: boolean): Promise<void> {\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const hit = findInTree(tree, name);\n if (hit === null) {\n const close = nearestTreeNames(name, tree.subsystems.map((s) => s.name));\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${name}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(\n json,\n \"invalid-option\",\n `'${name}' is a service, not a subsystem — loam does not delete services (\\`git rm -r ${repoPath(docsDir, hit.service.dir)}\\` does, and version control keeps the record).`,\n );\n return null;\n }\n const sub = hit.subsystem;\n const services = servicesUnder(tree, sub).map((s) => s.id);\n const children = subsystemsUnder(tree, sub).map((s) => s.name);\n // Stray entries beside the marker count as members too: after the marker\n // is gone the directory would re-enter the walk as an empty \"service\" the\n // moment anything keeps rmdir from removing it. But only entries the tree\n // has NOT already counted — a member service or child subsystem is also a\n // readdir entry here, and listing it a second time as \"file X\" made the\n // count wrong and the same name appear under two kinds. What remains is\n // discriminated by what it is (`entryIs`, the walk's own symlink-aware\n // question): a file, or a directory the tree does not claim (an unmarked\n // group, already its own `subsystem.unmarked` finding).\n const counted = new Set<string>([\n ...servicesUnder(tree, sub).filter((s) => s.subsystem.length === sub.path.length).map((s) => s.id as string),\n ...subsystemsUnder(tree, sub).filter((c) => c.path.length === sub.path.length + 1).map((c) => c.name),\n ]);\n const strays = (await readdir(sub.dir, { withFileTypes: true }))\n .filter((e) => !e.name.startsWith(\".\") && e.name !== SUBSYSTEM_MARKER && !counted.has(e.name))\n .map((e) => `${entryIs(sub.dir, e, \"dir\") ? \"directory\" : \"file\"} ${e.name}`);\n const members = [\n ...services.map((s) => `service ${s}`),\n ...children.map((c) => `subsystem ${c}`),\n ...strays,\n ];\n if (members.length > 0) {\n fail(\n json,\n \"subsystem-not-empty\",\n `'${name}' still holds ${members.length} member(s): ${members.join(\", \")}. ` +\n \"`loam subsystem move <name>... --into <sub|.>` moves them out; a destructive command never picks targets you did not name.\",\n );\n return null;\n }\n const after: FleetTree = { ...tree, subsystems: tree.subsystems.filter((s) => s !== sub) };\n return {\n target: name,\n writes: [{ path: join(sub.dir, SUBSYSTEM_MARKER), content: null }],\n tree: after,\n what: \"removed\",\n report: async (views, recovered) => {\n // The directory itself, after the transaction: the marker is gone, the\n // group was verifiably empty, and an empty marker-less directory would\n // read as an unfiled service. Dotfile litter (.DS_Store) can still\n // defeat rmdir — reported, not swallowed.\n let directoryRemoved = true;\n try {\n await rmdir(sub.dir);\n } catch {\n directoryRemoved = !existsSync(sub.dir);\n }\n if (json) {\n emitJson({\n command: \"subsystem\",\n removed: name,\n path: repoPath(docsDir, sub.dir),\n directoryRemoved,\n views,\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`removed subsystem '${name}' (${repoPath(docsDir, sub.dir)}/)${reportViews(views)}`);\n if (!directoryRemoved) {\n console.log(\n `note: the directory itself could not be removed (something non-loam is still inside) — ` +\n `until it is deleted by hand it will list as an empty unfiled service.`,\n );\n }\n },\n };\n });\n}\n"]}
1
+ {"version":3,"file":"edit.js","sourceRoot":"","sources":["../../../src/commands/subsystem/edit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The two verbs that create and remove GROUPS: `subsystem new` and\n * `subsystem rm`. Both commit the marker AND the regenerated views file in\n * one journaled transaction, because a marker without its view (or a view\n * outliving its marker) is exactly the `subsystem.views-stale` state the\n * generated file's contract refuses to leave behind.\n *\n * `rm` refuses a subsystem with members — services, child subsystems, or any\n * stray non-dot entry beside the marker the tree does not already count —\n * naming each once, as what it is (`subsystem-not-empty`):\n * a destructive command never picks targets the caller did not name, and a\n * directory emptied of its marker but not of its contents would re-enter the\n * walk as a phantom service.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir, rmdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stringify } from \"yaml\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { parseSubsystemName } from \"../../core/kernel/ids/subsystem.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { servicesDir, subsystemPathUnder } from \"../../core/repo/paths.js\";\nimport { closeNamesHint, findInTree, servicesUnder, subsystemsUnder } from \"../../core/repo/tree/find.js\";\nimport { entryIs } from \"../../core/repo/tree/fs.js\";\nimport { SUBSYSTEM_MARKER } from \"../../core/repo/tree/marker.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport { planWrite } from \"../../core/staging/writes.js\";\nimport { commitWindow, reportViews, type SubsystemTxn } from \"./txn/txn.js\";\nimport type { SubsystemOptions } from \"./subsystem.js\";\n\n/** `subsystem new <name> [--under <parent>] [--title …] [--description …] [--owner …]` */\nexport async function runNew(\n docsDir: DocsDir,\n name: string,\n opts: SubsystemOptions,\n json: boolean,\n): Promise<void> {\n const parsed = parseSubsystemName(name, \"subsystem name\");\n if (!parsed.ok) {\n fail(json, \"invalid-option\", parsed.problem);\n return;\n }\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n // The flat namespace: one name, one meaning, at any depth — a `new` that\n // collides with ANY service or subsystem would be the exact state\n // `subsystem.name-collision` refuses after the fact.\n const taken = findInTree(tree, name);\n if (taken !== null) {\n const where = taken.kind === \"service\" ? taken.service.dir : taken.subsystem.dir;\n fail(\n json,\n \"already-exists\",\n `'${name}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — ` +\n `service ids and subsystem names share one flat namespace, unique at any depth. Pick another name.`,\n );\n return null;\n }\n let parentDir = servicesDir(docsDir);\n let parentPath: string[] = [];\n if (opts.under !== undefined) {\n const parent = findInTree(tree, opts.under);\n if (parent === null) {\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${opts.under}' in the tree.` +\n closeNamesHint(opts.under, tree.subsystems.map((s) => s.name), \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n if (parent.kind === \"service\") {\n fail(json, \"invalid-option\", `--under names the service '${opts.under}' — a service never contains subsystems.`);\n return null;\n }\n parentDir = parent.subsystem.dir;\n parentPath = parent.subsystem.path;\n }\n const dir = subsystemPathUnder(parentDir, parsed.name);\n // The flat-namespace check above compares exact strings; the FILESYSTEM\n // may not. On a case-folding volume (macOS APFS by default) `Billing`\n // and an existing `services/billing` are one directory, so the marker\n // write below would land subsystem.yaml INSIDE the live service — the\n // exact marker-beside-artifacts state `subsystem.marker-misplaced`\n // refuses after the fact, created by a blessed command. A plain file of\n // the same name reaches here too (files at the root are not walked). So\n // the disk is probed directly and anything already there refuses closed.\n if (existsSync(dir)) {\n fail(\n json,\n \"already-exists\",\n `${repoPath(docsDir, dir)} already exists on disk — the tree resolves no entry by that exact name, ` +\n `so either this filesystem folds case (the directory answers to another spelling of the name) ` +\n `or something non-loam created it. Pick another name, or move what is there first. Nothing was created.`,\n );\n return null;\n }\n const meta = {\n ...(opts.title === undefined ? {} : { title: opts.title }),\n ...(opts.description === undefined ? {} : { description: opts.description }),\n ...(opts.owner === undefined ? {} : { owner: opts.owner }),\n };\n // An empty file is a valid marker — presence classifies, content is metadata.\n const marker = Object.keys(meta).length === 0 ? \"\" : stringify(meta);\n const after: FleetTree = {\n ...tree,\n subsystems: [...tree.subsystems, { name, path: [...parentPath, name], dir, meta }],\n };\n return {\n target: name,\n writes: [planWrite(join(dir, SUBSYSTEM_MARKER), marker)],\n tree: after,\n // A lost exclusive-create race on the marker IS the name being taken.\n racedCode: \"already-exists\",\n what: \"created\",\n report: (views, recovered) => {\n if (json) {\n emitJson({\n command: \"subsystem\",\n created: name,\n path: repoPath(docsDir, dir),\n views: views.subsystems,\n serviceViews: views.services,\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`created ${repoPath(docsDir, dir)}/ (${SUBSYSTEM_MARKER} written)${reportViews(views)}`);\n },\n };\n });\n}\n\n/** `subsystem rm <name>` — refuses anything but an empty group. */\nexport async function runRm(docsDir: DocsDir, name: string, json: boolean): Promise<void> {\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const hit = findInTree(tree, name);\n if (hit === null) {\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${name}' in the tree.` +\n closeNamesHint(name, tree.subsystems.map((s) => s.name), \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(\n json,\n \"invalid-option\",\n `'${name}' is a service, not a subsystem — loam does not delete services (\\`git rm -r ${repoPath(docsDir, hit.service.dir)}\\` does, and version control keeps the record).`,\n );\n return null;\n }\n const sub = hit.subsystem;\n const services = servicesUnder(tree, sub).map((s) => s.id);\n const children = subsystemsUnder(tree, sub).map((s) => s.name);\n // Stray entries beside the marker count as members too: after the marker\n // is gone the directory would re-enter the walk as an empty \"service\" the\n // moment anything keeps rmdir from removing it. But only entries the tree\n // has NOT already counted — a member service or child subsystem is also a\n // readdir entry here, and listing it a second time as \"file X\" made the\n // count wrong and the same name appear under two kinds. What remains is\n // discriminated by what it is (`entryIs`, the walk's own symlink-aware\n // question): a file, or a directory the tree does not claim (an unmarked\n // group, already its own `subsystem.unmarked` finding).\n const counted = new Set<string>([\n ...servicesUnder(tree, sub).filter((s) => s.subsystem.length === sub.path.length).map((s) => s.id as string),\n ...subsystemsUnder(tree, sub).filter((c) => c.path.length === sub.path.length + 1).map((c) => c.name),\n ]);\n const strays = (await readdir(sub.dir, { withFileTypes: true }))\n .filter((e) => !e.name.startsWith(\".\") && e.name !== SUBSYSTEM_MARKER && !counted.has(e.name))\n .map((e) => `${entryIs(sub.dir, e, \"dir\") ? \"directory\" : \"file\"} ${e.name}`);\n const members = [\n ...services.map((s) => `service ${s}`),\n ...children.map((c) => `subsystem ${c}`),\n ...strays,\n ];\n if (members.length > 0) {\n fail(\n json,\n \"subsystem-not-empty\",\n `'${name}' still holds ${members.length} member(s): ${members.join(\", \")}. ` +\n \"`loam subsystem move <name>... --into <sub|.>` moves them out; a destructive command never picks targets you did not name.\",\n );\n return null;\n }\n const after: FleetTree = { ...tree, subsystems: tree.subsystems.filter((s) => s !== sub) };\n return {\n target: name,\n writes: [{ path: join(sub.dir, SUBSYSTEM_MARKER), content: null }],\n tree: after,\n what: \"removed\",\n report: async (views, recovered) => {\n // The directory itself, after the transaction: the marker is gone, the\n // group was verifiably empty, and an empty marker-less directory would\n // read as an unfiled service. Dotfile litter (.DS_Store) can still\n // defeat rmdir — reported, not swallowed.\n let directoryRemoved = true;\n try {\n await rmdir(sub.dir);\n } catch {\n directoryRemoved = !existsSync(sub.dir);\n }\n if (json) {\n emitJson({\n command: \"subsystem\",\n removed: name,\n path: repoPath(docsDir, sub.dir),\n directoryRemoved,\n views: views.subsystems,\n serviceViews: views.services,\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`removed subsystem '${name}' (${repoPath(docsDir, sub.dir)}/)${reportViews(views)}`);\n if (!directoryRemoved) {\n console.log(\n `note: the directory itself could not be removed (something non-loam is still inside) — ` +\n `until it is deleted by hand it will list as an empty unfiled service.`,\n );\n }\n },\n };\n });\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `subsystem move` and `subsystem rename` — ONE transaction over N directory
3
- * renames plus the generated views file, the first real consumer of the
3
+ * renames plus BOTH generated views files, the first real consumer of the
4
4
  * journaled txn's moves half (`core/staging/txn/`). The planning lives in
5
5
  * this module; the commit window itself is `./txn/txn.ts`, shared with
6
6
  * `new` and `rm`.
@@ -9,7 +9,7 @@
9
9
  * uncommitted changes under a directory being moved — and only on positive
10
10
  * evidence: where git will not say, the move proceeds. After a landed move
11
11
  * loam performs the roadmap's one blessed git write, a best-effort `git add`
12
- * of the rename pairs and the regenerated views file, so git records the
12
+ * of the rename pairs and of BOTH regenerated views files, so git records the
13
13
  * renames as renames and `subsystem history` stays answerable once the user
14
14
  * commits. Nothing is ever committed.
15
15
  */
@@ -20,10 +20,10 @@ import { parseSubsystemName } from "../../core/kernel/ids/subsystem.js";
20
20
  import { isRecord } from "../../core/kernel/records.js";
21
21
  import { emitJson, fail, repoPath } from "../../core/envelope/json.js";
22
22
  import { gitDirtyPaths, gitStageRenames } from "../../core/provenance/gitq/moves.js";
23
- import { servicesDir, subsystemPathUnder, subsystemViewsPath } from "../../core/repo/paths.js";
23
+ import { servicesDir, serviceViewsPath, subsystemPathUnder, subsystemViewsPath } from "../../core/repo/paths.js";
24
24
  import { listFeatures } from "../../core/repo/repo.js";
25
- import { findInTree, nearestTreeNames, treeNames, withinSubsystem } from "../../core/repo/tree/find.js";
26
- import { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from "../../core/staging/snapshot.js";
25
+ import { closeNamesHint, findInTree, treeNames, withinSubsystem } from "../../core/repo/tree/find.js";
26
+ import { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from "../../core/staging/snapshot/manifest.js";
27
27
  import { commitWindow, reportViews } from "./txn/txn.js";
28
28
  import { movedTree } from "./txn/views.js";
29
29
  /** `subsystem move <name>... --into <sub|.>` — services and whole subtrees alike. */
@@ -44,9 +44,8 @@ export async function runMove(docsDir, names, into, json) {
44
44
  for (const name of names) {
45
45
  const hit = findInTree(tree, name);
46
46
  if (hit === null) {
47
- const close = nearestTreeNames(name, treeNames(tree));
48
47
  fail(json, "unknown-target", `No service or subsystem '${name}' in the tree.` +
49
- (close.length > 0 ? ` Close names: ${close.join(", ")}.` : " `loam subsystem list` shows what exists."));
48
+ closeNamesHint(name, treeNames(tree), " `loam subsystem list` shows what exists."));
50
49
  return null;
51
50
  }
52
51
  moved.push(hit.kind === "service"
@@ -87,7 +86,7 @@ export async function runMove(docsDir, names, into, json) {
87
86
  failedCode: "move-failed",
88
87
  what: "moved",
89
88
  report: async (views, recovered) => {
90
- await stageInGit(docsDir, renames);
89
+ await stageInGit(docsDir, renames, views);
91
90
  const rows = moved.map((m, i) => ({
92
91
  name: m.name,
93
92
  kind: m.kind,
@@ -99,7 +98,8 @@ export async function runMove(docsDir, names, into, json) {
99
98
  command: "subsystem",
100
99
  into,
101
100
  moved: rows,
102
- views,
101
+ views: views.subsystems,
102
+ serviceViews: views.services,
103
103
  ...(notices.length === 0 ? {} : { warnings: notices }),
104
104
  ...(recovered === null ? {} : { recovered }),
105
105
  });
@@ -120,8 +120,7 @@ export async function runRename(docsDir, names, json) {
120
120
  await commitWindow(docsDir, json, async (tree) => {
121
121
  const hit = findInTree(tree, from);
122
122
  if (hit === null) {
123
- const close = nearestTreeNames(from, tree.subsystems.map((s) => s.name));
124
- fail(json, "unknown-target", `No subsystem '${from}' in the tree.` + (close.length > 0 ? ` Close names: ${close.join(", ")}.` : ""));
123
+ fail(json, "unknown-target", `No subsystem '${from}' in the tree.` + closeNamesHint(from, tree.subsystems.map((s) => s.name), ""));
125
124
  return null;
126
125
  }
127
126
  if (hit.kind === "service") {
@@ -151,14 +150,15 @@ export async function runRename(docsDir, names, json) {
151
150
  failedCode: "move-failed",
152
151
  what: "renamed",
153
152
  report: async (views, recovered) => {
154
- await stageInGit(docsDir, [rename]);
153
+ await stageInGit(docsDir, [rename], views);
155
154
  if (json) {
156
155
  emitJson({
157
156
  command: "subsystem",
158
157
  renamed: from,
159
158
  to,
160
159
  path: repoPath(docsDir, rename.to),
161
- views,
160
+ views: views.subsystems,
161
+ serviceViews: views.services,
162
162
  ...(notices.length === 0 ? {} : { warnings: notices }),
163
163
  ...(recovered === null ? {} : { recovered }),
164
164
  });
@@ -177,9 +177,8 @@ function resolveTarget(tree, into, at) {
177
177
  return { dir: servicesDir(at.docsDir), path: [] };
178
178
  const hit = findInTree(tree, into);
179
179
  if (hit === null) {
180
- const close = nearestTreeNames(into, tree.subsystems.map((s) => s.name));
181
180
  fail(at.json, "unknown-target", `No subsystem '${into}' to move into.` +
182
- (close.length > 0 ? ` Close names: ${close.join(", ")}.` : " `--into .` unfiles; `loam subsystem new` creates."));
181
+ closeNamesHint(into, tree.subsystems.map((s) => s.name), " `--into .` unfiles; `loam subsystem new` creates."));
183
182
  return null;
184
183
  }
185
184
  if (hit.kind === "service") {
@@ -209,17 +208,53 @@ async function refuseUncommitted(docsDir, dirs, json) {
209
208
  }
210
209
  /**
211
210
  * Stage the move's whole delta, silently: the rename pairs (both ends — the
212
- * delete side and the add side) AND the regenerated views file. The views
213
- * file rides along for the same reason the transaction writes it in the same
214
- * commit: a user whose next `git commit` captured the renames without it
215
- * would commit a tree `validate --all` fails (`subsystem.views-stale`) — the
216
- * exact "failing between two commits" state the roadmap forbids.
211
+ * delete side and the add side) AND BOTH regenerated views files. They ride
212
+ * along for the same reason the transaction writes them in the same commit: a
213
+ * user whose next `git commit` captured the renames without them would commit
214
+ * a tree `validate --all` fails (`subsystem.views-stale`) — the exact "failing
215
+ * between two commits" state the roadmap forbids.
216
+ *
217
+ * A generated file that is neither ON DISK nor REMOVED BY THIS COMMIT is left
218
+ * out of the pathspec, and that is a correctness rule rather than tidiness:
219
+ * `gitStageRenames` runs one `git add -A -- <paths>`, and a pathspec matching
220
+ * neither the worktree nor the index makes git refuse the WHOLE invocation
221
+ * (silently — that write is failure-silent by contract) — so naming an absent
222
+ * `architecture/services.likec4` (a fleet whose map draws no service renders
223
+ * none) would take the other paths out of the index with it.
224
+ *
225
+ * THE `removed` ARM IS WHY `existsSync` ALONE IS NOT THE FILTER. A move can be
226
+ * the commit that DELETES a generated file rather than rewriting it: a
227
+ * committed `architecture/subsystems.likec4` standing over a tree that no
228
+ * longer marks any subsystem (the marker went in an earlier commit) must not
229
+ * exist, so the window renders null and the transaction removes it — and by the
230
+ * time this runs the file is gone from disk. Measured 2026-09-07 on exactly that
231
+ * fixture: under a disk-only filter the path never reached the pathspec, git
232
+ * reported the deletion as ` D` (unstaged) while both rename ends went in as
233
+ * `R `, and the user's next `git commit` captured the renames plus a generated
234
+ * file the tree no longer licenses — `subsystem.views-stale` on a commit loam
235
+ * itself produced, the exact state the paragraph above says this staging exists
236
+ * to prevent. A path this commit deleted is still in the INDEX, so it matches
237
+ * the pathspec and `-A` stages the deletion; the commit window's own
238
+ * `ViewsActions` is what says which file that was, so no second guess about disk
239
+ * is needed.
240
+ *
241
+ * TWO INVOCATIONS, not one, and the split is what makes the `removed` arm safe
242
+ * to add: a generated file that was never committed and is deleted here is in
243
+ * neither the worktree nor the index, and folded into one pathspec it would take
244
+ * the renames down with it — the failure this function's first rule exists to
245
+ * refuse. Staging in two calls costs one extra best-effort spawn and cannot
246
+ * cost the renames. git records a rename from the index state at commit time,
247
+ * never from which `git add` put the two ends there.
217
248
  */
218
- async function stageInGit(docsDir, renames) {
219
- await gitStageRenames(docsDir, [
220
- ...renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]),
221
- repoPath(docsDir, subsystemViewsPath(docsDir)),
222
- ]);
249
+ async function stageInGit(docsDir, renames, views) {
250
+ await gitStageRenames(docsDir, renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]));
251
+ const generated = [
252
+ [subsystemViewsPath(docsDir), views.subsystems],
253
+ [serviceViewsPath(docsDir), views.services],
254
+ ];
255
+ await gitStageRenames(docsDir, generated
256
+ .filter(([path, action]) => action === "removed" || existsSync(path))
257
+ .map(([path]) => repoPath(docsDir, path)));
223
258
  }
224
259
  /**
225
260
  * Which archived features hold a VERSION-2 snapshot addressing a path under
@@ -1 +1 @@
1
- {"version":3,"file":"move.js","sourceRoot":"","sources":["../../../src/commands/subsystem/move.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `subsystem move` and `subsystem rename` — ONE transaction over N directory\n * renames plus the generated views file, the first real consumer of the\n * journaled txn's moves half (`core/staging/txn/`). The planning lives in\n * this module; the commit window itself is `./txn/txn.ts`, shared with\n * `new` and `rm`.\n *\n * The ONLY move-specific refusal is `move-uncommitted` — git reports\n * uncommitted changes under a directory being moved — and only on positive\n * evidence: where git will not say, the move proceeds. After a landed move\n * loam performs the roadmap's one blessed git write, a best-effort `git add`\n * of the rename pairs and the regenerated views file, so git records the\n * renames as renames and `subsystem history` stays answerable once the user\n * commits. Nothing is ever committed.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, sep } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { parseSubsystemName } from \"../../core/kernel/ids/subsystem.js\";\nimport { isRecord } from \"../../core/kernel/records.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitDirtyPaths, gitStageRenames } from \"../../core/provenance/gitq/moves.js\";\nimport type { FeatureEntry } from \"../../core/repo/entries.js\";\nimport { servicesDir, subsystemPathUnder, subsystemViewsPath } from \"../../core/repo/paths.js\";\nimport { listFeatures } from \"../../core/repo/repo.js\";\nimport { findInTree, nearestTreeNames, treeNames, withinSubsystem } from \"../../core/repo/tree/find.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from \"../../core/staging/snapshot.js\";\nimport { commitWindow, reportViews, type SubsystemTxn } from \"./txn/txn.js\";\nimport { movedTree } from \"./txn/views.js\";\n\n/** What one name resolved to for a move: where it is, and where it goes. */\ninterface Moved {\n name: string;\n kind: \"service\" | \"subsystem\";\n dir: string;\n /** Path of the CONTAINING directory, as names from services/ down. */\n parent: string[];\n}\n\n/** `subsystem move <name>... --into <sub|.>` — services and whole subtrees alike. */\nexport async function runMove(docsDir: DocsDir, names: string[], into: string, json: boolean): Promise<void> {\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const seen = new Set<string>();\n for (const name of names) {\n if (seen.has(name)) {\n fail(json, \"invalid-option\", `'${name}' is named twice — each service or subsystem moves once.`);\n return null;\n }\n seen.add(name);\n }\n const target = resolveTarget(tree, into, { docsDir, json });\n if (target === null) return null;\n const moved: Moved[] = [];\n for (const name of names) {\n const hit = findInTree(tree, name);\n if (hit === null) {\n const close = nearestTreeNames(name, treeNames(tree));\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n moved.push(\n hit.kind === \"service\"\n ? { name, kind: \"service\", dir: hit.service.dir, parent: hit.service.subsystem }\n : { name, kind: \"subsystem\", dir: hit.subsystem.dir, parent: hit.subsystem.path.slice(0, -1) },\n );\n }\n for (const m of moved) {\n if (m.kind === \"subsystem\" && withinSubsystem([...m.parent, m.name], target.path)) {\n fail(json, \"invalid-option\", `'${m.name}' cannot move into itself or its own subtree.`);\n return null;\n }\n if (m.parent.join(\"/\") === target.path.join(\"/\")) {\n fail(json, \"invalid-option\", `'${m.name}' is already directly in ${into === \".\" ? \"the services/ root\" : `'${into}'`} — nothing to move.`);\n return null;\n }\n const inside = moved.find(\n (other) => other.kind === \"subsystem\" && other !== m && (m.dir + sep).startsWith(other.dir + sep),\n );\n if (inside !== undefined) {\n fail(json, \"invalid-option\", `'${m.name}' sits inside '${inside.name}', which is also being moved — name only the subtree root.`);\n return null;\n }\n if (existsSync(join(target.dir, m.name))) {\n // Unreachable in a healthy flat namespace; a tree already carrying\n // name collisions can produce it, and refusing beats stacking a\n // second directory of the same name.\n fail(json, \"already-exists\", `${repoPath(docsDir, join(target.dir, m.name))} already exists — fix the name collision first.`);\n return null;\n }\n }\n if (await refuseUncommitted(docsDir, moved.map((m) => m.dir), json)) return null;\n const notices = await v2SnapshotNotices(docsDir, moved.map((m) => m.dir));\n const renames = moved.map((m) => ({ from: m.dir, to: join(target.dir, m.name) }));\n return {\n target: names.join(\", \"),\n writes: [],\n tree: movedTree(tree, renames, servicesDir(docsDir)),\n moves: renames,\n failedCode: \"move-failed\",\n what: \"moved\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, renames);\n const rows = moved.map((m, i) => ({\n name: m.name,\n kind: m.kind,\n from: repoPath(docsDir, renames[i]!.from),\n to: repoPath(docsDir, renames[i]!.to),\n }));\n if (json) {\n emitJson({\n command: \"subsystem\",\n into,\n moved: rows,\n views,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n for (const row of rows) console.log(`moved ${row.from} -> ${row.to}`);\n for (const n of notices) console.log(`note: ${n}`);\n console.log(`Renames staged where git answers; nothing committed${reportViews(views)}.`);\n },\n };\n });\n}\n\n/** `subsystem rename <old> <new>` — one rename through the same transaction. */\nexport async function runRename(docsDir: DocsDir, names: [string, string], json: boolean): Promise<void> {\n const [from, to] = names;\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const hit = findInTree(tree, from);\n if (hit === null) {\n const close = nearestTreeNames(from, tree.subsystems.map((s) => s.name));\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${from}' in the tree.` + (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \"\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(\n json,\n \"invalid-option\",\n `'${from}' is a service — a service's id IS its identity (loam.json, frontmatter, feature specs all join on it), so loam never renames one.`,\n );\n return null;\n }\n const parsed = parseSubsystemName(to, \"subsystem name\");\n if (!parsed.ok) {\n fail(json, \"invalid-option\", parsed.problem);\n return null;\n }\n const taken = findInTree(tree, to);\n if (taken !== null) {\n const where = taken.kind === \"service\" ? taken.service.dir : taken.subsystem.dir;\n fail(json, \"already-exists\", `'${to}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — the namespace is flat at any depth.`);\n return null;\n }\n if (await refuseUncommitted(docsDir, [hit.subsystem.dir], json)) return null;\n const notices = await v2SnapshotNotices(docsDir, [hit.subsystem.dir]);\n const rename = { from: hit.subsystem.dir, to: subsystemPathUnder(dirname(hit.subsystem.dir), parsed.name) };\n return {\n target: `${from} -> ${to}`,\n writes: [],\n tree: movedTree(tree, [rename], servicesDir(docsDir)),\n moves: [rename],\n failedCode: \"move-failed\",\n what: \"renamed\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, [rename]);\n if (json) {\n emitJson({\n command: \"subsystem\",\n renamed: from,\n to,\n path: repoPath(docsDir, rename.to),\n views,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`renamed subsystem '${from}' -> '${to}' (${repoPath(docsDir, rename.to)}/)${reportViews(views)}`);\n for (const n of notices) console.log(`note: ${n}`);\n },\n };\n });\n}\n\n/** Where `--into` points: the services/ root for `.`, an existing subsystem otherwise. */\nfunction resolveTarget(tree: FleetTree, into: string, at: { docsDir: DocsDir; json: boolean }): { dir: string; path: string[] } | null {\n if (into === \".\") return { dir: servicesDir(at.docsDir), path: [] };\n const hit = findInTree(tree, into);\n if (hit === null) {\n const close = nearestTreeNames(into, tree.subsystems.map((s) => s.name));\n fail(\n at.json,\n \"unknown-target\",\n `No subsystem '${into}' to move into.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `--into .` unfiles; `loam subsystem new` creates.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(at.json, \"invalid-option\", `--into names the service '${into}' — a service never contains other services.`);\n return null;\n }\n return { dir: hit.subsystem.dir, path: hit.subsystem.path };\n}\n\n/**\n * The one move-specific refusal, on positive evidence only: git names\n * uncommitted work under a directory about to be renamed. Null (git will not\n * say) proceeds — a fleet that does not use git must not be refused over it.\n */\nasync function refuseUncommitted(docsDir: DocsDir, dirs: string[], json: boolean): Promise<boolean> {\n const dirty = await gitDirtyPaths(docsDir, dirs.map((d) => repoPath(docsDir, d)));\n if (dirty === null || dirty.length === 0) return false;\n fail(\n json,\n \"move-uncommitted\",\n // \"or untracked\", and `git stash -u` by name: the check fires on ANY\n // porcelain entry, untracked files included, and plain `git stash` does\n // not stash those — advice that said \"stash\" sent the user in a loop,\n // refused again with the same sentence after doing what it asked.\n `git reports ${dirty.length} uncommitted or untracked path(s) under the directory(ies) being moved: ${dirty.join(\", \")}. ` +\n \"Renaming now would sweep them into a move nobody reviewed — commit them, `git stash -u`, or remove them, then re-run. \" +\n \"Nothing was moved.\",\n );\n return true;\n}\n\n/**\n * Stage the move's whole delta, silently: the rename pairs (both ends — the\n * delete side and the add side) AND the regenerated views file. The views\n * file rides along for the same reason the transaction writes it in the same\n * commit: a user whose next `git commit` captured the renames without it\n * would commit a tree `validate --all` fails (`subsystem.views-stale`) — the\n * exact \"failing between two commits\" state the roadmap forbids.\n */\nasync function stageInGit(docsDir: DocsDir, renames: { from: string; to: string }[]): Promise<void> {\n await gitStageRenames(docsDir, [\n ...renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]),\n repoPath(docsDir, subsystemViewsPath(docsDir)),\n ]);\n}\n\n/**\n * Which archived features hold a VERSION-2 snapshot addressing a path under\n * one of these directories — the notice, never a refusal, a move prints\n * before it proceeds. A version-2 manifest predates the tree and records\n * literal `services/<id>/…` paths, so after this move an `unarchive --force`\n * of that feature restores into the OLD path, resurrecting the pre-move\n * directory beside the moved one (two claimants, `subsystem.name-collision`\n * — loud, but avoidable by being told now). Version-3 manifests key rows by\n * service id and follow the enumeration, so they are not named. Every\n * failure to read reads as \"nothing to warn about\": a warning needs positive\n * evidence exactly as the move's one refusal does.\n */\nasync function v2SnapshotNotices(docsDir: DocsDir, dirs: string[]): Promise<string[]> {\n const rels = dirs.map((d) => repoPath(docsDir, d));\n const notices: string[] = [];\n let features: FeatureEntry[];\n try {\n features = await listFeatures(docsDir, { includeArchived: true });\n } catch {\n return notices;\n }\n for (const f of features.filter((entry) => entry.archived)) {\n let manifest: unknown;\n try {\n manifest = JSON.parse(await readFile(join(snapshotDir(f.dir), SNAPSHOT_MANIFEST), \"utf8\"));\n } catch {\n continue;\n }\n if (!isRecord(manifest) || manifest.version !== SNAPSHOT_COMPAT_VERSION || !Array.isArray(manifest.files)) continue;\n const addressed = rels.filter((rel) =>\n (manifest.files as unknown[]).some(\n (row) => isRecord(row) && typeof row.path === \"string\" && row.path.startsWith(`${rel}/`),\n ),\n );\n if (addressed.length > 0) {\n notices.push(\n `${f.id}'s archived snapshot is version 2 and addresses ${addressed.join(\", \")} by literal path — ` +\n `\\`loam unarchive ${f.id} --force\\` after this move would restore into the old location, ` +\n `resurrecting the pre-move directory beside the moved one.`,\n );\n }\n }\n return notices;\n}\n"]}
1
+ {"version":3,"file":"move.js","sourceRoot":"","sources":["../../../src/commands/subsystem/move.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `subsystem move` and `subsystem rename` — ONE transaction over N directory\n * renames plus BOTH generated views files, the first real consumer of the\n * journaled txn's moves half (`core/staging/txn/`). The planning lives in\n * this module; the commit window itself is `./txn/txn.ts`, shared with\n * `new` and `rm`.\n *\n * The ONLY move-specific refusal is `move-uncommitted` — git reports\n * uncommitted changes under a directory being moved — and only on positive\n * evidence: where git will not say, the move proceeds. After a landed move\n * loam performs the roadmap's one blessed git write, a best-effort `git add`\n * of the rename pairs and of BOTH regenerated views files, so git records the\n * renames as renames and `subsystem history` stays answerable once the user\n * commits. Nothing is ever committed.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, sep } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { parseSubsystemName } from \"../../core/kernel/ids/subsystem.js\";\nimport { isRecord } from \"../../core/kernel/records.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitDirtyPaths, gitStageRenames } from \"../../core/provenance/gitq/moves.js\";\nimport type { FeatureEntry } from \"../../core/repo/entries.js\";\nimport { servicesDir, serviceViewsPath, subsystemPathUnder, subsystemViewsPath } from \"../../core/repo/paths.js\";\nimport { listFeatures } from \"../../core/repo/repo.js\";\nimport { closeNamesHint, findInTree, treeNames, withinSubsystem } from \"../../core/repo/tree/find.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from \"../../core/staging/snapshot/manifest.js\";\nimport { commitWindow, reportViews, type SubsystemTxn, type ViewsActions } from \"./txn/txn.js\";\nimport { movedTree } from \"./txn/views.js\";\n\n/** What one name resolved to for a move: where it is, and where it goes. */\ninterface Moved {\n name: string;\n kind: \"service\" | \"subsystem\";\n dir: string;\n /** Path of the CONTAINING directory, as names from services/ down. */\n parent: string[];\n}\n\n/** `subsystem move <name>... --into <sub|.>` — services and whole subtrees alike. */\nexport async function runMove(docsDir: DocsDir, names: string[], into: string, json: boolean): Promise<void> {\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const seen = new Set<string>();\n for (const name of names) {\n if (seen.has(name)) {\n fail(json, \"invalid-option\", `'${name}' is named twice — each service or subsystem moves once.`);\n return null;\n }\n seen.add(name);\n }\n const target = resolveTarget(tree, into, { docsDir, json });\n if (target === null) return null;\n const moved: Moved[] = [];\n for (const name of names) {\n const hit = findInTree(tree, name);\n if (hit === null) {\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` +\n closeNamesHint(name, treeNames(tree), \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n moved.push(\n hit.kind === \"service\"\n ? { name, kind: \"service\", dir: hit.service.dir, parent: hit.service.subsystem }\n : { name, kind: \"subsystem\", dir: hit.subsystem.dir, parent: hit.subsystem.path.slice(0, -1) },\n );\n }\n for (const m of moved) {\n if (m.kind === \"subsystem\" && withinSubsystem([...m.parent, m.name], target.path)) {\n fail(json, \"invalid-option\", `'${m.name}' cannot move into itself or its own subtree.`);\n return null;\n }\n if (m.parent.join(\"/\") === target.path.join(\"/\")) {\n fail(json, \"invalid-option\", `'${m.name}' is already directly in ${into === \".\" ? \"the services/ root\" : `'${into}'`} — nothing to move.`);\n return null;\n }\n const inside = moved.find(\n (other) => other.kind === \"subsystem\" && other !== m && (m.dir + sep).startsWith(other.dir + sep),\n );\n if (inside !== undefined) {\n fail(json, \"invalid-option\", `'${m.name}' sits inside '${inside.name}', which is also being moved — name only the subtree root.`);\n return null;\n }\n if (existsSync(join(target.dir, m.name))) {\n // Unreachable in a healthy flat namespace; a tree already carrying\n // name collisions can produce it, and refusing beats stacking a\n // second directory of the same name.\n fail(json, \"already-exists\", `${repoPath(docsDir, join(target.dir, m.name))} already exists — fix the name collision first.`);\n return null;\n }\n }\n if (await refuseUncommitted(docsDir, moved.map((m) => m.dir), json)) return null;\n const notices = await v2SnapshotNotices(docsDir, moved.map((m) => m.dir));\n const renames = moved.map((m) => ({ from: m.dir, to: join(target.dir, m.name) }));\n return {\n target: names.join(\", \"),\n writes: [],\n tree: movedTree(tree, renames, servicesDir(docsDir)),\n moves: renames,\n failedCode: \"move-failed\",\n what: \"moved\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, renames, views);\n const rows = moved.map((m, i) => ({\n name: m.name,\n kind: m.kind,\n from: repoPath(docsDir, renames[i]!.from),\n to: repoPath(docsDir, renames[i]!.to),\n }));\n if (json) {\n emitJson({\n command: \"subsystem\",\n into,\n moved: rows,\n views: views.subsystems,\n serviceViews: views.services,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n for (const row of rows) console.log(`moved ${row.from} -> ${row.to}`);\n for (const n of notices) console.log(`note: ${n}`);\n console.log(`Renames staged where git answers; nothing committed${reportViews(views)}.`);\n },\n };\n });\n}\n\n/** `subsystem rename <old> <new>` — one rename through the same transaction. */\nexport async function runRename(docsDir: DocsDir, names: [string, string], json: boolean): Promise<void> {\n const [from, to] = names;\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const hit = findInTree(tree, from);\n if (hit === null) {\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${from}' in the tree.` + closeNamesHint(from, tree.subsystems.map((s) => s.name), \"\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(\n json,\n \"invalid-option\",\n `'${from}' is a service — a service's id IS its identity (loam.json, frontmatter, feature specs all join on it), so loam never renames one.`,\n );\n return null;\n }\n const parsed = parseSubsystemName(to, \"subsystem name\");\n if (!parsed.ok) {\n fail(json, \"invalid-option\", parsed.problem);\n return null;\n }\n const taken = findInTree(tree, to);\n if (taken !== null) {\n const where = taken.kind === \"service\" ? taken.service.dir : taken.subsystem.dir;\n fail(json, \"already-exists\", `'${to}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — the namespace is flat at any depth.`);\n return null;\n }\n if (await refuseUncommitted(docsDir, [hit.subsystem.dir], json)) return null;\n const notices = await v2SnapshotNotices(docsDir, [hit.subsystem.dir]);\n const rename = { from: hit.subsystem.dir, to: subsystemPathUnder(dirname(hit.subsystem.dir), parsed.name) };\n return {\n target: `${from} -> ${to}`,\n writes: [],\n tree: movedTree(tree, [rename], servicesDir(docsDir)),\n moves: [rename],\n failedCode: \"move-failed\",\n what: \"renamed\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, [rename], views);\n if (json) {\n emitJson({\n command: \"subsystem\",\n renamed: from,\n to,\n path: repoPath(docsDir, rename.to),\n views: views.subsystems,\n serviceViews: views.services,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`renamed subsystem '${from}' -> '${to}' (${repoPath(docsDir, rename.to)}/)${reportViews(views)}`);\n for (const n of notices) console.log(`note: ${n}`);\n },\n };\n });\n}\n\n/** Where `--into` points: the services/ root for `.`, an existing subsystem otherwise. */\nfunction resolveTarget(tree: FleetTree, into: string, at: { docsDir: DocsDir; json: boolean }): { dir: string; path: string[] } | null {\n if (into === \".\") return { dir: servicesDir(at.docsDir), path: [] };\n const hit = findInTree(tree, into);\n if (hit === null) {\n fail(\n at.json,\n \"unknown-target\",\n `No subsystem '${into}' to move into.` +\n closeNamesHint(into, tree.subsystems.map((s) => s.name), \" `--into .` unfiles; `loam subsystem new` creates.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(at.json, \"invalid-option\", `--into names the service '${into}' — a service never contains other services.`);\n return null;\n }\n return { dir: hit.subsystem.dir, path: hit.subsystem.path };\n}\n\n/**\n * The one move-specific refusal, on positive evidence only: git names\n * uncommitted work under a directory about to be renamed. Null (git will not\n * say) proceeds — a fleet that does not use git must not be refused over it.\n */\nasync function refuseUncommitted(docsDir: DocsDir, dirs: string[], json: boolean): Promise<boolean> {\n const dirty = await gitDirtyPaths(docsDir, dirs.map((d) => repoPath(docsDir, d)));\n if (dirty === null || dirty.length === 0) return false;\n fail(\n json,\n \"move-uncommitted\",\n // \"or untracked\", and `git stash -u` by name: the check fires on ANY\n // porcelain entry, untracked files included, and plain `git stash` does\n // not stash those — advice that said \"stash\" sent the user in a loop,\n // refused again with the same sentence after doing what it asked.\n `git reports ${dirty.length} uncommitted or untracked path(s) under the directory(ies) being moved: ${dirty.join(\", \")}. ` +\n \"Renaming now would sweep them into a move nobody reviewed — commit them, `git stash -u`, or remove them, then re-run. \" +\n \"Nothing was moved.\",\n );\n return true;\n}\n\n/**\n * Stage the move's whole delta, silently: the rename pairs (both ends — the\n * delete side and the add side) AND BOTH regenerated views files. They ride\n * along for the same reason the transaction writes them in the same commit: a\n * user whose next `git commit` captured the renames without them would commit\n * a tree `validate --all` fails (`subsystem.views-stale`) — the exact \"failing\n * between two commits\" state the roadmap forbids.\n *\n * A generated file that is neither ON DISK nor REMOVED BY THIS COMMIT is left\n * out of the pathspec, and that is a correctness rule rather than tidiness:\n * `gitStageRenames` runs one `git add -A -- <paths>`, and a pathspec matching\n * neither the worktree nor the index makes git refuse the WHOLE invocation\n * (silently — that write is failure-silent by contract) — so naming an absent\n * `architecture/services.likec4` (a fleet whose map draws no service renders\n * none) would take the other paths out of the index with it.\n *\n * THE `removed` ARM IS WHY `existsSync` ALONE IS NOT THE FILTER. A move can be\n * the commit that DELETES a generated file rather than rewriting it: a\n * committed `architecture/subsystems.likec4` standing over a tree that no\n * longer marks any subsystem (the marker went in an earlier commit) must not\n * exist, so the window renders null and the transaction removes it — and by the\n * time this runs the file is gone from disk. Measured 2026-09-07 on exactly that\n * fixture: under a disk-only filter the path never reached the pathspec, git\n * reported the deletion as ` D` (unstaged) while both rename ends went in as\n * `R `, and the user's next `git commit` captured the renames plus a generated\n * file the tree no longer licenses — `subsystem.views-stale` on a commit loam\n * itself produced, the exact state the paragraph above says this staging exists\n * to prevent. A path this commit deleted is still in the INDEX, so it matches\n * the pathspec and `-A` stages the deletion; the commit window's own\n * `ViewsActions` is what says which file that was, so no second guess about disk\n * is needed.\n *\n * TWO INVOCATIONS, not one, and the split is what makes the `removed` arm safe\n * to add: a generated file that was never committed and is deleted here is in\n * neither the worktree nor the index, and folded into one pathspec it would take\n * the renames down with it — the failure this function's first rule exists to\n * refuse. Staging in two calls costs one extra best-effort spawn and cannot\n * cost the renames. git records a rename from the index state at commit time,\n * never from which `git add` put the two ends there.\n */\nasync function stageInGit(docsDir: DocsDir, renames: { from: string; to: string }[], views: ViewsActions): Promise<void> {\n await gitStageRenames(docsDir, renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]));\n const generated = [\n [subsystemViewsPath(docsDir), views.subsystems] as const,\n [serviceViewsPath(docsDir), views.services] as const,\n ];\n await gitStageRenames(\n docsDir,\n generated\n .filter(([path, action]) => action === \"removed\" || existsSync(path))\n .map(([path]) => repoPath(docsDir, path)),\n );\n}\n\n/**\n * Which archived features hold a VERSION-2 snapshot addressing a path under\n * one of these directories — the notice, never a refusal, a move prints\n * before it proceeds. A version-2 manifest predates the tree and records\n * literal `services/<id>/…` paths, so after this move an `unarchive --force`\n * of that feature restores into the OLD path, resurrecting the pre-move\n * directory beside the moved one (two claimants, `subsystem.name-collision`\n * — loud, but avoidable by being told now). Version-3 manifests key rows by\n * service id and follow the enumeration, so they are not named. Every\n * failure to read reads as \"nothing to warn about\": a warning needs positive\n * evidence exactly as the move's one refusal does.\n */\nasync function v2SnapshotNotices(docsDir: DocsDir, dirs: string[]): Promise<string[]> {\n const rels = dirs.map((d) => repoPath(docsDir, d));\n const notices: string[] = [];\n let features: FeatureEntry[];\n try {\n features = await listFeatures(docsDir, { includeArchived: true });\n } catch {\n return notices;\n }\n for (const f of features.filter((entry) => entry.archived)) {\n let manifest: unknown;\n try {\n manifest = JSON.parse(await readFile(join(snapshotDir(f.dir), SNAPSHOT_MANIFEST), \"utf8\"));\n } catch {\n continue;\n }\n if (!isRecord(manifest) || manifest.version !== SNAPSHOT_COMPAT_VERSION || !Array.isArray(manifest.files)) continue;\n const addressed = rels.filter((rel) =>\n (manifest.files as unknown[]).some(\n (row) => isRecord(row) && typeof row.path === \"string\" && row.path.startsWith(`${rel}/`),\n ),\n );\n if (addressed.length > 0) {\n notices.push(\n `${f.id}'s archived snapshot is version 2 and addresses ${addressed.join(\", \")} by literal path — ` +\n `\\`loam unarchive ${f.id} --force\\` after this move would restore into the old location, ` +\n `resurrecting the pre-move directory beside the moved one.`,\n );\n }\n }\n return notices;\n}\n"]}
@@ -16,7 +16,7 @@ import { emitJson, fail, repoPath } from "../../core/envelope/json.js";
16
16
  import { gitRenameHops, gitRenamePairingAmbiguous } from "../../core/provenance/gitq/moves.js";
17
17
  import { servicePathsAt } from "../../core/repo/paths.js";
18
18
  import { listFleetTree } from "../../core/repo/repo.js";
19
- import { findInTree, nearestTreeNames, servicesUnder, treeNames } from "../../core/repo/tree/find.js";
19
+ import { closeNamesHint, findInTree, servicesUnder, treeNames } from "../../core/repo/tree/find.js";
20
20
  import { SUBSYSTEM_MARKER } from "../../core/repo/tree/marker.js";
21
21
  export async function runList(docsDir, json) {
22
22
  const tree = await listFleetTree(docsDir);
@@ -53,9 +53,7 @@ export async function runHistory(docsDir, name, json) {
53
53
  const tree = await listFleetTree(docsDir);
54
54
  const hit = findInTree(tree, name);
55
55
  if (hit === null) {
56
- const close = nearestTreeNames(name, treeNames(tree));
57
- fail(json, "unknown-target", `No service or subsystem '${name}' in the tree.` +
58
- (close.length > 0 ? ` Close names: ${close.join(", ")}.` : ""));
56
+ fail(json, "unknown-target", `No service or subsystem '${name}' in the tree.` + closeNamesHint(name, treeNames(tree), ""));
59
57
  return;
60
58
  }
61
59
  const kind = hit.kind;
@@ -1 +1 @@
1
- {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/commands/subsystem/query.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The read verbs: `subsystem list` (the tree with member and unfiled counts)\n * and `subsystem history` (how a service or subsystem moved, asked of git).\n *\n * `history` stays inside the provenance doctrine (`core/provenance/git.ts`):\n * loam asks git and never tells it, and every way git declines reads as \"git\n * will not say\" — nothing to answer, exit 0, no finding. The question\n * follows a representative FILE (a service's first surviving artifact, a\n * subsystem's marker), because `git log --follow` is defined for one file\n * and prints nothing at all for a directory path; each hop's directories are\n * read off the file's own rename record.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitRenameHops, gitRenamePairingAmbiguous } from \"../../core/provenance/gitq/moves.js\";\nimport { servicePathsAt } from \"../../core/repo/paths.js\";\nimport { listFleetTree } from \"../../core/repo/repo.js\";\nimport { findInTree, nearestTreeNames, servicesUnder, treeNames } from \"../../core/repo/tree/find.js\";\nimport { SUBSYSTEM_MARKER } from \"../../core/repo/tree/marker.js\";\nimport type { SubsystemEntry } from \"../../core/repo/tree/walk.js\";\n\nexport async function runList(docsDir: DocsDir, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const sorted = [...tree.subsystems].sort((a, b) => (a.path.join(\"/\") < b.path.join(\"/\") ? -1 : 1));\n const unfiled = tree.services.filter((s) => s.subsystem.length === 0).length;\n const memberCount = (sub: SubsystemEntry): number => servicesUnder(tree, sub).length;\n if (json) {\n emitJson({\n command: \"subsystem\",\n subsystems: sorted.map((sub) => ({\n name: sub.name,\n path: repoPath(docsDir, sub.dir),\n title: sub.meta.title ?? null,\n memberCount: memberCount(sub),\n })),\n unfiledServices: unfiled,\n services: tree.services.length,\n });\n return;\n }\n if (sorted.length === 0) {\n console.log(`no subsystems — the fleet is flat (${tree.services.length} service(s), all unfiled).`);\n return;\n }\n console.log(`subsystems (${sorted.length})`);\n for (const sub of sorted) {\n const indent = \" \".repeat(sub.path.length);\n const title = sub.meta.title === undefined ? \"\" : ` ${sub.meta.title}`;\n console.log(`${indent}${sub.name}${title} — ${memberCount(sub)} service(s)`);\n }\n console.log(`unfiled: ${unfiled} of ${tree.services.length} service(s)`);\n}\n\nexport async function runHistory(docsDir: DocsDir, name: string, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const hit = findInTree(tree, name);\n if (hit === null) {\n const close = nearestTreeNames(name, treeNames(tree));\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \"\"),\n );\n return;\n }\n const kind = hit.kind;\n const file = representativeFile(hit);\n const followed = file === null ? null : await gitRenameHops(docsDir, repoPath(docsDir, file));\n // Every hop is cross-checked against its own commit before it is repeated:\n // `--follow` pairs paths by content, and identical files moved together\n // (empty markers above all) make that pairing a guess — a hop from a\n // directory this subsystem never inhabited. A guessed hop, or a commit the\n // check cannot read, poisons the whole answer, because the hops chain: one\n // untrusted link makes every earlier \"from\" untrustworthy too.\n let ambiguous = false;\n for (const h of followed ?? []) {\n if ((await gitRenamePairingAmbiguous(docsDir, h.commit, h.to)) !== false) {\n ambiguous = true;\n break;\n }\n }\n const hops = ambiguous ? null : followed;\n const parent = (rel: string): string => rel.slice(0, Math.max(0, rel.lastIndexOf(\"/\")));\n const moves = (hops ?? []).map((h) => ({ from: parent(h.from), to: parent(h.to), commit: h.commit }));\n if (json) {\n // Additive honesty key: `answered: false` is git DECLINING (or nothing to\n // follow, or a rename record too ambiguous to trust), not git answering\n // \"never moved\" — exit 0 either way, no finding.\n emitJson({ command: \"subsystem\", name, kind, moves, answered: hops !== null });\n return;\n }\n if (ambiguous) {\n console.log(\n `git will not say — a commit in this file's history moved identical files together, ` +\n `so \\`git log --follow\\` pairs them by guesswork and the hops cannot be trusted. No finding either way.`,\n );\n return;\n }\n if (hops === null) {\n console.log(`git will not say — not a repository, git unavailable, or nothing here to follow. No finding either way.`);\n return;\n }\n if (moves.length === 0) {\n console.log(`no recorded moves for '${name}'.`);\n return;\n }\n for (const m of moves) console.log(`${m.from} -> ${m.to} (${m.commit.slice(0, 7)})`);\n}\n\n/**\n * The file whose rename record carries the directory's history: a\n * subsystem's own marker; for a service, the first artifact that exists\n * today, in the fixed artifact order — deterministic, so two runs follow the\n * same file. A service with no artifact on disk gives git nothing to follow.\n */\nfunction representativeFile(hit: NonNullable<ReturnType<typeof findInTree>>): string | null {\n if (hit.kind === \"subsystem\") return join(hit.subsystem.dir, SUBSYSTEM_MARKER);\n const p = servicePathsAt(hit.service.dir);\n return [p.spec, p.model, p.archSpec, p.openapi, p.asyncapi, p.runbook, p.health].find(existsSync) ?? null;\n}\n"]}
1
+ {"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/commands/subsystem/query.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The read verbs: `subsystem list` (the tree with member and unfiled counts)\n * and `subsystem history` (how a service or subsystem moved, asked of git).\n *\n * `history` stays inside the provenance doctrine (`core/provenance/git.ts`):\n * loam asks git and never tells it, and every way git declines reads as \"git\n * will not say\" — nothing to answer, exit 0, no finding. The question\n * follows a representative FILE (a service's first surviving artifact, a\n * subsystem's marker), because `git log --follow` is defined for one file\n * and prints nothing at all for a directory path; each hop's directories are\n * read off the file's own rename record.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitRenameHops, gitRenamePairingAmbiguous } from \"../../core/provenance/gitq/moves.js\";\nimport { servicePathsAt } from \"../../core/repo/paths.js\";\nimport { listFleetTree } from \"../../core/repo/repo.js\";\nimport { closeNamesHint, findInTree, servicesUnder, treeNames } from \"../../core/repo/tree/find.js\";\nimport { SUBSYSTEM_MARKER } from \"../../core/repo/tree/marker.js\";\nimport type { SubsystemEntry } from \"../../core/repo/tree/walk.js\";\n\nexport async function runList(docsDir: DocsDir, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const sorted = [...tree.subsystems].sort((a, b) => (a.path.join(\"/\") < b.path.join(\"/\") ? -1 : 1));\n const unfiled = tree.services.filter((s) => s.subsystem.length === 0).length;\n const memberCount = (sub: SubsystemEntry): number => servicesUnder(tree, sub).length;\n if (json) {\n emitJson({\n command: \"subsystem\",\n subsystems: sorted.map((sub) => ({\n name: sub.name,\n path: repoPath(docsDir, sub.dir),\n title: sub.meta.title ?? null,\n memberCount: memberCount(sub),\n })),\n unfiledServices: unfiled,\n services: tree.services.length,\n });\n return;\n }\n if (sorted.length === 0) {\n console.log(`no subsystems — the fleet is flat (${tree.services.length} service(s), all unfiled).`);\n return;\n }\n console.log(`subsystems (${sorted.length})`);\n for (const sub of sorted) {\n const indent = \" \".repeat(sub.path.length);\n const title = sub.meta.title === undefined ? \"\" : ` ${sub.meta.title}`;\n console.log(`${indent}${sub.name}${title} — ${memberCount(sub)} service(s)`);\n }\n console.log(`unfiled: ${unfiled} of ${tree.services.length} service(s)`);\n}\n\nexport async function runHistory(docsDir: DocsDir, name: string, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const hit = findInTree(tree, name);\n if (hit === null) {\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` + closeNamesHint(name, treeNames(tree), \"\"),\n );\n return;\n }\n const kind = hit.kind;\n const file = representativeFile(hit);\n const followed = file === null ? null : await gitRenameHops(docsDir, repoPath(docsDir, file));\n // Every hop is cross-checked against its own commit before it is repeated:\n // `--follow` pairs paths by content, and identical files moved together\n // (empty markers above all) make that pairing a guess — a hop from a\n // directory this subsystem never inhabited. A guessed hop, or a commit the\n // check cannot read, poisons the whole answer, because the hops chain: one\n // untrusted link makes every earlier \"from\" untrustworthy too.\n let ambiguous = false;\n for (const h of followed ?? []) {\n if ((await gitRenamePairingAmbiguous(docsDir, h.commit, h.to)) !== false) {\n ambiguous = true;\n break;\n }\n }\n const hops = ambiguous ? null : followed;\n const parent = (rel: string): string => rel.slice(0, Math.max(0, rel.lastIndexOf(\"/\")));\n const moves = (hops ?? []).map((h) => ({ from: parent(h.from), to: parent(h.to), commit: h.commit }));\n if (json) {\n // Additive honesty key: `answered: false` is git DECLINING (or nothing to\n // follow, or a rename record too ambiguous to trust), not git answering\n // \"never moved\" — exit 0 either way, no finding.\n emitJson({ command: \"subsystem\", name, kind, moves, answered: hops !== null });\n return;\n }\n if (ambiguous) {\n console.log(\n `git will not say — a commit in this file's history moved identical files together, ` +\n `so \\`git log --follow\\` pairs them by guesswork and the hops cannot be trusted. No finding either way.`,\n );\n return;\n }\n if (hops === null) {\n console.log(`git will not say — not a repository, git unavailable, or nothing here to follow. No finding either way.`);\n return;\n }\n if (moves.length === 0) {\n console.log(`no recorded moves for '${name}'.`);\n return;\n }\n for (const m of moves) console.log(`${m.from} -> ${m.to} (${m.commit.slice(0, 7)})`);\n}\n\n/**\n * The file whose rename record carries the directory's history: a\n * subsystem's own marker; for a service, the first artifact that exists\n * today, in the fixed artifact order — deterministic, so two runs follow the\n * same file. A service with no artifact on disk gives git nothing to follow.\n */\nfunction representativeFile(hit: NonNullable<ReturnType<typeof findInTree>>): string | null {\n if (hit.kind === \"subsystem\") return join(hit.subsystem.dir, SUBSYSTEM_MARKER);\n const p = servicePathsAt(hit.service.dir);\n return [p.spec, p.model, p.archSpec, p.openapi, p.asyncapi, p.runbook, p.health].find(existsSync) ?? null;\n}\n"]}
@@ -1,5 +1,4 @@
1
- import { loadConfig } from "../../core/envelope/config.js";
2
- import { fail, reportNoConfig } from "../../core/envelope/json.js";
1
+ import { configOrRefuse, fail } from "../../core/envelope/json.js";
3
2
  import { DocsRepoUnavailableError } from "../../core/repo/state.js";
4
3
  import { docsRepoReady, reportDocsRepoError } from "../policy/gate.js";
5
4
  import { runNew, runRm } from "./edit.js";
@@ -63,12 +62,10 @@ export function registerSubsystem(program) {
63
62
  fail(json, "invalid-option", misuse);
64
63
  return;
65
64
  }
66
- const loaded = await loadConfig();
67
- if (loaded.kind !== "loaded") {
68
- reportNoConfig(json, loaded);
65
+ const config = await configOrRefuse(json);
66
+ if (config === null)
69
67
  return;
70
- }
71
- const { docsDir } = loaded.config;
68
+ const { docsDir } = config;
72
69
  // "services": every verb reads or rewrites the tree that IS the fleet,
73
70
  // so a docsDir with no services/ is a refusal, never an empty answer.
74
71
  if (!docsRepoReady(json, docsDir, "services"))
@@ -1 +1 @@
1
- {"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../src/commands/subsystem/subsystem.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam subsystem <verb>` — the command surface over the tree under\n * `services/`.\n *\n * ONE registration with the verbs dispatched inside the action, deliberately\n * NOT Commander subcommands: test/agents.test.ts counts the literal\n * command-registration calls across src/commands/ and asserts the count\n * equals `buildProgram()`'s command list, so nested subcommands would\n * register as one command while counting as many literals — the guard would\n * fail in a way that reads as unrelated. (That same scan is why this comment\n * never spells the registration call with its parenthesis.) The option\n * superset is declared here once; the arity table below refuses a flag on a\n * verb that does not read it, because a silently ignored `--into` is a move\n * that did not happen.\n */\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { fail, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { docsRepoReady, reportDocsRepoError } from \"../policy/gate.js\";\nimport { runNew, runRm } from \"./edit.js\";\nimport { runMove, runRename } from \"./move.js\";\nimport { runHistory, runList } from \"./query.js\";\nimport { runSync } from \"./sync.js\";\n\nexport interface SubsystemOptions {\n into?: string;\n under?: string;\n title?: string;\n description?: string;\n owner?: string;\n json?: boolean;\n}\n\nconst VERBS = [\"new\", \"move\", \"rename\", \"rm\", \"list\", \"history\", \"sync\"] as const;\ntype Verb = (typeof VERBS)[number];\n\n/** How many names each verb takes, spelled once so the refusals agree with the dispatch. */\nconst NAMES: Record<Verb, { min: number; max: number; usage: string }> = {\n new: { min: 1, max: 1, usage: \"subsystem new <name> [--under <sub>] [--title <text>] [--description <text>] [--owner <name>]\" },\n move: { min: 1, max: Infinity, usage: \"subsystem move <name>... --into <sub|.>\" },\n rename: { min: 2, max: 2, usage: \"subsystem rename <old> <new>\" },\n rm: { min: 1, max: 1, usage: \"subsystem rm <name>\" },\n list: { min: 0, max: 0, usage: \"subsystem list\" },\n history: { min: 1, max: 1, usage: \"subsystem history <name>\" },\n sync: { min: 0, max: 0, usage: \"subsystem sync\" },\n};\n\n/** The flag/verb contradictions worth refusing: an ignored flag is a lie about what ran. */\nfunction flagMisuse(verb: Verb, opts: SubsystemOptions): string | null {\n if (opts.into !== undefined && verb !== \"move\") return `--into belongs to 'move' (${NAMES.move.usage}).`;\n if (opts.into === undefined && verb === \"move\") return `'move' needs a destination: ${NAMES.move.usage} ('.' unfiles).`;\n for (const [flag, value] of [\n [\"--under\", opts.under],\n [\"--title\", opts.title],\n [\"--description\", opts.description],\n [\"--owner\", opts.owner],\n ] as const) {\n if (value !== undefined && verb !== \"new\") return `${flag} belongs to 'new' (${NAMES.new.usage}).`;\n }\n return null;\n}\n\nexport function registerSubsystem(program: Command): void {\n program\n .command(\"subsystem\")\n .description(\"Manage the subsystem tree under services/ — the grouping no identity depends on\")\n .argument(\"<verb>\", VERBS.join(\" | \"))\n .argument(\"[names...]\", \"the subsystem or service names the verb applies to\")\n .option(\"--into <name>\", \"move: the destination subsystem, or '.' for the services/ root (unfiled)\")\n .option(\"--under <name>\", \"new: the parent subsystem (default: the services/ root)\")\n .option(\"--title <text>\", \"new: the subsystem's human title, kept in subsystem.yaml\")\n .option(\"--description <text>\", \"new: what the group is, kept in subsystem.yaml\")\n .option(\"--owner <name>\", \"new: who answers for the group, kept in subsystem.yaml\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (verb: string, names: string[], opts: SubsystemOptions) => {\n const json = opts.json === true;\n if (!(VERBS as readonly string[]).includes(verb)) {\n // The same code `list` gives a bad section: one mistake class, one code.\n fail(json, \"invalid-option\", `Unknown verb '${verb}'. Expected: ${VERBS.join(\" | \")}.`);\n return;\n }\n const arity = NAMES[verb as Verb];\n if (names.length < arity.min || names.length > arity.max) {\n fail(json, \"invalid-option\", `'${verb}' takes ${arity.min === arity.max ? arity.min : `${arity.min}+`} name(s): ${arity.usage}`);\n return;\n }\n const misuse = flagMisuse(verb as Verb, opts);\n if (misuse !== null) {\n fail(json, \"invalid-option\", misuse);\n return;\n }\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const { docsDir } = loaded.config;\n // \"services\": every verb reads or rewrites the tree that IS the fleet,\n // so a docsDir with no services/ is a refusal, never an empty answer.\n if (!docsRepoReady(json, docsDir, \"services\")) return;\n try {\n switch (verb as Verb) {\n case \"new\":\n return await runNew(docsDir, names[0]!, opts, json);\n case \"move\":\n return await runMove(docsDir, names, opts.into!, json);\n case \"rename\":\n return await runRename(docsDir, [names[0]!, names[1]!], json);\n case \"rm\":\n return await runRm(docsDir, names[0]!, json);\n case \"list\":\n return await runList(docsDir, json);\n case \"history\":\n return await runHistory(docsDir, names[0]!, json);\n case \"sync\":\n return await runSync(docsDir, json);\n }\n } catch (err) {\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n reportDocsRepoError(json, err);\n }\n });\n}\n"]}
1
+ {"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../src/commands/subsystem/subsystem.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam subsystem <verb>` — the command surface over the tree under\n * `services/`.\n *\n * ONE registration with the verbs dispatched inside the action, deliberately\n * NOT Commander subcommands: test/agents.test.ts counts the literal\n * command-registration calls across src/commands/ and asserts the count\n * equals `buildProgram()`'s command list, so nested subcommands would\n * register as one command while counting as many literals — the guard would\n * fail in a way that reads as unrelated. (That same scan is why this comment\n * never spells the registration call with its parenthesis.) The option\n * superset is declared here once; the arity table below refuses a flag on a\n * verb that does not read it, because a silently ignored `--into` is a move\n * that did not happen.\n */\nimport type { Command } from \"commander\";\nimport { configOrRefuse, fail } from \"../../core/envelope/json.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { docsRepoReady, reportDocsRepoError } from \"../policy/gate.js\";\nimport { runNew, runRm } from \"./edit.js\";\nimport { runMove, runRename } from \"./move.js\";\nimport { runHistory, runList } from \"./query.js\";\nimport { runSync } from \"./sync.js\";\n\nexport interface SubsystemOptions {\n into?: string;\n under?: string;\n title?: string;\n description?: string;\n owner?: string;\n json?: boolean;\n}\n\nconst VERBS = [\"new\", \"move\", \"rename\", \"rm\", \"list\", \"history\", \"sync\"] as const;\ntype Verb = (typeof VERBS)[number];\n\n/** How many names each verb takes, spelled once so the refusals agree with the dispatch. */\nconst NAMES: Record<Verb, { min: number; max: number; usage: string }> = {\n new: { min: 1, max: 1, usage: \"subsystem new <name> [--under <sub>] [--title <text>] [--description <text>] [--owner <name>]\" },\n move: { min: 1, max: Infinity, usage: \"subsystem move <name>... --into <sub|.>\" },\n rename: { min: 2, max: 2, usage: \"subsystem rename <old> <new>\" },\n rm: { min: 1, max: 1, usage: \"subsystem rm <name>\" },\n list: { min: 0, max: 0, usage: \"subsystem list\" },\n history: { min: 1, max: 1, usage: \"subsystem history <name>\" },\n sync: { min: 0, max: 0, usage: \"subsystem sync\" },\n};\n\n/** The flag/verb contradictions worth refusing: an ignored flag is a lie about what ran. */\nfunction flagMisuse(verb: Verb, opts: SubsystemOptions): string | null {\n if (opts.into !== undefined && verb !== \"move\") return `--into belongs to 'move' (${NAMES.move.usage}).`;\n if (opts.into === undefined && verb === \"move\") return `'move' needs a destination: ${NAMES.move.usage} ('.' unfiles).`;\n for (const [flag, value] of [\n [\"--under\", opts.under],\n [\"--title\", opts.title],\n [\"--description\", opts.description],\n [\"--owner\", opts.owner],\n ] as const) {\n if (value !== undefined && verb !== \"new\") return `${flag} belongs to 'new' (${NAMES.new.usage}).`;\n }\n return null;\n}\n\nexport function registerSubsystem(program: Command): void {\n program\n .command(\"subsystem\")\n .description(\"Manage the subsystem tree under services/ — the grouping no identity depends on\")\n .argument(\"<verb>\", VERBS.join(\" | \"))\n .argument(\"[names...]\", \"the subsystem or service names the verb applies to\")\n .option(\"--into <name>\", \"move: the destination subsystem, or '.' for the services/ root (unfiled)\")\n .option(\"--under <name>\", \"new: the parent subsystem (default: the services/ root)\")\n .option(\"--title <text>\", \"new: the subsystem's human title, kept in subsystem.yaml\")\n .option(\"--description <text>\", \"new: what the group is, kept in subsystem.yaml\")\n .option(\"--owner <name>\", \"new: who answers for the group, kept in subsystem.yaml\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (verb: string, names: string[], opts: SubsystemOptions) => {\n const json = opts.json === true;\n if (!(VERBS as readonly string[]).includes(verb)) {\n // The same code `list` gives a bad section: one mistake class, one code.\n fail(json, \"invalid-option\", `Unknown verb '${verb}'. Expected: ${VERBS.join(\" | \")}.`);\n return;\n }\n const arity = NAMES[verb as Verb];\n if (names.length < arity.min || names.length > arity.max) {\n fail(json, \"invalid-option\", `'${verb}' takes ${arity.min === arity.max ? arity.min : `${arity.min}+`} name(s): ${arity.usage}`);\n return;\n }\n const misuse = flagMisuse(verb as Verb, opts);\n if (misuse !== null) {\n fail(json, \"invalid-option\", misuse);\n return;\n }\n const config = await configOrRefuse(json);\n if (config === null) return;\n const { docsDir } = config;\n // \"services\": every verb reads or rewrites the tree that IS the fleet,\n // so a docsDir with no services/ is a refusal, never an empty answer.\n if (!docsRepoReady(json, docsDir, \"services\")) return;\n try {\n switch (verb as Verb) {\n case \"new\":\n return await runNew(docsDir, names[0]!, opts, json);\n case \"move\":\n return await runMove(docsDir, names, opts.into!, json);\n case \"rename\":\n return await runRename(docsDir, [names[0]!, names[1]!], json);\n case \"rm\":\n return await runRm(docsDir, names[0]!, json);\n case \"list\":\n return await runList(docsDir, json);\n case \"history\":\n return await runHistory(docsDir, names[0]!, json);\n case \"sync\":\n return await runSync(docsDir, json);\n }\n } catch (err) {\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n reportDocsRepoError(json, err);\n }\n });\n}\n"]}