@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (901) hide show
  1. package/CHANGELOG.md +3448 -0
  2. package/COMPARISON.md +91 -3
  3. package/CONTRIBUTING.md +37 -0
  4. package/MIGRATING-from-OpenSpec.md +47 -23
  5. package/QUICKSTART.md +189 -12
  6. package/README.md +274 -65
  7. package/ROADMAP.md +572 -31
  8. package/SCHEMA.md +1709 -155
  9. package/WORKFLOW.md +298 -72
  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/adopt/render.js +50 -9
  15. package/dist/commands/adopt/render.js.map +1 -1
  16. package/dist/commands/archive/archive.js +16 -19
  17. package/dist/commands/archive/archive.js.map +1 -1
  18. package/dist/commands/archive/closing.js +42 -0
  19. package/dist/commands/archive/closing.js.map +1 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
  21. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
  22. package/dist/commands/archive/plan/contracts/consumers.js +56 -0
  23. package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
  24. package/dist/commands/archive/plan/contracts/openapi.js +77 -43
  25. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
  26. package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
  27. package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
  28. package/dist/commands/archive/plan/document/head.js +151 -0
  29. package/dist/commands/archive/plan/document/head.js.map +1 -0
  30. package/dist/commands/archive/plan/document/links.js +284 -0
  31. package/dist/commands/archive/plan/document/links.js.map +1 -0
  32. package/dist/commands/archive/plan/document/run.js +136 -0
  33. package/dist/commands/archive/plan/document/run.js.map +1 -0
  34. package/dist/commands/archive/plan/gate.js +21 -19
  35. package/dist/commands/archive/plan/gate.js.map +1 -1
  36. package/dist/commands/archive/plan/landscape.js +167 -30
  37. package/dist/commands/archive/plan/landscape.js.map +1 -1
  38. package/dist/commands/archive/plan/model/extending.js +85 -0
  39. package/dist/commands/archive/plan/model/extending.js.map +1 -0
  40. package/dist/commands/archive/plan/refusal.js +14 -19
  41. package/dist/commands/archive/plan/refusal.js.map +1 -1
  42. package/dist/commands/archive/plan/specs.js +137 -56
  43. package/dist/commands/archive/plan/specs.js.map +1 -1
  44. package/dist/commands/archive/plan/state.js +3 -0
  45. package/dist/commands/archive/plan/state.js.map +1 -1
  46. package/dist/commands/archive/run.js +134 -30
  47. package/dist/commands/archive/run.js.map +1 -1
  48. package/dist/commands/archive/shipped.js +49 -0
  49. package/dist/commands/archive/shipped.js.map +1 -0
  50. package/dist/commands/context/context.js +85 -18
  51. package/dist/commands/context/context.js.map +1 -1
  52. package/dist/commands/context/print.js +29 -7
  53. package/dist/commands/context/print.js.map +1 -1
  54. package/dist/commands/delta/delta.js +102 -14
  55. package/dist/commands/delta/delta.js.map +1 -1
  56. package/dist/commands/delta/print.js +17 -1
  57. package/dist/commands/delta/print.js.map +1 -1
  58. package/dist/commands/dependencies.js +3 -7
  59. package/dist/commands/dependencies.js.map +1 -1
  60. package/dist/commands/diff/diff.js +20 -27
  61. package/dist/commands/diff/diff.js.map +1 -1
  62. package/dist/commands/doctor.js +60 -1
  63. package/dist/commands/doctor.js.map +1 -1
  64. package/dist/commands/explain/explain.js +89 -13
  65. package/dist/commands/explain/explain.js.map +1 -1
  66. package/dist/commands/explore.js +16 -10
  67. package/dist/commands/explore.js.map +1 -1
  68. package/dist/commands/gate/gate.js +45 -8
  69. package/dist/commands/gate/gate.js.map +1 -1
  70. package/dist/commands/gate/print.js +15 -3
  71. package/dist/commands/gate/print.js.map +1 -1
  72. package/dist/commands/gherkin/commit.js +13 -54
  73. package/dist/commands/gherkin/commit.js.map +1 -1
  74. package/dist/commands/gherkin/gherkin.js +36 -20
  75. package/dist/commands/gherkin/gherkin.js.map +1 -1
  76. package/dist/commands/gherkin/reconcile.js +10 -13
  77. package/dist/commands/gherkin/reconcile.js.map +1 -1
  78. package/dist/commands/init/first-hour.js +44 -0
  79. package/dist/commands/init/first-hour.js.map +1 -1
  80. package/dist/commands/init/init.js +18 -22
  81. package/dist/commands/init/init.js.map +1 -1
  82. package/dist/commands/list/campaign/campaign.js +4 -6
  83. package/dist/commands/list/campaign/campaign.js.map +1 -1
  84. package/dist/commands/list/json.js +5 -7
  85. package/dist/commands/list/json.js.map +1 -1
  86. package/dist/commands/list/list.js +44 -29
  87. package/dist/commands/list/list.js.map +1 -1
  88. package/dist/commands/list/print.js +52 -9
  89. package/dist/commands/list/print.js.map +1 -1
  90. package/dist/commands/list/suites/suites.js +140 -0
  91. package/dist/commands/list/suites/suites.js.map +1 -0
  92. package/dist/commands/list/views.js +37 -34
  93. package/dist/commands/list/views.js.map +1 -1
  94. package/dist/commands/mcp/dispatch.js +91 -36
  95. package/dist/commands/mcp/dispatch.js.map +1 -1
  96. package/dist/commands/mcp/mcp.js +56 -15
  97. package/dist/commands/mcp/mcp.js.map +1 -1
  98. package/dist/commands/mcp/serve.js.map +1 -1
  99. package/dist/commands/migrate-openspec/materialize/active.js +27 -22
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
  101. package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
  102. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
  103. package/dist/commands/migrate-openspec/materialize/target.js +2 -2
  104. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
  105. package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
  106. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
  107. package/dist/commands/migrate-openspec/openspec/error.js +7 -8
  108. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
  109. package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
  110. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
  111. package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
  112. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
  113. package/dist/commands/new/capability-template.js +118 -0
  114. package/dist/commands/new/capability-template.js.map +1 -0
  115. package/dist/commands/new/commit.js +8 -22
  116. package/dist/commands/new/commit.js.map +1 -1
  117. package/dist/commands/new/modifies.js +206 -0
  118. package/dist/commands/new/modifies.js.map +1 -0
  119. package/dist/commands/new/new.js +59 -14
  120. package/dist/commands/new/new.js.map +1 -1
  121. package/dist/commands/new/templates.js +48 -124
  122. package/dist/commands/new/templates.js.map +1 -1
  123. package/dist/commands/open.js +3 -7
  124. package/dist/commands/open.js.map +1 -1
  125. package/dist/commands/policy/gate.js +27 -0
  126. package/dist/commands/policy/gate.js.map +1 -1
  127. package/dist/commands/rebase/plan.js +2 -2
  128. package/dist/commands/rebase/plan.js.map +1 -1
  129. package/dist/commands/rebase/rebase.js +60 -35
  130. package/dist/commands/rebase/rebase.js.map +1 -1
  131. package/dist/commands/seed/commit.js +55 -26
  132. package/dist/commands/seed/commit.js.map +1 -1
  133. package/dist/commands/seed/plan.js +158 -13
  134. package/dist/commands/seed/plan.js.map +1 -1
  135. package/dist/commands/seed/seed.js +13 -11
  136. package/dist/commands/seed/seed.js.map +1 -1
  137. package/dist/commands/show/feature.js +9 -5
  138. package/dist/commands/show/feature.js.map +1 -1
  139. package/dist/commands/show/introduced.js +157 -0
  140. package/dist/commands/show/introduced.js.map +1 -0
  141. package/dist/commands/show/marks.js +35 -6
  142. package/dist/commands/show/marks.js.map +1 -1
  143. package/dist/commands/show/service.js +41 -33
  144. package/dist/commands/show/service.js.map +1 -1
  145. package/dist/commands/show/show.js +17 -7
  146. package/dist/commands/show/show.js.map +1 -1
  147. package/dist/commands/status/fleet-next.js +90 -0
  148. package/dist/commands/status/fleet-next.js.map +1 -0
  149. package/dist/commands/status/json.js +2 -0
  150. package/dist/commands/status/json.js.map +1 -1
  151. package/dist/commands/status/print.js +89 -37
  152. package/dist/commands/status/print.js.map +1 -1
  153. package/dist/commands/status/status.js +3 -7
  154. package/dist/commands/status/status.js.map +1 -1
  155. package/dist/commands/steps/steps.js +103 -23
  156. package/dist/commands/steps/steps.js.map +1 -1
  157. package/dist/commands/subsystem/edit.js +7 -7
  158. package/dist/commands/subsystem/edit.js.map +1 -1
  159. package/dist/commands/subsystem/move.js +106 -46
  160. package/dist/commands/subsystem/move.js.map +1 -1
  161. package/dist/commands/subsystem/query.js +2 -4
  162. package/dist/commands/subsystem/query.js.map +1 -1
  163. package/dist/commands/subsystem/subsystem.js +4 -7
  164. package/dist/commands/subsystem/subsystem.js.map +1 -1
  165. package/dist/commands/subsystem/sync.js +289 -74
  166. package/dist/commands/subsystem/sync.js.map +1 -1
  167. package/dist/commands/subsystem/txn/exclude.js +132 -0
  168. package/dist/commands/subsystem/txn/exclude.js.map +1 -0
  169. package/dist/commands/subsystem/txn/links.js +128 -0
  170. package/dist/commands/subsystem/txn/links.js.map +1 -0
  171. package/dist/commands/subsystem/txn/report.js +174 -0
  172. package/dist/commands/subsystem/txn/report.js.map +1 -0
  173. package/dist/commands/subsystem/txn/txn.js +147 -45
  174. package/dist/commands/subsystem/txn/txn.js.map +1 -1
  175. package/dist/commands/subsystem/txn/views.js +200 -21
  176. package/dist/commands/subsystem/txn/views.js.map +1 -1
  177. package/dist/commands/tasks/actions.js +107 -0
  178. package/dist/commands/tasks/actions.js.map +1 -0
  179. package/dist/commands/tasks/render.js +253 -0
  180. package/dist/commands/tasks/render.js.map +1 -0
  181. package/dist/commands/tasks/tasks.js +119 -0
  182. package/dist/commands/tasks/tasks.js.map +1 -0
  183. package/dist/commands/unarchive/manifest.js +42 -26
  184. package/dist/commands/unarchive/manifest.js.map +1 -1
  185. package/dist/commands/unarchive/restore.js +83 -33
  186. package/dist/commands/unarchive/restore.js.map +1 -1
  187. package/dist/commands/unarchive/unarchive.js +22 -30
  188. package/dist/commands/unarchive/unarchive.js.map +1 -1
  189. package/dist/commands/validate/arch-coverage.js +78 -27
  190. package/dist/commands/validate/arch-coverage.js.map +1 -1
  191. package/dist/commands/validate/checks/fleet-shape.js +34 -126
  192. package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
  193. package/dist/commands/validate/checks/health-deps.js +9 -6
  194. package/dist/commands/validate/checks/health-deps.js.map +1 -1
  195. package/dist/commands/validate/checks/introduced.js +102 -0
  196. package/dist/commands/validate/checks/introduced.js.map +1 -0
  197. package/dist/commands/validate/checks/requirements.js +18 -8
  198. package/dist/commands/validate/checks/requirements.js.map +1 -1
  199. package/dist/commands/validate/checks/sources.js +11 -2
  200. package/dist/commands/validate/checks/sources.js.map +1 -1
  201. package/dist/commands/validate/coverage/covers-after.js +105 -0
  202. package/dist/commands/validate/coverage/covers-after.js.map +1 -0
  203. package/dist/commands/validate/feature.js +26 -20
  204. package/dist/commands/validate/feature.js.map +1 -1
  205. package/dist/commands/validate/fleet/census.js +37 -13
  206. package/dist/commands/validate/fleet/census.js.map +1 -1
  207. package/dist/commands/validate/fleet/landscape.js +144 -126
  208. package/dist/commands/validate/fleet/landscape.js.map +1 -1
  209. package/dist/commands/validate/fleet/load.js +66 -0
  210. package/dist/commands/validate/fleet/load.js.map +1 -1
  211. package/dist/commands/validate/fleet/map/attest.js +98 -0
  212. package/dist/commands/validate/fleet/map/attest.js.map +1 -0
  213. package/dist/commands/validate/fleet/map/bindings.js +107 -0
  214. package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
  215. package/dist/commands/validate/fleet/map/consumers.js +244 -0
  216. package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
  217. package/dist/commands/validate/fleet/map/isolation.js +116 -0
  218. package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
  219. package/dist/commands/validate/fleet/map/usecases.js +54 -0
  220. package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
  221. package/dist/commands/validate/fleet/obligations.js +44 -14
  222. package/dist/commands/validate/fleet/obligations.js.map +1 -1
  223. package/dist/commands/validate/fleet/scorecard/print.js +10 -2
  224. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
  225. package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
  226. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
  227. package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
  228. package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
  229. package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
  230. package/dist/commands/validate/fleet/views/ids.js +50 -15
  231. package/dist/commands/validate/fleet/views/ids.js.map +1 -1
  232. package/dist/commands/validate/fleet/views/projects.js +278 -0
  233. package/dist/commands/validate/fleet/views/projects.js.map +1 -0
  234. package/dist/commands/validate/fleet/views/root-documents.js +83 -0
  235. package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
  236. package/dist/commands/validate/fleet/views/stale.js +40 -47
  237. package/dist/commands/validate/fleet/views/stale.js.map +1 -1
  238. package/dist/commands/validate/links/corpus.js +1 -4
  239. package/dist/commands/validate/links/corpus.js.map +1 -1
  240. package/dist/commands/validate/links/glossary.js.map +1 -1
  241. package/dist/commands/validate/render/repeats.js +63 -0
  242. package/dist/commands/validate/render/repeats.js.map +1 -0
  243. package/dist/commands/validate/render/rollups.js +115 -0
  244. package/dist/commands/validate/render/rollups.js.map +1 -0
  245. package/dist/commands/validate/render/text.js +199 -0
  246. package/dist/commands/validate/render/text.js.map +1 -0
  247. package/dist/commands/validate/report.js +36 -160
  248. package/dist/commands/validate/report.js.map +1 -1
  249. package/dist/commands/validate/scope.js +113 -0
  250. package/dist/commands/validate/scope.js.map +1 -0
  251. package/dist/commands/validate/service/api.js +21 -107
  252. package/dist/commands/validate/service/api.js.map +1 -1
  253. package/dist/commands/validate/service/contracts/generated.js +134 -0
  254. package/dist/commands/validate/service/contracts/generated.js.map +1 -0
  255. package/dist/commands/validate/service/events/events.js +36 -14
  256. package/dist/commands/validate/service/events/events.js.map +1 -1
  257. package/dist/commands/validate/service/events/message-producers.js +1 -1
  258. package/dist/commands/validate/service/events/message-producers.js.map +1 -1
  259. package/dist/commands/validate/service/evidence-pins.js +56 -10
  260. package/dist/commands/validate/service/evidence-pins.js.map +1 -1
  261. package/dist/commands/validate/service/model/diverged.js +226 -0
  262. package/dist/commands/validate/service/model/diverged.js.map +1 -0
  263. package/dist/commands/validate/service/model/grade.js +163 -0
  264. package/dist/commands/validate/service/model/grade.js.map +1 -0
  265. package/dist/commands/validate/service/service.js +121 -61
  266. package/dist/commands/validate/service/service.js.map +1 -1
  267. package/dist/commands/validate/service/specs.js +88 -28
  268. package/dist/commands/validate/service/specs.js.map +1 -1
  269. package/dist/commands/validate/service/spine.js +38 -3
  270. package/dist/commands/validate/service/spine.js.map +1 -1
  271. package/dist/commands/validate/service/usecases/tags.js +113 -0
  272. package/dist/commands/validate/service/usecases/tags.js.map +1 -0
  273. package/dist/commands/validate/service/usecases/usecases.js +209 -0
  274. package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
  275. package/dist/commands/validate/validate.js +85 -60
  276. package/dist/commands/validate/validate.js.map +1 -1
  277. package/dist/commands/verify/cross/diff.js +2 -6
  278. package/dist/commands/verify/cross/diff.js.map +1 -1
  279. package/dist/commands/verify/evidence/contract.js +1 -1
  280. package/dist/commands/verify/evidence/contract.js.map +1 -1
  281. package/dist/commands/verify/evidence/read.js +12 -3
  282. package/dist/commands/verify/evidence/read.js.map +1 -1
  283. package/dist/commands/verify/frozen.js +45 -23
  284. package/dist/commands/verify/frozen.js.map +1 -1
  285. package/dist/commands/verify/record.js +69 -17
  286. package/dist/commands/verify/record.js.map +1 -1
  287. package/dist/commands/verify/report.js +27 -44
  288. package/dist/commands/verify/report.js.map +1 -1
  289. package/dist/commands/verify/results.js +112 -30
  290. package/dist/commands/verify/results.js.map +1 -1
  291. package/dist/commands/verify/verify.js +55 -52
  292. package/dist/commands/verify/verify.js.map +1 -1
  293. package/dist/commands/vouch/pack/pack.js +2 -2
  294. package/dist/commands/vouch/pack/pack.js.map +1 -1
  295. package/dist/commands/vouch/pack/print.js +1 -6
  296. package/dist/commands/vouch/pack/print.js.map +1 -1
  297. package/dist/commands/vouch/pack/sections.js +1 -2
  298. package/dist/commands/vouch/pack/sections.js.map +1 -1
  299. package/dist/commands/vouch/run.js +26 -81
  300. package/dist/commands/vouch/run.js.map +1 -1
  301. package/dist/commands/vouch/sample/plan.js +20 -34
  302. package/dist/commands/vouch/sample/plan.js.map +1 -1
  303. package/dist/commands/vouch/vet/verify.js +39 -7
  304. package/dist/commands/vouch/vet/verify.js.map +1 -1
  305. package/dist/commands/vouch/vouch.js +10 -17
  306. package/dist/commands/vouch/vouch.js.map +1 -1
  307. package/dist/core/agent/agents-md/command-map.js +81 -106
  308. package/dist/core/agent/agents-md/command-map.js.map +1 -1
  309. package/dist/core/agent/agents-md/map/explain.js +21 -9
  310. package/dist/core/agent/agents-md/map/explain.js.map +1 -1
  311. package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
  312. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
  313. package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
  314. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
  315. package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
  316. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
  317. package/dist/core/agent/agents-md/map/mcp.js +10 -7
  318. package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
  319. package/dist/core/agent/agents-md/map/status.js +24 -8
  320. package/dist/core/agent/agents-md/map/status.js.map +1 -1
  321. package/dist/core/agent/agents-md/map/subsystem.js +80 -8
  322. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
  323. package/dist/core/agent/agents-md/map/usecases.js +88 -10
  324. package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
  325. package/dist/core/agent/agents-md/refusals.js +49 -22
  326. package/dist/core/agent/agents-md/refusals.js.map +1 -1
  327. package/dist/core/agent/agents-md.js +39 -6
  328. package/dist/core/agent/agents-md.js.map +1 -1
  329. package/dist/core/agent/agents-stamp.js +10 -0
  330. package/dist/core/agent/agents-stamp.js.map +1 -1
  331. package/dist/core/agent/protocol.js +1 -1
  332. package/dist/core/agent/protocol.js.map +1 -1
  333. package/dist/core/agent/scaffold.js +10 -15
  334. package/dist/core/agent/scaffold.js.map +1 -1
  335. package/dist/core/agent/support/report.js +46 -5
  336. package/dist/core/agent/support/report.js.map +1 -1
  337. package/dist/core/agent/tools/dialects.js +1 -0
  338. package/dist/core/agent/tools/dialects.js.map +1 -1
  339. package/dist/core/agent/tools/registry.js +41 -76
  340. package/dist/core/agent/tools/registry.js.map +1 -1
  341. package/dist/core/agent/workflows/adopt.js +158 -11
  342. package/dist/core/agent/workflows/adopt.js.map +1 -1
  343. package/dist/core/agent/workflows/check.js +78 -39
  344. package/dist/core/agent/workflows/check.js.map +1 -1
  345. package/dist/core/agent/workflows/closing.js +88 -27
  346. package/dist/core/agent/workflows/closing.js.map +1 -1
  347. package/dist/core/agent/workflows/feature.js +128 -13
  348. package/dist/core/agent/workflows/feature.js.map +1 -1
  349. package/dist/core/agent/workflows/implement.js +96 -13
  350. package/dist/core/agent/workflows/implement.js.map +1 -1
  351. package/dist/core/agent/workflows/reference/authoring.js +106 -4
  352. package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
  353. package/dist/core/agent/workflows/reference/codes.js +8 -6
  354. package/dist/core/agent/workflows/reference/codes.js.map +1 -1
  355. package/dist/core/agent/workflows/reference/done-check.js +37 -15
  356. package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
  357. package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
  358. package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
  359. package/dist/core/agent/workflows/reference/reference.js +6 -3
  360. package/dist/core/agent/workflows/reference/reference.js.map +1 -1
  361. package/dist/core/agent/workflows/reference/spine.js +68 -27
  362. package/dist/core/agent/workflows/reference/spine.js.map +1 -1
  363. package/dist/core/asyncapi/baseline/plan.js +14 -81
  364. package/dist/core/asyncapi/baseline/plan.js.map +1 -1
  365. package/dist/core/asyncapi/digest.js +30 -25
  366. package/dist/core/asyncapi/digest.js.map +1 -1
  367. package/dist/core/asyncapi/merge/components.js +5 -4
  368. package/dist/core/asyncapi/merge/components.js.map +1 -1
  369. package/dist/core/asyncapi/merge/error.js +7 -2
  370. package/dist/core/asyncapi/merge/error.js.map +1 -1
  371. package/dist/core/asyncapi/merge/markers.js +32 -50
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -1
  373. package/dist/core/asyncapi/merge/merge.js +33 -53
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -1
  375. package/dist/core/asyncapi/merge/pin.js +12 -36
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -1
  377. package/dist/core/asyncapi/model.js.map +1 -1
  378. package/dist/core/asyncapi/read.js +36 -12
  379. package/dist/core/asyncapi/read.js.map +1 -1
  380. package/dist/core/brief/brief.js +96 -36
  381. package/dist/core/brief/brief.js.map +1 -1
  382. package/dist/core/brief/checks.js +138 -3
  383. package/dist/core/brief/checks.js.map +1 -1
  384. package/dist/core/brief/landscape.js +209 -130
  385. package/dist/core/brief/landscape.js.map +1 -1
  386. package/dist/core/brief/map/extend.js +84 -0
  387. package/dist/core/brief/map/extend.js.map +1 -0
  388. package/dist/core/brief/map/owed.js +266 -0
  389. package/dist/core/brief/map/owed.js.map +1 -0
  390. package/dist/core/brief/targets.js +109 -31
  391. package/dist/core/brief/targets.js.map +1 -1
  392. package/dist/core/brief/unchecked.js +14 -3
  393. package/dist/core/brief/unchecked.js.map +1 -1
  394. package/dist/core/c4/arch.js +90 -182
  395. package/dist/core/c4/arch.js.map +1 -1
  396. package/dist/core/c4/direction/direction.js +114 -0
  397. package/dist/core/c4/direction/direction.js.map +1 -0
  398. package/dist/core/c4/likec4.js +169 -14
  399. package/dist/core/c4/likec4.js.map +1 -1
  400. package/dist/core/c4/locate/unlocated.js +150 -0
  401. package/dist/core/c4/locate/unlocated.js.map +1 -0
  402. package/dist/core/c4/parsed/deployment.js +160 -0
  403. package/dist/core/c4/parsed/deployment.js.map +1 -0
  404. package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
  405. package/dist/core/c4/parsed/values.js +54 -1
  406. package/dist/core/c4/parsed/values.js.map +1 -1
  407. package/dist/core/c4/parsed/view-ids.js +39 -1
  408. package/dist/core/c4/parsed/view-ids.js.map +1 -1
  409. package/dist/core/c4/prefetch/fleet.js +134 -0
  410. package/dist/core/c4/prefetch/fleet.js.map +1 -0
  411. package/dist/core/c4/project/architecture.js +123 -7
  412. package/dist/core/c4/project/architecture.js.map +1 -1
  413. package/dist/core/c4/project/batch.js +140 -0
  414. package/dist/core/c4/project/batch.js.map +1 -0
  415. package/dist/core/c4/project/documents.js +43 -12
  416. package/dist/core/c4/project/documents.js.map +1 -1
  417. package/dist/core/c4/project/load.js +79 -43
  418. package/dist/core/c4/project/load.js.map +1 -1
  419. package/dist/core/c4/project/staged.js +277 -0
  420. package/dist/core/c4/project/staged.js.map +1 -0
  421. package/dist/core/c4/resolve/attested.js +0 -0
  422. package/dist/core/c4/resolve/attested.js.map +1 -0
  423. package/dist/core/c4/resolve/external.js +51 -0
  424. package/dist/core/c4/resolve/external.js.map +1 -0
  425. package/dist/core/c4/resolve/service.js +78 -17
  426. package/dist/core/c4/resolve/service.js.map +1 -1
  427. package/dist/core/c4/resolve/steps.js +290 -0
  428. package/dist/core/c4/resolve/steps.js.map +1 -0
  429. package/dist/core/c4/resolve/systems.js +154 -0
  430. package/dist/core/c4/resolve/systems.js.map +1 -0
  431. package/dist/core/c4/root-project/exclude.js +352 -0
  432. package/dist/core/c4/root-project/exclude.js.map +1 -0
  433. package/dist/core/c4/seed/template.js +65 -1
  434. package/dist/core/c4/seed/template.js.map +1 -1
  435. package/dist/core/c4/service-model/created/models.js +96 -0
  436. package/dist/core/c4/service-model/created/models.js.map +1 -0
  437. package/dist/core/c4/service-model/documents.js +47 -0
  438. package/dist/core/c4/service-model/documents.js.map +1 -0
  439. package/dist/core/c4/service-model/fleet/extending.js +82 -0
  440. package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
  441. package/dist/core/c4/service-model/load.js +165 -0
  442. package/dist/core/c4/service-model/load.js.map +1 -0
  443. package/dist/core/c4/service-model/renderer.js +128 -0
  444. package/dist/core/c4/service-model/renderer.js.map +1 -0
  445. package/dist/core/c4/service-model/shape.js +106 -0
  446. package/dist/core/c4/service-model/shape.js.map +1 -0
  447. package/dist/core/c4/service-model/slice.js +188 -0
  448. package/dist/core/c4/service-model/slice.js.map +1 -0
  449. package/dist/core/c4/source-mask.js +297 -10
  450. package/dist/core/c4/source-mask.js.map +1 -1
  451. package/dist/core/c4/source-scan.js +222 -141
  452. package/dist/core/c4/source-scan.js.map +1 -1
  453. package/dist/core/c4/splice/authored-source.js +79 -13
  454. package/dist/core/c4/splice/authored-source.js.map +1 -1
  455. package/dist/core/c4/splice/contract.js +20 -0
  456. package/dist/core/c4/splice/contract.js.map +1 -1
  457. package/dist/core/c4/splice/delta-blocks.js +20 -20
  458. package/dist/core/c4/splice/delta-blocks.js.map +1 -1
  459. package/dist/core/c4/splice/identity/declared.js +87 -0
  460. package/dist/core/c4/splice/identity/declared.js.map +1 -0
  461. package/dist/core/c4/splice/identity/edges.js +37 -0
  462. package/dist/core/c4/splice/identity/edges.js.map +1 -1
  463. package/dist/core/c4/splice/identity/existing.js +80 -0
  464. package/dist/core/c4/splice/identity/existing.js.map +1 -0
  465. package/dist/core/c4/splice/identity/interior.js +80 -0
  466. package/dist/core/c4/splice/identity/interior.js.map +1 -0
  467. package/dist/core/c4/splice/identity/owner.js +50 -0
  468. package/dist/core/c4/splice/identity/owner.js.map +1 -0
  469. package/dist/core/c4/splice/landscape-merge.js +182 -114
  470. package/dist/core/c4/splice/landscape-merge.js.map +1 -1
  471. package/dist/core/c4/splice/model/merge.js +151 -0
  472. package/dist/core/c4/splice/model/merge.js.map +1 -0
  473. package/dist/core/c4/splice/placement.js +160 -56
  474. package/dist/core/c4/splice/placement.js.map +1 -1
  475. package/dist/core/c4/splice/text/spot.js +131 -0
  476. package/dist/core/c4/splice/text/spot.js.map +1 -0
  477. package/dist/core/c4/workspace.js +13 -19
  478. package/dist/core/c4/workspace.js.map +1 -1
  479. package/dist/core/capabilities/capabilities.js +6 -6
  480. package/dist/core/capabilities/capabilities.js.map +1 -1
  481. package/dist/core/capabilities/delta/doc.js +7 -10
  482. package/dist/core/capabilities/delta/doc.js.map +1 -1
  483. package/dist/core/capabilities/delta/uncovered.js +2 -2
  484. package/dist/core/capabilities/delta/uncovered.js.map +1 -1
  485. package/dist/core/capabilities/findings.js +18 -22
  486. package/dist/core/capabilities/findings.js.map +1 -1
  487. package/dist/core/capabilities/realizes/findings.js +12 -19
  488. package/dist/core/capabilities/realizes/findings.js.map +1 -1
  489. package/dist/core/capabilities/realizes/join.js +0 -20
  490. package/dist/core/capabilities/realizes/join.js.map +1 -1
  491. package/dist/core/capabilities/rollup.js +6 -0
  492. package/dist/core/capabilities/rollup.js.map +1 -1
  493. package/dist/core/capabilities/tree.js +6 -28
  494. package/dist/core/capabilities/tree.js.map +1 -1
  495. package/dist/core/capabilities/usecase-join.js +3 -13
  496. package/dist/core/capabilities/usecase-join.js.map +1 -1
  497. package/dist/core/coherence/authoring/scaffold.js +11 -3
  498. package/dist/core/coherence/authoring/scaffold.js.map +1 -1
  499. package/dist/core/coherence/authoring/sentinels.js +2 -1
  500. package/dist/core/coherence/authoring/sentinels.js.map +1 -1
  501. package/dist/core/coherence/calls/called.js +52 -0
  502. package/dist/core/coherence/calls/called.js.map +1 -0
  503. package/dist/core/coherence/coherence.js +103 -22
  504. package/dist/core/coherence/coherence.js.map +1 -1
  505. package/dist/core/coherence/consumed/operations.js +70 -0
  506. package/dist/core/coherence/consumed/operations.js.map +1 -0
  507. package/dist/core/coherence/consumed/refusal.js +38 -0
  508. package/dist/core/coherence/consumed/refusal.js.map +1 -0
  509. package/dist/core/coherence/covers/health.js +85 -0
  510. package/dist/core/coherence/covers/health.js.map +1 -0
  511. package/dist/core/coherence/declared.js +60 -34
  512. package/dist/core/coherence/declared.js.map +1 -1
  513. package/dist/core/coherence/events/declared.js +44 -59
  514. package/dist/core/coherence/events/declared.js.map +1 -1
  515. package/dist/core/coherence/events/events.js +147 -16
  516. package/dist/core/coherence/events/events.js.map +1 -1
  517. package/dist/core/coherence/events/grades.js +31 -8
  518. package/dist/core/coherence/events/grades.js.map +1 -1
  519. package/dist/core/coherence/events/lookups.js +28 -87
  520. package/dist/core/coherence/events/lookups.js.map +1 -1
  521. package/dist/core/coherence/events/produced.js +100 -0
  522. package/dist/core/coherence/events/produced.js.map +1 -0
  523. package/dist/core/coherence/lookups.js +18 -78
  524. package/dist/core/coherence/lookups.js.map +1 -1
  525. package/dist/core/coherence/retired/archived.js +285 -0
  526. package/dist/core/coherence/retired/archived.js.map +1 -0
  527. package/dist/core/coherence/retired/event-pair.js +62 -0
  528. package/dist/core/coherence/retired/event-pair.js.map +1 -0
  529. package/dist/core/coherence/retired/merged.js +79 -0
  530. package/dist/core/coherence/retired/merged.js.map +1 -0
  531. package/dist/core/coherence/retired/retirement.js +49 -0
  532. package/dist/core/coherence/retired/retirement.js.map +1 -0
  533. package/dist/core/coherence/retired/revival/arrivals.js +131 -0
  534. package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
  535. package/dist/core/coherence/retired/revival/revived.js +297 -0
  536. package/dist/core/coherence/retired/revival/revived.js.map +1 -0
  537. package/dist/core/consumers/after.js +113 -0
  538. package/dist/core/consumers/after.js.map +1 -0
  539. package/dist/core/consumers/consumers.js +296 -0
  540. package/dist/core/consumers/consumers.js.map +1 -0
  541. package/dist/core/consumers/current.js +211 -0
  542. package/dist/core/consumers/current.js.map +1 -0
  543. package/dist/core/consumers/scan.js +46 -0
  544. package/dist/core/consumers/scan.js.map +1 -0
  545. package/dist/core/consumers/state.js +27 -0
  546. package/dist/core/consumers/state.js.map +1 -0
  547. package/dist/core/delta/delta.js +51 -6
  548. package/dist/core/delta/delta.js.map +1 -1
  549. package/dist/core/dependencies/fanin.js +2 -2
  550. package/dist/core/dependencies/fanin.js.map +1 -1
  551. package/dist/core/deployment/delta.js +191 -0
  552. package/dist/core/deployment/delta.js.map +1 -0
  553. package/dist/core/deployment/objects.js +145 -0
  554. package/dist/core/deployment/objects.js.map +1 -0
  555. package/dist/core/diff/base-git.js +94 -12
  556. package/dist/core/diff/base-git.js.map +1 -1
  557. package/dist/core/diff/base-state.js +49 -21
  558. package/dist/core/diff/base-state.js.map +1 -1
  559. package/dist/core/diff/joins.js +136 -0
  560. package/dist/core/diff/joins.js.map +1 -0
  561. package/dist/core/diff/scope/changed-paths.js +22 -6
  562. package/dist/core/diff/scope/changed-paths.js.map +1 -1
  563. package/dist/core/diff/scope/edges.js +82 -0
  564. package/dist/core/diff/scope/edges.js.map +1 -0
  565. package/dist/core/diff/semantic.js +100 -31
  566. package/dist/core/diff/semantic.js.map +1 -1
  567. package/dist/core/docs.js +31 -22
  568. package/dist/core/docs.js.map +1 -1
  569. package/dist/core/doctor/agents.js +34 -18
  570. package/dist/core/doctor/agents.js.map +1 -1
  571. package/dist/core/doctor/config.js +7 -3
  572. package/dist/core/doctor/config.js.map +1 -1
  573. package/dist/core/doctor/doctor.js +91 -11
  574. package/dist/core/doctor/doctor.js.map +1 -1
  575. package/dist/core/doctor/report.js.map +1 -1
  576. package/dist/core/doctor/reports/scan.js +242 -0
  577. package/dist/core/doctor/reports/scan.js.map +1 -0
  578. package/dist/core/document/apply.js +158 -11
  579. package/dist/core/document/apply.js.map +1 -1
  580. package/dist/core/document/frontmatter.js +55 -0
  581. package/dist/core/document/frontmatter.js.map +1 -1
  582. package/dist/core/document/parse.js +29 -6
  583. package/dist/core/document/parse.js.map +1 -1
  584. package/dist/core/document/scenarios.js +17 -0
  585. package/dist/core/document/scenarios.js.map +1 -1
  586. package/dist/core/document/spec.js +4 -11
  587. package/dist/core/document/spec.js.map +1 -1
  588. package/dist/core/envelope/config.js +10 -0
  589. package/dist/core/envelope/config.js.map +1 -1
  590. package/dist/core/envelope/json.js +34 -0
  591. package/dist/core/envelope/json.js.map +1 -1
  592. package/dist/core/explain/families.js +26 -21
  593. package/dist/core/explain/families.js.map +1 -1
  594. package/dist/core/explain/lookup.js +14 -1
  595. package/dist/core/explain/lookup.js.map +1 -1
  596. package/dist/core/explain/refusals.js +5 -5
  597. package/dist/core/explain/refusals.js.map +1 -1
  598. package/dist/core/explain/terms/documents.js +227 -0
  599. package/dist/core/explain/terms/documents.js.map +1 -0
  600. package/dist/core/explain/terms/done-check.js +144 -0
  601. package/dist/core/explain/terms/done-check.js.map +1 -0
  602. package/dist/core/explain/terms/entry.js +14 -0
  603. package/dist/core/explain/terms/entry.js.map +1 -0
  604. package/dist/core/explain/terms/stages.js +71 -0
  605. package/dist/core/explain/terms/stages.js.map +1 -0
  606. package/dist/core/explain/terms/tasks.js +97 -0
  607. package/dist/core/explain/terms/tasks.js.map +1 -0
  608. package/dist/core/explain/terms.js +68 -109
  609. package/dist/core/explain/terms.js.map +1 -1
  610. package/dist/core/explore/explore.js +40 -10
  611. package/dist/core/explore/explore.js.map +1 -1
  612. package/dist/core/fleet-context.js +81 -95
  613. package/dist/core/fleet-context.js.map +1 -1
  614. package/dist/core/gate/checks.js +11 -4
  615. package/dist/core/gate/checks.js.map +1 -1
  616. package/dist/core/gate/partners.js +69 -28
  617. package/dist/core/gate/partners.js.map +1 -1
  618. package/dist/core/gate/report.js.map +1 -1
  619. package/dist/core/gate/verification.js +75 -12
  620. package/dist/core/gate/verification.js.map +1 -1
  621. package/dist/core/gherkin/stale.js +13 -37
  622. package/dist/core/gherkin/stale.js.map +1 -1
  623. package/dist/core/glossary/delta.js +10 -7
  624. package/dist/core/glossary/delta.js.map +1 -1
  625. package/dist/core/glossary/tree.js +6 -19
  626. package/dist/core/glossary/tree.js.map +1 -1
  627. package/dist/core/kernel/concurrency.js +19 -0
  628. package/dist/core/kernel/concurrency.js.map +1 -1
  629. package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
  630. package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
  631. package/dist/core/kernel/path-safety.js +38 -0
  632. package/dist/core/kernel/path-safety.js.map +1 -1
  633. package/dist/core/kernel/records.js +11 -0
  634. package/dist/core/kernel/records.js.map +1 -1
  635. package/dist/core/links/backlinks.js +1 -3
  636. package/dist/core/links/backlinks.js.map +1 -1
  637. package/dist/core/links/corpus.js +51 -37
  638. package/dist/core/links/corpus.js.map +1 -1
  639. package/dist/core/links/findings.js.map +1 -1
  640. package/dist/core/links/parse.js +38 -9
  641. package/dist/core/links/parse.js.map +1 -1
  642. package/dist/core/mcp/argv.js +101 -0
  643. package/dist/core/mcp/argv.js.map +1 -1
  644. package/dist/core/mcp/author-tools.js +2 -1
  645. package/dist/core/mcp/author-tools.js.map +1 -1
  646. package/dist/core/mcp/protocol.js +2 -2
  647. package/dist/core/mcp/protocol.js.map +1 -1
  648. package/dist/core/mcp/tools.js +43 -33
  649. package/dist/core/mcp/tools.js.map +1 -1
  650. package/dist/core/openapi/baseline/gate.js +53 -12
  651. package/dist/core/openapi/baseline/gate.js.map +1 -1
  652. package/dist/core/openapi/baseline/plan.js +40 -10
  653. package/dist/core/openapi/baseline/plan.js.map +1 -1
  654. package/dist/core/openapi/baseline/record.js +0 -1
  655. package/dist/core/openapi/baseline/record.js.map +1 -1
  656. package/dist/core/openapi/contract-text.js +33 -0
  657. package/dist/core/openapi/contract-text.js.map +1 -0
  658. package/dist/core/openapi/contract-tree.js +301 -0
  659. package/dist/core/openapi/contract-tree.js.map +1 -0
  660. package/dist/core/openapi/depth.js +38 -24
  661. package/dist/core/openapi/depth.js.map +1 -1
  662. package/dist/core/openapi/digest.js +52 -2
  663. package/dist/core/openapi/digest.js.map +1 -1
  664. package/dist/core/openapi/doc.js +12 -4
  665. package/dist/core/openapi/doc.js.map +1 -1
  666. package/dist/core/openapi/merge/components.js +25 -60
  667. package/dist/core/openapi/merge/components.js.map +1 -1
  668. package/dist/core/openapi/merge/error.js +3 -13
  669. package/dist/core/openapi/merge/error.js.map +1 -1
  670. package/dist/core/openapi/merge/markers.js +26 -30
  671. package/dist/core/openapi/merge/markers.js.map +1 -1
  672. package/dist/core/openapi/merge/merge.js +28 -52
  673. package/dist/core/openapi/merge/merge.js.map +1 -1
  674. package/dist/core/openapi/merge/pin.js +17 -35
  675. package/dist/core/openapi/merge/pin.js.map +1 -1
  676. package/dist/core/openspec/decide/verdict.js.map +1 -1
  677. package/dist/core/openspec/inventory.js +4 -5
  678. package/dist/core/openspec/inventory.js.map +1 -1
  679. package/dist/core/openspec/model/mapping.js +30 -28
  680. package/dist/core/openspec/model/mapping.js.map +1 -1
  681. package/dist/core/openspec/model/model.js +12 -7
  682. package/dist/core/openspec/model/model.js.map +1 -1
  683. package/dist/core/openspec/scan/changes.js +10 -4
  684. package/dist/core/openspec/scan/changes.js.map +1 -1
  685. package/dist/core/openspec/scan/config.js +7 -16
  686. package/dist/core/openspec/scan/config.js.map +1 -1
  687. package/dist/core/openspec/scan/shape.js +63 -19
  688. package/dist/core/openspec/scan/shape.js.map +1 -1
  689. package/dist/core/openspec/scan/walk.js +21 -38
  690. package/dist/core/openspec/scan/walk.js.map +1 -1
  691. package/dist/core/pack/living.js +43 -4
  692. package/dist/core/pack/living.js.map +1 -1
  693. package/dist/core/pack/pack.js +50 -6
  694. package/dist/core/pack/pack.js.map +1 -1
  695. package/dist/core/projection/arch-slice.js +2 -2
  696. package/dist/core/projection/arch-slice.js.map +1 -1
  697. package/dist/core/projection/introduced.js +14 -0
  698. package/dist/core/projection/introduced.js.map +1 -0
  699. package/dist/core/provenance/findings.js +48 -12
  700. package/dist/core/provenance/findings.js.map +1 -1
  701. package/dist/core/provenance/git.js +33 -57
  702. package/dist/core/provenance/git.js.map +1 -1
  703. package/dist/core/provenance/gitq/moves.js +71 -114
  704. package/dist/core/provenance/gitq/moves.js.map +1 -1
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
  707. package/dist/core/provenance/sources.js +23 -6
  708. package/dist/core/provenance/sources.js.map +1 -1
  709. package/dist/core/provenance/stamp.js +5 -17
  710. package/dist/core/provenance/stamp.js.map +1 -1
  711. package/dist/core/repo/authored/paths.js +18 -0
  712. package/dist/core/repo/authored/paths.js.map +1 -1
  713. package/dist/core/repo/entries.js.map +1 -1
  714. package/dist/core/repo/paths.js +92 -6
  715. package/dist/core/repo/paths.js.map +1 -1
  716. package/dist/core/repo/repo.js +74 -14
  717. package/dist/core/repo/repo.js.map +1 -1
  718. package/dist/core/repo/tree/find.js +12 -3
  719. package/dist/core/repo/tree/find.js.map +1 -1
  720. package/dist/core/repo/tree/fs.js +27 -1
  721. package/dist/core/repo/tree/fs.js.map +1 -1
  722. package/dist/core/repo/tree/render/body.js +258 -0
  723. package/dist/core/repo/tree/render/body.js.map +1 -0
  724. package/dist/core/repo/tree/render/projects.js +182 -0
  725. package/dist/core/repo/tree/render/projects.js.map +1 -0
  726. package/dist/core/repo/tree/render/service/header.js +125 -0
  727. package/dist/core/repo/tree/render/service/header.js.map +1 -0
  728. package/dist/core/repo/tree/render/service/peers.js +28 -0
  729. package/dist/core/repo/tree/render/service/peers.js.map +1 -0
  730. package/dist/core/repo/tree/render/service/view-id.js +67 -0
  731. package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
  732. package/dist/core/repo/tree/render/service/views.js +78 -0
  733. package/dist/core/repo/tree/render/service/views.js.map +1 -0
  734. package/dist/core/repo/tree/render/stale.js +42 -0
  735. package/dist/core/repo/tree/render/stale.js.map +1 -0
  736. package/dist/core/repo/tree/render/text.js +84 -0
  737. package/dist/core/repo/tree/render/text.js.map +1 -0
  738. package/dist/core/repo/tree/render/views.js +293 -0
  739. package/dist/core/repo/tree/render/views.js.map +1 -0
  740. package/dist/core/repo/tree/walk.js +53 -32
  741. package/dist/core/repo/tree/walk.js.map +1 -1
  742. package/dist/core/results.js +47 -12
  743. package/dist/core/results.js.map +1 -1
  744. package/dist/core/scaffold/landscape.js +121 -13
  745. package/dist/core/scaffold/landscape.js.map +1 -1
  746. package/dist/core/scaffold/legacy.js +271 -0
  747. package/dist/core/scaffold/legacy.js.map +1 -0
  748. package/dist/core/staging/commit.js +26 -15
  749. package/dist/core/staging/commit.js.map +1 -1
  750. package/dist/core/staging/lock.js +74 -12
  751. package/dist/core/staging/lock.js.map +1 -1
  752. package/dist/core/staging/recovery/intent.js +2 -5
  753. package/dist/core/staging/recovery/intent.js.map +1 -1
  754. package/dist/core/staging/recovery/recover.js +84 -6
  755. package/dist/core/staging/recovery/recover.js.map +1 -1
  756. package/dist/core/staging/snapshot/manifest.js +188 -0
  757. package/dist/core/staging/snapshot/manifest.js.map +1 -0
  758. package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
  759. package/dist/core/staging/snapshot/snapshot.js.map +1 -0
  760. package/dist/core/staging/txn/forward.js +24 -14
  761. package/dist/core/staging/txn/forward.js.map +1 -1
  762. package/dist/core/staging/writes.js.map +1 -1
  763. package/dist/core/status/actions/execution.js +11 -0
  764. package/dist/core/status/actions/execution.js.map +1 -1
  765. package/dist/core/status/contracts.js +39 -15
  766. package/dist/core/status/contracts.js.map +1 -1
  767. package/dist/core/status/feature/artifacts.js +33 -8
  768. package/dist/core/status/feature/artifacts.js.map +1 -1
  769. package/dist/core/status/feature/feature.js +24 -17
  770. package/dist/core/status/feature/feature.js.map +1 -1
  771. package/dist/core/status/feature/next.js +20 -7
  772. package/dist/core/status/feature/next.js.map +1 -1
  773. package/dist/core/status/feature/words.js +96 -0
  774. package/dist/core/status/feature/words.js.map +1 -0
  775. package/dist/core/status/fleet/fleet.js +43 -14
  776. package/dist/core/status/fleet/fleet.js.map +1 -1
  777. package/dist/core/status/fleet/next.js +153 -58
  778. package/dist/core/status/fleet/next.js.map +1 -1
  779. package/dist/core/status/report.js.map +1 -1
  780. package/dist/core/status/scan.js.map +1 -1
  781. package/dist/core/status/verification.js +30 -15
  782. package/dist/core/status/verification.js.map +1 -1
  783. package/dist/core/tasks/packet.js +199 -0
  784. package/dist/core/tasks/packet.js.map +1 -0
  785. package/dist/core/tasks/record.js +43 -0
  786. package/dist/core/tasks/record.js.map +1 -0
  787. package/dist/core/tasks/sources.js +181 -0
  788. package/dist/core/tasks/sources.js.map +1 -0
  789. package/dist/core/tasks/stamps.js +76 -0
  790. package/dist/core/tasks/stamps.js.map +1 -0
  791. package/dist/core/tasks/unit.js +0 -0
  792. package/dist/core/tasks/unit.js.map +1 -0
  793. package/dist/core/usecases/capability.js +11 -14
  794. package/dist/core/usecases/capability.js.map +1 -1
  795. package/dist/core/usecases/delta/claims.js +31 -7
  796. package/dist/core/usecases/delta/claims.js.map +1 -1
  797. package/dist/core/usecases/delta/flows.js +5 -7
  798. package/dist/core/usecases/delta/flows.js.map +1 -1
  799. package/dist/core/usecases/delta/modified.js +315 -0
  800. package/dist/core/usecases/delta/modified.js.map +1 -0
  801. package/dist/core/usecases/delta/overlay.js +32 -191
  802. package/dist/core/usecases/delta/overlay.js.map +1 -1
  803. package/dist/core/usecases/fleet.js +195 -36
  804. package/dist/core/usecases/fleet.js.map +1 -1
  805. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
  806. package/dist/core/usecases/grade/capability-tag.js.map +1 -0
  807. package/dist/core/usecases/grade/feature.js +88 -0
  808. package/dist/core/usecases/grade/feature.js.map +1 -0
  809. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
  810. package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
  811. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
  812. package/dist/core/usecases/grade/steps.js.map +1 -0
  813. package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
  814. package/dist/core/usecases/grade/usecases.js.map +1 -0
  815. package/dist/core/usecases/operations.js +26 -14
  816. package/dist/core/usecases/operations.js.map +1 -1
  817. package/dist/core/usecases/place.js.map +1 -1
  818. package/dist/core/usecases/service/exclude.js +119 -0
  819. package/dist/core/usecases/service/exclude.js.map +1 -0
  820. package/dist/core/usecases/service/flows.js +164 -0
  821. package/dist/core/usecases/service/flows.js.map +1 -0
  822. package/dist/core/usecases/suites/participants.js +83 -0
  823. package/dist/core/usecases/suites/participants.js.map +1 -0
  824. package/dist/core/usecases/suites/suites.js +45 -0
  825. package/dist/core/usecases/suites/suites.js.map +1 -0
  826. package/dist/core/verify/answers.js +12 -5
  827. package/dist/core/verify/answers.js.map +1 -1
  828. package/dist/core/verify/build.js +102 -82
  829. package/dist/core/verify/build.js.map +1 -1
  830. package/dist/core/verify/checklist.js +70 -12
  831. package/dist/core/verify/checklist.js.map +1 -1
  832. package/dist/core/verify/location.js +67 -0
  833. package/dist/core/verify/location.js.map +1 -0
  834. package/dist/core/verify/pins/lint.js +3 -2
  835. package/dist/core/verify/pins/lint.js.map +1 -1
  836. package/dist/core/verify/pins/pin.js +1 -1
  837. package/dist/core/verify/pins/pin.js.map +1 -1
  838. package/dist/core/verify/read/file.js +224 -0
  839. package/dist/core/verify/read/file.js.map +1 -0
  840. package/dist/core/verify/{file.js → read/shape.js} +16 -104
  841. package/dist/core/verify/read/shape.js.map +1 -0
  842. package/dist/core/verify/read/union.js +105 -0
  843. package/dist/core/verify/read/union.js.map +1 -0
  844. package/dist/core/verify/record.js +35 -12
  845. package/dist/core/verify/record.js.map +1 -1
  846. package/dist/core/verify/store/commit.js +40 -30
  847. package/dist/core/verify/store/commit.js.map +1 -1
  848. package/dist/core/verify/store/render.js +8 -4
  849. package/dist/core/verify/store/render.js.map +1 -1
  850. package/dist/core/vocabulary/issue.js +4 -0
  851. package/dist/core/vocabulary/issue.js.map +1 -1
  852. package/dist/core/vocabulary/maturity.js +75 -4
  853. package/dist/core/vocabulary/maturity.js.map +1 -1
  854. package/dist/core/vocabulary/report.js +16 -1
  855. package/dist/core/vocabulary/report.js.map +1 -1
  856. package/examples/README.md +54 -11
  857. package/examples/docs/architecture/landscape.likec4 +62 -6
  858. package/examples/docs/architecture/services.likec4 +70 -0
  859. package/examples/docs/architecture/subsystems.likec4 +7 -0
  860. package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
  863. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
  864. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
  865. package/examples/docs/likec4.config.json +0 -1
  866. package/examples/docs/services/checkout-web/model.likec4 +39 -56
  867. package/examples/docs/services/order-service/arch.spec.md +13 -6
  868. package/examples/docs/services/order-service/asyncapi.yaml +3 -2
  869. package/examples/docs/services/order-service/model.likec4 +58 -70
  870. package/examples/docs/services/payment-service/arch.spec.md +7 -4
  871. package/examples/docs/services/payment-service/model.likec4 +38 -37
  872. package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
  873. package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
  874. package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
  875. package/examples/docs/services/platform/notification-service/health.yaml +8 -3
  876. package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
  877. package/package.json +1 -1
  878. package/dist/commands/validate/checks/vocabulary.js +0 -31
  879. package/dist/commands/validate/checks/vocabulary.js.map +0 -1
  880. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
  881. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
  882. package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
  883. package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
  884. package/dist/core/agent/agents-md/artifacts.js +0 -220
  885. package/dist/core/agent/agents-md/artifacts.js.map +0 -1
  886. package/dist/core/agent/agents-md/cycle.js +0 -165
  887. package/dist/core/agent/agents-md/cycle.js.map +0 -1
  888. package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
  889. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
  890. package/dist/core/agent/agents-md/spine.js +0 -40
  891. package/dist/core/agent/agents-md/spine.js.map +0 -1
  892. package/dist/core/coherence/events/merged.js +0 -40
  893. package/dist/core/coherence/events/merged.js.map +0 -1
  894. package/dist/core/diff/current-state.js +0 -96
  895. package/dist/core/diff/current-state.js.map +0 -1
  896. package/dist/core/diff/victims.js +0 -247
  897. package/dist/core/diff/victims.js.map +0 -1
  898. package/dist/core/repo/tree/views.js +0 -172
  899. package/dist/core/repo/tree/views.js.map +0 -1
  900. package/dist/core/staging/snapshot.js.map +0 -1
  901. package/dist/core/verify/file.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"author-tools.js","sourceRoot":"","sources":["../../../src/core/mcp/author-tools.ts"],"names":[],"mappings":"AAGA,MAAM,iBAAiB,GAAG;IACxB,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,MAAM,sBAAsB,GAAG;IAC7B,GAAG,iBAAiB;IACpB,cAAc,EAAE,IAAI;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,EACT,mFAAmF;YACnF,iIAAiI;QACnI,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,+BAA+B,EAAE;SACzG;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;YACrG,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,uCAAuC,EAAE;YACjH,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,iCAAiC,EAAE;YACnH,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,2CAA2C,EAAE;SAC9H;QACD,WAAW,EAAE,iBAAiB;KAC/B;IACD;QACE,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,QAAQ;QACjB,WAAW,EACT,4GAA4G;YAC5G,iEAAiE;QACnE,yEAAyE;QACzE,sEAAsE;QACtE,2EAA2E;QAC3E,0EAA0E;QAC1E,gDAAgD;QAChD,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,0CAA0C,EAAE;SACrH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iCAAiC,EAAE;SAC3G;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,2HAA2H;YAC3H,kEAAkE;QACpE,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,uCAAuC,EAAE;SAClH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;SAC/F;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,oFAAoF;YACpF,2DAA2D;QAC7D,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE;SAChG;QACD,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC1D;CACF,CAAC","sourcesContent":["/** Opt-in MCP writers. Vouch and a committing archive are never exposed. */\nimport type { McpTool } from \"./tools.js\";\n\nconst WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n} as const;\n\nconst SAFE_WRITE_ANNOTATIONS = {\n ...WRITE_ANNOTATIONS,\n idempotentHint: true,\n} as const;\n\nexport const MCP_AUTHOR_TOOLS: readonly McpTool[] = [\n {\n name: \"loam_new\",\n command: \"new\",\n description:\n \"Scaffold a feature in the docs repo. Opt-in writer; refuses an existing feature. \" +\n \"CLI equivalent: loam new <featureId> [--title <text>] [--touches <id>...] [--new-service <id>...] [--capability <id>...] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"new feature id, e.g. FEAT-101\" },\n ],\n flags: [\n { property: \"title\", flag: \"--title\", kind: \"string\", description: \"human title and directory slug\" },\n { property: \"touches\", flag: \"--touches\", kind: \"strings\", description: \"existing services changed; repeatable\" },\n { property: \"newServices\", flag: \"--new-service\", kind: \"strings\", description: \"services introduced; repeatable\" },\n { property: \"capabilities\", flag: \"--capability\", kind: \"strings\", description: \"business capabilities changed; repeatable\" },\n ],\n annotations: WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_rebase\",\n command: \"rebase\",\n description:\n \"Pin a feature delta to the living baselines after the agent has reconciled them. Opt-in journaled writer. \" +\n \"CLI equivalent: loam rebase [featureId] [--service <id>] --json\",\n // Optional because the REGISTERED argument is — `loam rebase` relaxed it\n // for `--living`, which names no feature — and the schema mirrors the\n // command it wraps rather than the subset this tool exposes. `--living` is\n // not offered here, so an omitted id reaches the CLI's own refusal, which\n // names the flag that makes the omission legal.\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id whose baselines were reviewed\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"restrict to one touched service\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_gherkin\",\n command: \"gherkin\",\n description:\n \"Generate loam-owned Gherkin files in the bound service repository. Opt-in journaled writer; refuses ownership conflicts. \" +\n \"CLI equivalent: loam gherkin [featureId] [--service <id>] --json\",\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id; omit for the living suite\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"service to emit for\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_archive_plan\",\n command: \"archive\",\n description:\n \"Compute the complete archive plan without writing. The server enforces --dry-run. \" +\n \"CLI equivalent: loam archive <featureId> --dry-run --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id to review\" },\n ],\n flags: [],\n fixed: [\"--dry-run\"],\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n];\n"]}
1
+ {"version":3,"file":"author-tools.js","sourceRoot":"","sources":["../../../src/core/mcp/author-tools.ts"],"names":[],"mappings":"AAGA,MAAM,iBAAiB,GAAG;IACxB,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,MAAM,sBAAsB,GAAG;IAC7B,GAAG,iBAAiB;IACpB,cAAc,EAAE,IAAI;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,EACT,mFAAmF;YACnF,0JAA0J;QAC5J,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,+BAA+B,EAAE;SACzG;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;YACrG,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,uCAAuC,EAAE;YACjH,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,iCAAiC,EAAE;YACnH,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,2CAA2C,EAAE;YAC7H,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,oHAAoH,EAAE;SACjM;QACD,WAAW,EAAE,iBAAiB;KAC/B;IACD;QACE,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,QAAQ;QACjB,WAAW,EACT,4GAA4G;YAC5G,iEAAiE;QACnE,yEAAyE;QACzE,sEAAsE;QACtE,2EAA2E;QAC3E,0EAA0E;QAC1E,gDAAgD;QAChD,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,0CAA0C,EAAE;SACrH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iCAAiC,EAAE;SAC3G;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,2HAA2H;YAC3H,kEAAkE;QACpE,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,uCAAuC,EAAE;SAClH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;SAC/F;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,oFAAoF;YACpF,2DAA2D;QAC7D,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE;SAChG;QACD,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC1D;CACF,CAAC","sourcesContent":["/** Opt-in MCP writers. Vouch and a committing archive are never exposed. */\nimport type { McpTool } from \"./tools.js\";\n\nconst WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n} as const;\n\nconst SAFE_WRITE_ANNOTATIONS = {\n ...WRITE_ANNOTATIONS,\n idempotentHint: true,\n} as const;\n\nexport const MCP_AUTHOR_TOOLS: readonly McpTool[] = [\n {\n name: \"loam_new\",\n command: \"new\",\n description:\n \"Scaffold a feature in the docs repo. Opt-in writer; refuses an existing feature. \" +\n \"CLI equivalent: loam new <featureId> [--title <text>] [--touches <id>...] [--new-service <id>...] [--capability <id>...] [--modifies <Req-ID>...] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"new feature id, e.g. FEAT-101\" },\n ],\n flags: [\n { property: \"title\", flag: \"--title\", kind: \"string\", description: \"human title and directory slug\" },\n { property: \"touches\", flag: \"--touches\", kind: \"strings\", description: \"existing services changed; repeatable\" },\n { property: \"newServices\", flag: \"--new-service\", kind: \"strings\", description: \"services introduced; repeatable\" },\n { property: \"capabilities\", flag: \"--capability\", kind: \"strings\", description: \"business capabilities changed; repeatable\" },\n { property: \"modifies\", flag: \"--modifies\", kind: \"strings\", description: \"living Requirement-IDs of touched services this feature rewrites, scaffolded as pinned MODIFIED blocks; repeatable\" },\n ],\n annotations: WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_rebase\",\n command: \"rebase\",\n description:\n \"Pin a feature delta to the living baselines after the agent has reconciled them. Opt-in journaled writer. \" +\n \"CLI equivalent: loam rebase [featureId] [--service <id>] --json\",\n // Optional because the REGISTERED argument is — `loam rebase` relaxed it\n // for `--living`, which names no feature — and the schema mirrors the\n // command it wraps rather than the subset this tool exposes. `--living` is\n // not offered here, so an omitted id reaches the CLI's own refusal, which\n // names the flag that makes the omission legal.\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id whose baselines were reviewed\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"restrict to one touched service\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_gherkin\",\n command: \"gherkin\",\n description:\n \"Generate loam-owned Gherkin files in the bound service repository. Opt-in journaled writer; refuses ownership conflicts. \" +\n \"CLI equivalent: loam gherkin [featureId] [--service <id>] --json\",\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id; omit for the living suite\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"service to emit for\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_archive_plan\",\n command: \"archive\",\n description:\n \"Compute the complete archive plan without writing. The server enforces --dry-run. \" +\n \"CLI equivalent: loam archive <featureId> --dry-run --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id to review\" },\n ],\n flags: [],\n fixed: [\"--dry-run\"],\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n];\n"]}
@@ -16,8 +16,8 @@
16
16
  */
17
17
  import { isRecord } from "../kernel/records.js";
18
18
  import { LOAM_VERSION } from "../envelope/version.js";
19
- import { toArgv } from "./argv.js";
20
- import { MCP_TOOLS, READ_ONLY_ANNOTATIONS, toInputSchema, toolByName, } from "./tools.js";
19
+ import { toArgv, toInputSchema } from "./argv.js";
20
+ import { MCP_TOOLS, READ_ONLY_ANNOTATIONS, toolByName, } from "./tools.js";
21
21
  import { AGENTS_MD } from "../agent/agents-md.js";
22
22
  import { PROTOCOLS } from "../agent/protocol.js";
23
23
  import { withoutFixTables } from "../explain/fix-tables.js";
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/core/mcp/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure JSON-RPC 2.0 + MCP routing for `loam mcp` — parse one inbound frame,\n * decide the reply. Computes and returns only: the stream loop, the stdout\n * writes and the dispatcher live in `src/commands/mcp/`, so every decision\n * here is unit-testable without a stream in sight.\n *\n * Spec revision assumed: MCP 2025-06-18 (framing note in `./framing.ts`).\n * The lifecycle is deliberately NOT policed: this server is a stateless\n * facade over a stateless CLI, its capabilities never vary, and refusing a\n * tools/call that arrives before `initialize` would protect nothing — so\n * every request is answered on its own terms, whatever came first. What IS\n * refused: JSON-RPC batch arrays (removed in 2025-06-18; the older revisions\n * this server also negotiates allowed them, and that gap is deliberate — a\n * clear -32600 with the reason beats a half-implemented batch path no real\n * MCP client exercises).\n */\nimport { isRecord } from \"../kernel/records.js\";\nimport { LOAM_VERSION } from \"../envelope/version.js\";\nimport { toArgv } from \"./argv.js\";\nimport {\n MCP_TOOLS,\n READ_ONLY_ANNOTATIONS,\n toInputSchema,\n toolByName,\n type McpTool,\n} from \"./tools.js\";\nimport { AGENTS_MD } from \"../agent/agents-md.js\";\nimport { PROTOCOLS } from \"../agent/protocol.js\";\nimport { withoutFixTables } from \"../explain/fix-tables.js\";\n\n/** JSON-RPC 2.0 error codes this server emits. */\nexport const PARSE_ERROR = -32700;\nexport const INVALID_REQUEST = -32600;\nexport const METHOD_NOT_FOUND = -32601;\nexport const INVALID_PARAMS = -32602;\nexport const INTERNAL_ERROR = -32603;\n\n/**\n * Newest first. `initialize` echoes the client's requested version when it is\n * one of these, else answers the newest — the negotiation rule the 2025-06-18\n * lifecycle spec states for servers. All three revisions are identical in\n * everything this facade implements (stdio framing, tools/list, tools/call\n * with text content) except batching, refused above.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS = [\"2025-06-18\", \"2025-03-26\", \"2024-11-05\"] as const;\nexport const LATEST_PROTOCOL_VERSION = SUPPORTED_PROTOCOL_VERSIONS[0];\n\nconst TOOL_OUTPUT_SCHEMA = {\n type: \"object\",\n required: [\"contractVersion\", \"version\", \"ok\"],\n properties: {\n contractVersion: { const: \"1.0\" },\n version: { type: \"string\" },\n ok: { type: \"boolean\" },\n error: {\n type: \"object\",\n properties: { code: { type: \"string\" }, message: { type: \"string\" } },\n required: [\"code\", \"message\"],\n additionalProperties: true,\n },\n },\n additionalProperties: true,\n} as const;\n\nconst RESOURCE_TEXT: Readonly<Record<string, string>> = {\n \"loam://orientation\": AGENTS_MD,\n ...Object.fromEntries(\n Object.entries(PROTOCOLS).map(([name, body]) => [`loam://instructions/${name}`, body]),\n ),\n \"loam://instructions/loam-check/compact\": withoutFixTables(PROTOCOLS[\"loam-check\"]!),\n};\n\n/** A response id: echoed from the request, or null when no id could be read (parse errors). */\nexport type JsonRpcId = string | number;\n\nexport interface JsonRpcResponse extends Record<string, unknown> {\n readonly jsonrpc: \"2.0\";\n readonly id: JsonRpcId | null;\n}\n\nexport function resultResponse(id: JsonRpcId | null, result: unknown): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, result };\n}\n\n/**\n * `rpcCode`, not `code`: the stable-code drift collector\n * (test/helpers/stable-codes.ts) treats every function with a parameter named\n * `code` as an emitter of loam's stable code STRINGS and demands a literal at\n * each call site. A JSON-RPC numeric code is a different vocabulary — naming\n * the parameter into that scan would make the guard demand string literals\n * where the protocol requires numbers.\n */\nexport function errorResponse(id: JsonRpcId | null, rpcCode: number, message: string): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, error: { code: rpcCode, message } };\n}\n\n/**\n * What one inbound frame asks of the serve loop:\n * - `ignore`: a blank line, or a notification — nothing goes back.\n * - `reply`: answered here, in pure code; write the response.\n * - `call`: a validated tools/call — run `argv` through the dispatcher and\n * wrap what comes back. The argv is fully built here so the loop never\n * interprets arguments.\n */\nexport type RouteOutcome =\n | { readonly kind: \"ignore\" }\n | { readonly kind: \"reply\"; readonly response: JsonRpcResponse }\n | { readonly kind: \"call\"; readonly id: JsonRpcId; readonly toolName: string; readonly argv: readonly string[] };\n\nconst reply = (response: JsonRpcResponse): RouteOutcome => ({ kind: \"reply\", response });\n\n/** One line off the wire → what to do about it. Total: every input maps to an outcome, nothing throws. */\nexport function routeLine(line: string, tools: readonly McpTool[] = MCP_TOOLS): RouteOutcome {\n if (line.trim() === \"\") return { kind: \"ignore\" };\n let message: unknown;\n try {\n message = JSON.parse(line);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n return reply(errorResponse(null, PARSE_ERROR, `Parse error: ${detail}`));\n }\n if (Array.isArray(message)) {\n // JSON-RPC batching was removed in MCP 2025-06-18; see the module comment\n // for why the older negotiated revisions refuse it too instead of half-supporting it.\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: JSON-RPC batch arrays are not supported\"));\n }\n if (!isRecord(message)) {\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: a message must be a JSON object\"));\n }\n const rawId = message[\"id\"];\n // Three id states, kept apart because they demand opposite answers. ABSENT\n // (or an explicit null, reserved for unanswerable errors) is a notification.\n // A PRESENT id that is not a string or a finite number — an object, a bool,\n // an array, a JSON `1e999` that parsed to Infinity — is a malformed REQUEST:\n // the client is waiting on a reply, and folding it into the notification\n // branch answers with silence, which for a request is a hang, not an error.\n const validId = typeof rawId === \"string\" || (typeof rawId === \"number\" && Number.isFinite(rawId)) ? rawId : null;\n if (message[\"jsonrpc\"] !== \"2.0\") {\n return reply(errorResponse(validId, INVALID_REQUEST, \"Invalid Request: jsonrpc must be the string \\\"2.0\\\"\"));\n }\n const method = message[\"method\"];\n if (typeof method !== \"string\") {\n return reply(errorResponse(validId, INVALID_REQUEST, \"Invalid Request: method must be a string\"));\n }\n if (!(\"id\" in message) || rawId === null) return { kind: \"ignore\" };\n if (validId === null) {\n // id null in the response: the request's own id is unusable, and null is\n // exactly the id JSON-RPC reserves for that answer.\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: id must be a string or a finite number\"));\n }\n return routeRequest(validId, method, message[\"params\"], tools);\n}\n\nfunction routeRequest(\n id: JsonRpcId,\n method: string,\n params: unknown,\n tools: readonly McpTool[],\n): RouteOutcome {\n switch (method) {\n case \"initialize\":\n return reply(resultResponse(id, initializeResult(params)));\n case \"ping\":\n return reply(resultResponse(id, {}));\n case \"tools/list\":\n // No pagination: the whole tool table fits in one page, so `nextCursor`\n // is omitted rather than emitted empty — the spec reads an absent\n // cursor as \"done\".\n return reply(resultResponse(id, {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: toInputSchema(tool),\n outputSchema: TOOL_OUTPUT_SCHEMA,\n // Base tools share the read-only default; opt-in authoring tools\n // carry their own mutation annotations in author-tools.ts.\n annotations: tool.annotations ?? READ_ONLY_ANNOTATIONS,\n })),\n }));\n case \"resources/list\":\n return reply(resultResponse(id, {\n resources: Object.keys(RESOURCE_TEXT).map((uri) => ({\n uri,\n name: uri === \"loam://orientation\" ? \"loam orientation\" : uri.slice(\"loam://instructions/\".length),\n description:\n uri === \"loam://orientation\"\n ? \"Small always-loaded map of a loam repository\"\n : \"Version-matched loam workflow, support protocol or reference page\",\n mimeType: \"text/markdown\",\n })),\n }));\n case \"resources/read\":\n return routeResourceRead(id, params);\n case \"tools/call\":\n return routeToolCall(id, params, tools);\n default:\n // Everything else — including a literal `shutdown`, which is LSP's\n // lifecycle and not MCP's (the MCP stdio lifecycle ends at stdin EOF).\n return reply(errorResponse(id, METHOD_NOT_FOUND, `Method not found: ${method}`));\n }\n}\n\nfunction routeResourceRead(id: JsonRpcId, params: unknown): RouteOutcome {\n if (!isRecord(params) || typeof params[\"uri\"] !== \"string\") {\n return reply(errorResponse(id, INVALID_PARAMS, \"resources/read requires params.uri\"));\n }\n const uri = params[\"uri\"];\n const text = RESOURCE_TEXT[uri];\n if (text === undefined) {\n return reply(errorResponse(id, INVALID_PARAMS, `Unknown resource '${uri}'`));\n }\n return reply(resultResponse(id, { contents: [{ uri, mimeType: \"text/markdown\", text }] }));\n}\n\nfunction routeToolCall(\n id: JsonRpcId,\n params: unknown,\n tools: readonly McpTool[],\n): RouteOutcome {\n if (!isRecord(params) || typeof params[\"name\"] !== \"string\") {\n return reply(errorResponse(id, INVALID_PARAMS, \"tools/call requires params.name naming a tool\"));\n }\n const tool = toolByName(params[\"name\"], tools);\n if (tool === undefined) {\n const names = tools.map((t) => t.name).join(\", \");\n return reply(errorResponse(id, INVALID_PARAMS, `Unknown tool '${params[\"name\"]}' — this server offers: ${names}`));\n }\n const rawArgs = params[\"arguments\"] ?? {};\n if (!isRecord(rawArgs)) {\n return reply(errorResponse(id, INVALID_PARAMS, \"tools/call params.arguments must be an object when present\"));\n }\n const built = toArgv(tool, rawArgs);\n if (!built.ok) return reply(errorResponse(id, INVALID_PARAMS, built.problem));\n return { kind: \"call\", id, toolName: tool.name, argv: built.argv };\n}\n\n/**\n * The `initialize` result. The version rule: echo the requested revision when\n * this server supports it, otherwise answer the newest it does — the client\n * then decides whether it can live with that (2025-06-18 lifecycle,\n * \"Version Negotiation\").\n */\nexport function initializeResult(params: unknown): Record<string, unknown> {\n const requested = isRecord(params) ? params[\"protocolVersion\"] : undefined;\n const negotiated =\n typeof requested === \"string\" && (SUPPORTED_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION;\n return {\n protocolVersion: negotiated,\n capabilities: {\n // The sets never change while the server lives, so no\n // listChanged notification is declared — announcing one and never\n // sending it would be a promise, not a capability.\n tools: {},\n resources: {},\n },\n serverInfo: { name: \"loam\", version: LOAM_VERSION },\n instructions:\n \"Every tool result is a loam --json envelope (contractVersion 1.0): branch on ok, \" +\n \"and on error.code when ok is false — the same machine contract the CLI prints.\",\n };\n}\n\n/** What the dispatcher hands back from one tool call, before it becomes a protocol reply. */\nexport interface ToolRunOutcome {\n readonly stdout: string;\n readonly stderr: string;\n readonly code: number;\n}\n\nexport type ToolReply =\n | { readonly kind: \"result\"; readonly result: Record<string, unknown> }\n | { readonly kind: \"error\"; readonly code: number; readonly message: string };\n\n/**\n * One tool run wrapped as an MCP tool result. The envelope rides VERBATIM in\n * content[0].text — one machine contract, not two — and again parsed as\n * structuredContent for clients that read that field.\n *\n * `isError` follows the ENVELOPE's `ok`, and the exit code only when no\n * envelope could be parsed. The two disagree on purpose for half the tool\n * set: validate, doctor, gate, context and delta all have graded answers\n * that exit 1 while reporting `ok: true` — an invalid fleet, a blocked\n * doctor, a `verdict: \"fail\"` deploy gate. Those exits are CI levers, not\n * call failures, and an MCP host renders `isError: true` as \"the call\n * failed\" and may discard structuredContent — which for loam_gate would\n * discard the exact verdict the caller asked for. `ok: false` is the one\n * signal that means \"loam refused to answer\", so it is the one isError\n * mirrors; the exit-code fallback exists only for stdout that parsed as no\n * envelope at all.\n *\n * An EMPTY stdout is a protocol error, not a quiet result: with `--json` on\n * every argv, a command that printed no envelope is a command whose answer\n * was lost, and \"nobody could look\" must stay distinguishable from any\n * genuine envelope — even a refusing one.\n */\nexport function toolReply(run: ToolRunOutcome): ToolReply {\n if (run.stdout.trim() === \"\") {\n const hint = run.stderr.trim() === \"\" ? \"\" : ` stderr: ${run.stderr.trim()}`;\n return {\n kind: \"error\",\n code: INTERNAL_ERROR,\n message: `the command exited ${run.code} without printing a --json envelope, so there is no result to return.${hint}`,\n };\n }\n let structured: Record<string, unknown> | undefined;\n try {\n const parsed: unknown = JSON.parse(run.stdout);\n // structuredContent must be an object; the envelope always is.\n structured = isRecord(parsed) ? parsed : undefined;\n } catch {\n // The fallback below handles both invalid JSON and valid non-object JSON.\n }\n if (structured === undefined) {\n // Preserve the bytes in content, but keep the declared output contract:\n // an MCP client should never have to branch on the absence of\n // structuredContent after tools/list promised a schema.\n structured = {\n contractVersion: \"1.0\",\n version: LOAM_VERSION,\n ok: false,\n error: {\n code: \"internal\",\n message: \"the command did not print a JSON object envelope\",\n },\n raw: run.stdout,\n };\n }\n const envelopeOk = structured?.[\"ok\"];\n return {\n kind: \"result\",\n result: {\n content: [{ type: \"text\", text: run.stdout }],\n structuredContent: structured,\n isError: typeof envelopeOk === \"boolean\" ? !envelopeOk : run.code !== 0,\n },\n };\n}\n"]}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/core/mcp/protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EACL,SAAS,EACT,qBAAqB,EACrB,UAAU,GAEX,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,kDAAkD;AAClD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,KAAK,CAAC;AAClC,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAAK,CAAC;AACtC,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAK,CAAC;AACvC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC;AACrC,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,KAAK,CAAC;AAErC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,YAAY,CAAU,CAAC;AAC/F,MAAM,CAAC,MAAM,uBAAuB,GAAG,2BAA2B,CAAC,CAAC,CAAC,CAAC;AAEtE,MAAM,kBAAkB,GAAG;IACzB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,CAAC,iBAAiB,EAAE,SAAS,EAAE,IAAI,CAAC;IAC9C,UAAU,EAAE;QACV,eAAe,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE;QACjC,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;QAC3B,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;QACvB,KAAK,EAAE;YACL,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACrE,QAAQ,EAAE,CAAC,MAAM,EAAE,SAAS,CAAC;YAC7B,oBAAoB,EAAE,IAAI;SAC3B;KACF;IACD,oBAAoB,EAAE,IAAI;CAClB,CAAC;AAEX,MAAM,aAAa,GAAqC;IACtD,oBAAoB,EAAE,SAAS;IAC/B,GAAG,MAAM,CAAC,WAAW,CACnB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,uBAAuB,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,CACvF;IACD,wCAAwC,EAAE,gBAAgB,CAAC,SAAS,CAAC,YAAY,CAAE,CAAC;CACrF,CAAC;AAUF,MAAM,UAAU,cAAc,CAAC,EAAoB,EAAE,MAAe;IAClE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,EAAoB,EAAE,OAAe,EAAE,OAAe;IAClF,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAAC;AACnE,CAAC;AAeD,MAAM,KAAK,GAAG,CAAC,QAAyB,EAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;AAEzF,0GAA0G;AAC1G,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,KAAK,GAAuB,SAAS;IAC3E,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IAClD,IAAI,OAAgB,CAAC;IACrB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAChE,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,WAAW,EAAE,gBAAgB,MAAM,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,0EAA0E;QAC1E,sFAAsF;QACtF,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,0DAA0D,CAAC,CAAC,CAAC;IACjH,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,kDAAkD,CAAC,CAAC,CAAC;IACzG,CAAC;IACD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,2EAA2E;IAC3E,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,yEAAyE;IACzE,4EAA4E;IAC5E,MAAM,OAAO,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IAClH,IAAI,OAAO,CAAC,SAAS,CAAC,KAAK,KAAK,EAAE,CAAC;QACjC,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,qDAAqD,CAAC,CAAC,CAAC;IAC/G,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC/B,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,EAAE,eAAe,EAAE,0CAA0C,CAAC,CAAC,CAAC;IACpG,CAAC;IACD,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;IACpE,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;QACrB,yEAAyE;QACzE,oDAAoD;QACpD,OAAO,KAAK,CAAC,aAAa,CAAC,IAAI,EAAE,eAAe,EAAE,yDAAyD,CAAC,CAAC,CAAC;IAChH,CAAC;IACD,OAAO,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,YAAY,CACnB,EAAa,EACb,MAAc,EACd,MAAe,EACf,KAAyB;IAEzB,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,YAAY;YACf,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC7D,KAAK,MAAM;YACT,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;QACvC,KAAK,YAAY;YACf,wEAAwE;YACxE,kEAAkE;YAClE,oBAAoB;YACpB,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE;gBAC9B,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;oBAC1B,IAAI,EAAE,IAAI,CAAC,IAAI;oBACf,WAAW,EAAE,IAAI,CAAC,WAAW;oBAC7B,WAAW,EAAE,aAAa,CAAC,IAAI,CAAC;oBAChC,YAAY,EAAE,kBAAkB;oBAChC,iEAAiE;oBACjE,2DAA2D;oBAC3D,WAAW,EAAE,IAAI,CAAC,WAAW,IAAI,qBAAqB;iBACvD,CAAC,CAAC;aACJ,CAAC,CAAC,CAAC;QACN,KAAK,gBAAgB;YACnB,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE;gBAC9B,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;oBAClD,GAAG;oBACH,IAAI,EAAE,GAAG,KAAK,oBAAoB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,sBAAsB,CAAC,MAAM,CAAC;oBAClG,WAAW,EACT,GAAG,KAAK,oBAAoB;wBAC1B,CAAC,CAAC,8CAA8C;wBAChD,CAAC,CAAC,mEAAmE;oBACzE,QAAQ,EAAE,eAAe;iBAC1B,CAAC,CAAC;aACJ,CAAC,CAAC,CAAC;QACN,KAAK,gBAAgB;YACnB,OAAO,iBAAiB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACvC,KAAK,YAAY;YACf,OAAO,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;QAC1C;YACE,mEAAmE;YACnE,uEAAuE;YACvE,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,gBAAgB,EAAE,qBAAqB,MAAM,EAAE,CAAC,CAAC,CAAC;IACrF,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,EAAa,EAAE,MAAe;IACvD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC3D,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,oCAAoC,CAAC,CAAC,CAAC;IACxF,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC1B,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,qBAAqB,GAAG,GAAG,CAAC,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,KAAK,CAAC,cAAc,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAC7F,CAAC;AAED,SAAS,aAAa,CACpB,EAAa,EACb,MAAe,EACf,KAAyB;IAEzB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC5D,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,+CAA+C,CAAC,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,iBAAiB,MAAM,CAAC,MAAM,CAAC,2BAA2B,KAAK,EAAE,CAAC,CAAC,CAAC;IACrH,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IAC1C,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QACvB,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,4DAA4D,CAAC,CAAC,CAAC;IAChH,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,KAAK,CAAC,EAAE;QAAE,OAAO,KAAK,CAAC,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9E,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC;AACrE,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAe;IAC9C,MAAM,SAAS,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,MAAM,UAAU,GACd,OAAO,SAAS,KAAK,QAAQ,IAAK,2BAAiD,CAAC,QAAQ,CAAC,SAAS,CAAC;QACrG,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,uBAAuB,CAAC;IAC9B,OAAO;QACL,eAAe,EAAE,UAAU;QAC3B,YAAY,EAAE;YACZ,sDAAsD;YACtD,kEAAkE;YAClE,mDAAmD;YACnD,KAAK,EAAE,EAAE;YACT,SAAS,EAAE,EAAE;SACd;QACD,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE;QACnD,YAAY,EACV,mFAAmF;YACnF,gFAAgF;KACnF,CAAC;AACJ,CAAC;AAaD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,SAAS,CAAC,GAAmB;IAC3C,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7E,OAAO;YACL,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,sBAAsB,GAAG,CAAC,IAAI,wEAAwE,IAAI,EAAE;SACtH,CAAC;IACJ,CAAC;IACD,IAAI,UAA+C,CAAC;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC/C,+DAA+D;QAC/D,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IACrD,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;IAC5E,CAAC;IACD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,wEAAwE;QACxE,8DAA8D;QAC9D,wDAAwD;QACxD,UAAU,GAAG;YACX,eAAe,EAAE,KAAK;YACtB,OAAO,EAAE,YAAY;YACrB,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,kDAAkD;aAC5D;YACD,GAAG,EAAE,GAAG,CAAC,MAAM;SAChB,CAAC;IACJ,CAAC;IACD,MAAM,UAAU,GAAG,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;IACtC,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,MAAM,EAAE;YACN,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC;YAC7C,iBAAiB,EAAE,UAAU;YAC7B,OAAO,EAAE,OAAO,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC;SACxE;KACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Pure JSON-RPC 2.0 + MCP routing for `loam mcp` — parse one inbound frame,\n * decide the reply. Computes and returns only: the stream loop, the stdout\n * writes and the dispatcher live in `src/commands/mcp/`, so every decision\n * here is unit-testable without a stream in sight.\n *\n * Spec revision assumed: MCP 2025-06-18 (framing note in `./framing.ts`).\n * The lifecycle is deliberately NOT policed: this server is a stateless\n * facade over a stateless CLI, its capabilities never vary, and refusing a\n * tools/call that arrives before `initialize` would protect nothing — so\n * every request is answered on its own terms, whatever came first. What IS\n * refused: JSON-RPC batch arrays (removed in 2025-06-18; the older revisions\n * this server also negotiates allowed them, and that gap is deliberate — a\n * clear -32600 with the reason beats a half-implemented batch path no real\n * MCP client exercises).\n */\nimport { isRecord } from \"../kernel/records.js\";\nimport { LOAM_VERSION } from \"../envelope/version.js\";\nimport { toArgv, toInputSchema } from \"./argv.js\";\nimport {\n MCP_TOOLS,\n READ_ONLY_ANNOTATIONS,\n toolByName,\n type McpTool,\n} from \"./tools.js\";\nimport { AGENTS_MD } from \"../agent/agents-md.js\";\nimport { PROTOCOLS } from \"../agent/protocol.js\";\nimport { withoutFixTables } from \"../explain/fix-tables.js\";\n\n/** JSON-RPC 2.0 error codes this server emits. */\nexport const PARSE_ERROR = -32700;\nexport const INVALID_REQUEST = -32600;\nexport const METHOD_NOT_FOUND = -32601;\nexport const INVALID_PARAMS = -32602;\nexport const INTERNAL_ERROR = -32603;\n\n/**\n * Newest first. `initialize` echoes the client's requested version when it is\n * one of these, else answers the newest — the negotiation rule the 2025-06-18\n * lifecycle spec states for servers. All three revisions are identical in\n * everything this facade implements (stdio framing, tools/list, tools/call\n * with text content) except batching, refused above.\n */\nexport const SUPPORTED_PROTOCOL_VERSIONS = [\"2025-06-18\", \"2025-03-26\", \"2024-11-05\"] as const;\nexport const LATEST_PROTOCOL_VERSION = SUPPORTED_PROTOCOL_VERSIONS[0];\n\nconst TOOL_OUTPUT_SCHEMA = {\n type: \"object\",\n required: [\"contractVersion\", \"version\", \"ok\"],\n properties: {\n contractVersion: { const: \"1.0\" },\n version: { type: \"string\" },\n ok: { type: \"boolean\" },\n error: {\n type: \"object\",\n properties: { code: { type: \"string\" }, message: { type: \"string\" } },\n required: [\"code\", \"message\"],\n additionalProperties: true,\n },\n },\n additionalProperties: true,\n} as const;\n\nconst RESOURCE_TEXT: Readonly<Record<string, string>> = {\n \"loam://orientation\": AGENTS_MD,\n ...Object.fromEntries(\n Object.entries(PROTOCOLS).map(([name, body]) => [`loam://instructions/${name}`, body]),\n ),\n \"loam://instructions/loam-check/compact\": withoutFixTables(PROTOCOLS[\"loam-check\"]!),\n};\n\n/** A response id: echoed from the request, or null when no id could be read (parse errors). */\nexport type JsonRpcId = string | number;\n\nexport interface JsonRpcResponse extends Record<string, unknown> {\n readonly jsonrpc: \"2.0\";\n readonly id: JsonRpcId | null;\n}\n\nexport function resultResponse(id: JsonRpcId | null, result: unknown): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, result };\n}\n\n/**\n * `rpcCode`, not `code`: the stable-code drift collector\n * (test/helpers/stable-codes.ts) treats every function with a parameter named\n * `code` as an emitter of loam's stable code STRINGS and demands a literal at\n * each call site. A JSON-RPC numeric code is a different vocabulary — naming\n * the parameter into that scan would make the guard demand string literals\n * where the protocol requires numbers.\n */\nexport function errorResponse(id: JsonRpcId | null, rpcCode: number, message: string): JsonRpcResponse {\n return { jsonrpc: \"2.0\", id, error: { code: rpcCode, message } };\n}\n\n/**\n * What one inbound frame asks of the serve loop:\n * - `ignore`: a blank line, or a notification — nothing goes back.\n * - `reply`: answered here, in pure code; write the response.\n * - `call`: a validated tools/call — run `argv` through the dispatcher and\n * wrap what comes back. The argv is fully built here so the loop never\n * interprets arguments.\n */\nexport type RouteOutcome =\n | { readonly kind: \"ignore\" }\n | { readonly kind: \"reply\"; readonly response: JsonRpcResponse }\n | { readonly kind: \"call\"; readonly id: JsonRpcId; readonly toolName: string; readonly argv: readonly string[] };\n\nconst reply = (response: JsonRpcResponse): RouteOutcome => ({ kind: \"reply\", response });\n\n/** One line off the wire → what to do about it. Total: every input maps to an outcome, nothing throws. */\nexport function routeLine(line: string, tools: readonly McpTool[] = MCP_TOOLS): RouteOutcome {\n if (line.trim() === \"\") return { kind: \"ignore\" };\n let message: unknown;\n try {\n message = JSON.parse(line);\n } catch (err) {\n const detail = err instanceof Error ? err.message : String(err);\n return reply(errorResponse(null, PARSE_ERROR, `Parse error: ${detail}`));\n }\n if (Array.isArray(message)) {\n // JSON-RPC batching was removed in MCP 2025-06-18; see the module comment\n // for why the older negotiated revisions refuse it too instead of half-supporting it.\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: JSON-RPC batch arrays are not supported\"));\n }\n if (!isRecord(message)) {\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: a message must be a JSON object\"));\n }\n const rawId = message[\"id\"];\n // Three id states, kept apart because they demand opposite answers. ABSENT\n // (or an explicit null, reserved for unanswerable errors) is a notification.\n // A PRESENT id that is not a string or a finite number — an object, a bool,\n // an array, a JSON `1e999` that parsed to Infinity — is a malformed REQUEST:\n // the client is waiting on a reply, and folding it into the notification\n // branch answers with silence, which for a request is a hang, not an error.\n const validId = typeof rawId === \"string\" || (typeof rawId === \"number\" && Number.isFinite(rawId)) ? rawId : null;\n if (message[\"jsonrpc\"] !== \"2.0\") {\n return reply(errorResponse(validId, INVALID_REQUEST, \"Invalid Request: jsonrpc must be the string \\\"2.0\\\"\"));\n }\n const method = message[\"method\"];\n if (typeof method !== \"string\") {\n return reply(errorResponse(validId, INVALID_REQUEST, \"Invalid Request: method must be a string\"));\n }\n if (!(\"id\" in message) || rawId === null) return { kind: \"ignore\" };\n if (validId === null) {\n // id null in the response: the request's own id is unusable, and null is\n // exactly the id JSON-RPC reserves for that answer.\n return reply(errorResponse(null, INVALID_REQUEST, \"Invalid Request: id must be a string or a finite number\"));\n }\n return routeRequest(validId, method, message[\"params\"], tools);\n}\n\nfunction routeRequest(\n id: JsonRpcId,\n method: string,\n params: unknown,\n tools: readonly McpTool[],\n): RouteOutcome {\n switch (method) {\n case \"initialize\":\n return reply(resultResponse(id, initializeResult(params)));\n case \"ping\":\n return reply(resultResponse(id, {}));\n case \"tools/list\":\n // No pagination: the whole tool table fits in one page, so `nextCursor`\n // is omitted rather than emitted empty — the spec reads an absent\n // cursor as \"done\".\n return reply(resultResponse(id, {\n tools: tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: toInputSchema(tool),\n outputSchema: TOOL_OUTPUT_SCHEMA,\n // Base tools share the read-only default; opt-in authoring tools\n // carry their own mutation annotations in author-tools.ts.\n annotations: tool.annotations ?? READ_ONLY_ANNOTATIONS,\n })),\n }));\n case \"resources/list\":\n return reply(resultResponse(id, {\n resources: Object.keys(RESOURCE_TEXT).map((uri) => ({\n uri,\n name: uri === \"loam://orientation\" ? \"loam orientation\" : uri.slice(\"loam://instructions/\".length),\n description:\n uri === \"loam://orientation\"\n ? \"Small always-loaded map of a loam repository\"\n : \"Version-matched loam workflow, support protocol or reference page\",\n mimeType: \"text/markdown\",\n })),\n }));\n case \"resources/read\":\n return routeResourceRead(id, params);\n case \"tools/call\":\n return routeToolCall(id, params, tools);\n default:\n // Everything else — including a literal `shutdown`, which is LSP's\n // lifecycle and not MCP's (the MCP stdio lifecycle ends at stdin EOF).\n return reply(errorResponse(id, METHOD_NOT_FOUND, `Method not found: ${method}`));\n }\n}\n\nfunction routeResourceRead(id: JsonRpcId, params: unknown): RouteOutcome {\n if (!isRecord(params) || typeof params[\"uri\"] !== \"string\") {\n return reply(errorResponse(id, INVALID_PARAMS, \"resources/read requires params.uri\"));\n }\n const uri = params[\"uri\"];\n const text = RESOURCE_TEXT[uri];\n if (text === undefined) {\n return reply(errorResponse(id, INVALID_PARAMS, `Unknown resource '${uri}'`));\n }\n return reply(resultResponse(id, { contents: [{ uri, mimeType: \"text/markdown\", text }] }));\n}\n\nfunction routeToolCall(\n id: JsonRpcId,\n params: unknown,\n tools: readonly McpTool[],\n): RouteOutcome {\n if (!isRecord(params) || typeof params[\"name\"] !== \"string\") {\n return reply(errorResponse(id, INVALID_PARAMS, \"tools/call requires params.name naming a tool\"));\n }\n const tool = toolByName(params[\"name\"], tools);\n if (tool === undefined) {\n const names = tools.map((t) => t.name).join(\", \");\n return reply(errorResponse(id, INVALID_PARAMS, `Unknown tool '${params[\"name\"]}' — this server offers: ${names}`));\n }\n const rawArgs = params[\"arguments\"] ?? {};\n if (!isRecord(rawArgs)) {\n return reply(errorResponse(id, INVALID_PARAMS, \"tools/call params.arguments must be an object when present\"));\n }\n const built = toArgv(tool, rawArgs);\n if (!built.ok) return reply(errorResponse(id, INVALID_PARAMS, built.problem));\n return { kind: \"call\", id, toolName: tool.name, argv: built.argv };\n}\n\n/**\n * The `initialize` result. The version rule: echo the requested revision when\n * this server supports it, otherwise answer the newest it does — the client\n * then decides whether it can live with that (2025-06-18 lifecycle,\n * \"Version Negotiation\").\n */\nexport function initializeResult(params: unknown): Record<string, unknown> {\n const requested = isRecord(params) ? params[\"protocolVersion\"] : undefined;\n const negotiated =\n typeof requested === \"string\" && (SUPPORTED_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION;\n return {\n protocolVersion: negotiated,\n capabilities: {\n // The sets never change while the server lives, so no\n // listChanged notification is declared — announcing one and never\n // sending it would be a promise, not a capability.\n tools: {},\n resources: {},\n },\n serverInfo: { name: \"loam\", version: LOAM_VERSION },\n instructions:\n \"Every tool result is a loam --json envelope (contractVersion 1.0): branch on ok, \" +\n \"and on error.code when ok is false — the same machine contract the CLI prints.\",\n };\n}\n\n/** What the dispatcher hands back from one tool call, before it becomes a protocol reply. */\nexport interface ToolRunOutcome {\n readonly stdout: string;\n readonly stderr: string;\n readonly code: number;\n}\n\nexport type ToolReply =\n | { readonly kind: \"result\"; readonly result: Record<string, unknown> }\n | { readonly kind: \"error\"; readonly code: number; readonly message: string };\n\n/**\n * One tool run wrapped as an MCP tool result. The envelope rides VERBATIM in\n * content[0].text — one machine contract, not two — and again parsed as\n * structuredContent for clients that read that field.\n *\n * `isError` follows the ENVELOPE's `ok`, and the exit code only when no\n * envelope could be parsed. The two disagree on purpose for half the tool\n * set: validate, doctor, gate, context and delta all have graded answers\n * that exit 1 while reporting `ok: true` — an invalid fleet, a blocked\n * doctor, a `verdict: \"fail\"` deploy gate. Those exits are CI levers, not\n * call failures, and an MCP host renders `isError: true` as \"the call\n * failed\" and may discard structuredContent — which for loam_gate would\n * discard the exact verdict the caller asked for. `ok: false` is the one\n * signal that means \"loam refused to answer\", so it is the one isError\n * mirrors; the exit-code fallback exists only for stdout that parsed as no\n * envelope at all.\n *\n * An EMPTY stdout is a protocol error, not a quiet result: with `--json` on\n * every argv, a command that printed no envelope is a command whose answer\n * was lost, and \"nobody could look\" must stay distinguishable from any\n * genuine envelope — even a refusing one.\n */\nexport function toolReply(run: ToolRunOutcome): ToolReply {\n if (run.stdout.trim() === \"\") {\n const hint = run.stderr.trim() === \"\" ? \"\" : ` stderr: ${run.stderr.trim()}`;\n return {\n kind: \"error\",\n code: INTERNAL_ERROR,\n message: `the command exited ${run.code} without printing a --json envelope, so there is no result to return.${hint}`,\n };\n }\n let structured: Record<string, unknown> | undefined;\n try {\n const parsed: unknown = JSON.parse(run.stdout);\n // structuredContent must be an object; the envelope always is.\n structured = isRecord(parsed) ? parsed : undefined;\n } catch {\n // The fallback below handles both invalid JSON and valid non-object JSON.\n }\n if (structured === undefined) {\n // Preserve the bytes in content, but keep the declared output contract:\n // an MCP client should never have to branch on the absence of\n // structuredContent after tools/list promised a schema.\n structured = {\n contractVersion: \"1.0\",\n version: LOAM_VERSION,\n ok: false,\n error: {\n code: \"internal\",\n message: \"the command did not print a JSON object envelope\",\n },\n raw: run.stdout,\n };\n }\n const envelopeOk = structured?.[\"ok\"];\n return {\n kind: \"result\",\n result: {\n content: [{ type: \"text\", text: run.stdout }],\n structuredContent: structured,\n isError: typeof envelopeOk === \"boolean\" ? !envelopeOk : run.code !== 0,\n },\n };\n}\n"]}
@@ -19,6 +19,12 @@
19
19
  * run that has not happened yet), so an MCP-only host that could not reach
20
20
  * them could not fetch the protocol its own generated skill points at.
21
21
  *
22
+ * `adopt` is here for the same reason one step later: it writes nothing — it
23
+ * emits the brief an agent then writes a baseline from — and the loam-adopt
24
+ * protocol an MCP-only host fetches through `loam_instructions` opens by
25
+ * running it. Without the tool that host could read the protocol and never
26
+ * receive the brief the protocol is about.
27
+ *
22
28
  * Every table entry mirrors a real registration in `src/commands/` — same
23
29
  * positionals, same flags, same spellings — so the contract an MCP client
24
30
  * sees is the CLI contract, not a second one. `--json` is appended by
@@ -102,9 +108,10 @@ export const MCP_TOOLS = [
102
108
  name: "loam_list",
103
109
  command: "list",
104
110
  description: "List the services and features in the docs repo. " +
105
- "CLI equivalent: loam list [section] [--archived] [--needs-work] [--review-order] [--subsystem <name>] [--owners <path>] --json",
111
+ "CLI equivalent: loam list [section] [name] [--archived] [--needs-work] [--review-order] [--subsystem <name>] [--owners <path>] --json",
106
112
  positionals: [
107
- { property: "section", required: false, variadic: false, description: "services | features | capabilities (default: services + features)" },
113
+ { property: "section", required: false, variadic: false, description: "services | features | capabilities | glossary | suites (default: services + features)" },
114
+ { property: "name", required: false, variadic: false, description: "suites only: the one suite to show" },
108
115
  ],
109
116
  flags: [
110
117
  { property: "archived", flag: "--archived", kind: "boolean", description: "include archived features" },
@@ -136,6 +143,19 @@ export const MCP_TOOLS = [
136
143
  ],
137
144
  flags: [{ ...SERVICE_FLAG, description: "service to project onto (defaults to the configured service)" }],
138
145
  },
146
+ {
147
+ name: "loam_tasks",
148
+ command: "tasks",
149
+ description: "What is still open on a feature, at which step, and what closes each unit — a read-only projection that writes nothing. " +
150
+ "CLI equivalent: loam tasks <featureId> [--service <id>] [--next] --json",
151
+ positionals: [
152
+ { property: "featureId", required: true, variadic: false, description: "feature id, e.g. FEAT-101" },
153
+ ],
154
+ flags: [
155
+ { ...SERVICE_FLAG, description: "narrow the packet to the units one service owns (a lens: no binding needed)" },
156
+ { property: "next", flag: "--next", kind: "boolean", description: "the frontier head alone — the single leaf to hand to a worker" },
157
+ ],
158
+ },
139
159
  {
140
160
  name: "loam_explore",
141
161
  command: "explore",
@@ -196,14 +216,27 @@ export const MCP_TOOLS = [
196
216
  { property: "feature", flag: "--feature", kind: "string", description: "narrow the in-flight section to this one feature" },
197
217
  ],
198
218
  },
219
+ {
220
+ name: "loam_adopt",
221
+ command: "adopt",
222
+ description: "Brief an agent to write one service's baseline docs from its code, and say what will be checked — writes nothing. " +
223
+ "CLI equivalent: loam adopt [--service <id>] [--subsystem <name>] [--targets] --json",
224
+ positionals: [],
225
+ flags: [
226
+ { ...SERVICE_FLAG, description: "service to adopt (defaults to the configured service)" },
227
+ { property: "subsystem", flag: "--subsystem", kind: "string", description: "brief a NEW service's baseline into this subsystem instead of the services/ root" },
228
+ { property: "targets", flag: "--targets", kind: "boolean", description: "only what varies by service; a `full` field names the run that carries the walk, the checks and the unchecked list" },
229
+ ],
230
+ },
199
231
  {
200
232
  name: "loam_gate",
201
233
  command: "gate",
202
234
  description: "Can this service deploy? A read-only query over recorded evidence — advisory by default. " +
203
- "CLI equivalent: loam gate [--service <id>] [--strict] --json",
235
+ "CLI equivalent: loam gate [--service <id>] [--since <ref>] [--strict] --json",
204
236
  positionals: [],
205
237
  flags: [
206
238
  { ...SERVICE_FLAG, description: "the service being deployed (defaults to the configured service)" },
239
+ { property: "since", flag: "--since", kind: "string", description: "also grade features archived after this docs-repo git ref; without it only in-flight features are read" },
207
240
  { property: "strict", flag: "--strict", kind: "boolean", description: "exit 1 on any warning too; the payload does not change" },
208
241
  ],
209
242
  },
@@ -243,9 +276,9 @@ export const MCP_TOOLS = [
243
276
  command: "instructions",
244
277
  description: "Print a workflow, support protocol or reference page, version-matched to this binary; reads no config and no docs repo, so it answers " +
245
278
  "before the repository is wired. Ask for loam-check DELIBERATELY: it is by far the largest protocol " +
246
- "(its per-code fix tables are ~83 KB of the ~84 KB it prints), and noFixTables true returns the narrowed page " +
279
+ "(almost all of what it prints is its per-code fix tables), and noFixTables true returns the narrowed page " +
247
280
  "— every paragraph that introduces a table, none of the rows — after which loam_explain answers any one code " +
248
- "a run reports in under 500 bytes. " +
281
+ "a run reports, on its own. " +
249
282
  "CLI equivalent: loam instructions [workflow] [args...] [--no-fix-tables] --json",
250
283
  positionals: [
251
284
  {
@@ -280,35 +313,12 @@ export const MCP_TOOLS = [
280
313
  export function toolByName(name, tools = MCP_TOOLS) {
281
314
  return tools.find((tool) => tool.name === name);
282
315
  }
283
- /** The MCP inputSchema for one tool: a closed object, so a typo'd argument refuses instead of vanishing. */
284
- export function toInputSchema(tool) {
285
- const properties = {};
286
- for (const positional of tool.positionals) {
287
- properties[positional.property] = positional.variadic
288
- ? { type: "array", items: { type: "string" }, description: positional.description }
289
- : { type: "string", description: positional.description };
290
- }
291
- for (const flag of tool.flags) {
292
- properties[flag.property] =
293
- flag.kind === "boolean"
294
- ? { type: "boolean", description: flag.description }
295
- : flag.kind === "strings"
296
- ? { type: "array", items: { type: "string" }, description: flag.description }
297
- : { type: "string", description: flag.description };
298
- }
299
- const required = [
300
- ...tool.positionals.filter((p) => p.required).map((p) => p.property),
301
- ...tool.flags.filter((f) => f.required === true).map((f) => f.property),
302
- ];
303
- return {
304
- type: "object",
305
- properties,
306
- ...(required.length > 0 ? { required } : {}),
307
- additionalProperties: false,
308
- };
309
- }
310
316
  // How a tool call's JSON arguments become an argv — including the refusal of
311
317
  // any string a shell-less argv would still read as a flag — lives in
312
318
  // `./argv.ts`: the table above says WHAT the tools are, that module says how
313
- // a call crosses into the CLI's own parsing.
319
+ // a call crosses into the CLI's own parsing. The inputSchema each tool is
320
+ // advertised with (`toInputSchema`) lives there too: it DECLARES the argument
321
+ // contract `toArgv` ENFORCES — the closed object, the required set, the order
322
+ // the positionals are read in — and the two halves change together or a
323
+ // client validates against one rule and is refused by another.
314
324
  //# sourceMappingURL=tools.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/core/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The curated MCP tool table: which loam commands an MCP client can reach,\n * and how a JSON argument object becomes an argv the CLI already trusts.\n *\n * This base table is read-only. Opt-in writers live in `./author-tools.ts`;\n * vouch and a committing archive remain absent: an MCP caller is definitionally\n * an agent, `loam vouch` is a HUMAN act (the CLI refuses unattended runs with\n * vouch-unattended), and exposing it here would rebuild the hole the generated\n * skill files' allowlist was narrowed to close. verify is excluded with them: its read form and its\n * attesting `--record`/`--results`/`--contract-results` form are one command,\n * and a facade that exposes \"only the read half\" of a writer is one\n * flag-mapping bug away from exposing the writer.\n *\n * The inclusion of the two commands that read no CONFIG — `explain` and\n * `instructions` — is equally deliberate, and is recorded here because the\n * gap is otherwise re-derivable as an oversight: an agent meets both BEFORE\n * the repository is wired (every generated skill's first line is `loam\n * instructions <workflow>`, and `loam explain <code>` answers a code from a\n * run that has not happened yet), so an MCP-only host that could not reach\n * them could not fetch the protocol its own generated skill points at.\n *\n * Every table entry mirrors a real registration in `src/commands/` — same\n * positionals, same flags, same spellings — so the contract an MCP client\n * sees is the CLI contract, not a second one. `--json` is appended by\n * `toArgv` unconditionally: the tool result IS the machine envelope.\n */\n\nimport { TERMS } from \"../explain/terms.js\";\n\n/**\n * The concept-term names, from the registry that owns them — `loam_explain`'s\n * schema description must not be a hand copy that silently trails TERMS.\n */\nconst TERM_LIST = TERMS.map(({ term }) => term).join(\", \");\n\n/** A positional argument, in declaration order. A variadic one is always last. */\nexport interface ToolPositional {\n readonly property: string;\n readonly required: boolean;\n /** True when the JSON argument is an array of strings spread as trailing positionals. */\n readonly variadic: boolean;\n readonly description: string;\n}\n\n/** One CLI flag: `kind` decides both the JSON Schema type and the argv shape. */\nexport interface ToolFlag {\n readonly property: string;\n readonly flag: string;\n readonly kind: \"string\" | \"boolean\" | \"strings\";\n /**\n * Set when the CLI declares the option with `requiredOption` — the schema\n * then requires the property and the argv builder refuses its absence, so\n * a client learns the requirement from the schema instead of from an\n * invalid-option envelope after the call. The shape test asserts this\n * mirrors commander's own `mandatory`, both ways.\n */\n readonly required?: true;\n readonly description: string;\n}\n\nexport interface McpTool {\n readonly name: string;\n readonly command: string;\n readonly description: string;\n readonly positionals: readonly ToolPositional[];\n readonly flags: readonly ToolFlag[];\n /** Arguments enforced by the server rather than exposed to the caller. */\n readonly fixed?: readonly string[];\n readonly annotations?: Readonly<Record<string, boolean>>;\n}\n\nconst SERVICE_FLAG = {\n property: \"service\",\n flag: \"--service\",\n kind: \"string\",\n description: \"service id (defaults to the one loam.json configures)\",\n} as const;\n\n/**\n * The tool annotations EVERY entry in this table carries — one shared literal,\n * because the table is read-only by construction and a per-tool copy is a\n * place for one of them to drift into claiming something else.\n *\n * `readOnlyHint` is the whole point: without it a host has no machine signal\n * that `loam_validate` or `loam_context` is safe, so a call that only reads\n * files falls into the same approval prompt as a mutating tool. Read-only\n * hints are what let a host auto-approve, and the reason the writers are\n * excluded from the table above is precisely so this hint can be true of\n * everything left. `openWorldHint: false` states the other half a host acts\n * on: loam reaches no network and no service — it reads the files in the\n * directory the server started in, and nothing else.\n *\n * `idempotentHint` and `destructiveHint` are deliberately ABSENT rather than\n * spelled `true`/`false`: MCP defines both as meaningful only when\n * `readOnlyHint` is false, so shipping them would be noise a reviewer has to\n * justify before deciding they mean nothing here.\n *\n * `outputSchema` lives in `./protocol.ts`, beside `toolReply`: the declaration\n * and the fallback structured envelope have to change together or a client is\n * promised structured content one branch can omit.\n */\nexport const READ_ONLY_ANNOTATIONS = { readOnlyHint: true, openWorldHint: false } as const;\n\n/**\n * The `loam_` prefix on every name: multi-server MCP hosts flatten tool names\n * into one namespace, and a bare `validate` collides with anybody else's.\n * Each description names the CLI command it mirrors, so the equivalence is\n * stated where the client reads it.\n */\nexport const MCP_TOOLS: readonly McpTool[] = [\n {\n name: \"loam_validate\",\n command: \"validate\",\n description:\n \"Validate a service (C4 + requirement coverage), a feature (delta + coverage), or the whole fleet. \" +\n \"CLI equivalent: loam validate [target] [--service <id>] [--feature <id>] [--all] [--strict] [--errors-only] --json\",\n positionals: [\n {\n property: \"target\",\n required: false,\n variadic: false,\n description: \"service or feature id (a feature wins when both match; service/feature force the reading)\",\n },\n ],\n flags: [\n { ...SERVICE_FLAG, description: \"service to validate (defaults to the configured service)\" },\n { property: \"feature\", flag: \"--feature\", kind: \"string\", description: \"validate a feature delta instead of a service\" },\n { property: \"all\", flag: \"--all\", kind: \"boolean\", description: \"validate every service and every active feature\" },\n { property: \"strict\", flag: \"--strict\", kind: \"boolean\", description: \"exit 1 on any warning too; the payload does not change\" },\n { property: \"errorsOnly\", flag: \"--errors-only\", kind: \"boolean\", description: \"print only errors and warnings; the payload does not change\" },\n ],\n },\n {\n name: \"loam_status\",\n command: \"status\",\n description:\n \"Where the work stands and what to do next, derived from the files. \" +\n \"CLI equivalent: loam status [feature] [--service <id>] --json\",\n positionals: [\n { property: \"feature\", required: false, variadic: false, description: \"feature id or directory name; omit for the whole repository\" },\n ],\n flags: [{ ...SERVICE_FLAG, description: \"narrow the per-service view to one service\" }],\n },\n {\n name: \"loam_list\",\n command: \"list\",\n description:\n \"List the services and features in the docs repo. \" +\n \"CLI equivalent: loam list [section] [--archived] [--needs-work] [--review-order] [--subsystem <name>] [--owners <path>] --json\",\n positionals: [\n { property: \"section\", required: false, variadic: false, description: \"services | features | capabilities (default: services + features)\" },\n ],\n flags: [\n { property: \"archived\", flag: \"--archived\", kind: \"boolean\", description: \"include archived features\" },\n { property: \"needsWork\", flag: \"--needs-work\", kind: \"boolean\", description: \"services only: every service below vouched, with what it is missing\" },\n { property: \"reviewOrder\", flag: \"--review-order\", kind: \"boolean\", description: \"with needsWork: order the worklist by fan-in, highest blast radius first\" },\n { property: \"subsystem\", flag: \"--subsystem\", kind: \"string\", description: \"services only: limit the listing to services filed under this subsystem, at any depth ('unfiled' selects the ones filed under none)\" },\n { property: \"owners\", flag: \"--owners\", kind: \"string\", description: \"services only: group the listing by owning team from this CODEOWNERS file (directory-pattern rules only; unsupported rules are listed as skipped, never guessed)\" },\n ],\n },\n {\n name: \"loam_show\",\n command: \"show\",\n description:\n \"Everything loam knows about a service or a feature. \" +\n \"CLI equivalent: loam show <target> [--type service|feature] --json\",\n positionals: [\n { property: \"target\", required: true, variadic: false, description: \"service id or feature id\" },\n ],\n flags: [\n { property: \"type\", flag: \"--type\", kind: \"string\", description: \"force the reading: service | feature\" },\n ],\n },\n {\n name: \"loam_delta\",\n command: \"delta\",\n description:\n \"Project a feature onto a service: why + requirement delta + C4 changes. \" +\n \"CLI equivalent: loam delta <featureId> [--service <id>] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id, e.g. FEAT-101\" },\n ],\n flags: [{ ...SERVICE_FLAG, description: \"service to project onto (defaults to the configured service)\" }],\n },\n {\n name: \"loam_explore\",\n command: \"explore\",\n description:\n \"Read the fleet around a change nobody has written down yet — writes nothing. \" +\n \"CLI equivalent: loam explore [service...] [--op <id>] [--capability <id>] [--as <FEAT>] --json\",\n positionals: [\n { property: \"services\", required: false, variadic: true, description: \"service ids the change starts from\" },\n ],\n flags: [\n { property: \"op\", flag: \"--op\", kind: \"strings\", description: \"seed from an operation instead of a service; repeatable\" },\n { property: \"capability\", flag: \"--capability\", kind: \"strings\", description: \"seed from a declared capability's realizing services; repeatable\" },\n { property: \"as\", flag: \"--as\", kind: \"string\", description: \"feature id for the suggested command line\" },\n ],\n },\n {\n name: \"loam_dependencies\",\n command: \"dependencies\",\n description:\n \"Dependencies and conflicts derived from active feature artifacts. \" +\n \"CLI equivalent: loam dependencies [featureId] --json\",\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"active feature id; omit for the whole in-flight graph\" },\n ],\n flags: [],\n },\n {\n name: \"loam_diff\",\n command: \"diff\",\n description:\n \"Semantic diff of the living docs against a base git ref of the docs repo — removals graded against their current consumers; read-only. \" +\n \"CLI equivalent: loam diff --base <ref> --json\",\n positionals: [],\n flags: [\n {\n property: \"base\",\n flag: \"--base\",\n kind: \"string\",\n required: true,\n description: \"base git ref of the docs repo (e.g. main, origin/main, a commit sha)\",\n },\n ],\n },\n {\n name: \"loam_doctor\",\n command: \"doctor\",\n description:\n \"Diagnose local loam configuration and docs-repo accessibility without writing. \" +\n \"CLI equivalent: loam doctor --json\",\n positionals: [],\n flags: [],\n },\n {\n name: \"loam_context\",\n command: \"context\",\n description:\n \"Assemble one service's whole docs slice as one deterministic briefing. \" +\n \"CLI equivalent: loam context <service> [--feature <FEAT>] --json\",\n positionals: [\n { property: \"service\", required: true, variadic: false, description: \"service id, e.g. payment-service\" },\n ],\n flags: [\n { property: \"feature\", flag: \"--feature\", kind: \"string\", description: \"narrow the in-flight section to this one feature\" },\n ],\n },\n {\n name: \"loam_gate\",\n command: \"gate\",\n description:\n \"Can this service deploy? A read-only query over recorded evidence — advisory by default. \" +\n \"CLI equivalent: loam gate [--service <id>] [--strict] --json\",\n positionals: [],\n flags: [\n { ...SERVICE_FLAG, description: \"the service being deployed (defaults to the configured service)\" },\n { property: \"strict\", flag: \"--strict\", kind: \"boolean\", description: \"exit 1 on any warning too; the payload does not change\" },\n ],\n },\n {\n name: \"loam_steps\",\n command: \"steps\",\n description:\n \"Inventory the step phrases of a service's scenarios — how many step definitions its suite needs. \" +\n \"CLI equivalent: loam steps [--service <id>] [--duplicates] --json\",\n positionals: [],\n flags: [\n { ...SERVICE_FLAG, description: \"service to inventory (defaults to the configured service)\" },\n {\n property: \"duplicates\",\n flag: \"--duplicates\",\n kind: \"boolean\",\n description: \"list only the near-duplicate groups — phrases that differ by an article or a trailing clause\",\n },\n ],\n },\n {\n name: \"loam_explain\",\n command: \"explain\",\n description:\n \"Explain a finding code, a refusal code, or a loam concept term, version-matched to this binary; reads no config and no docs repo. \" +\n \"CLI equivalent: loam explain [subject] --json\",\n positionals: [\n {\n property: \"subject\",\n required: false,\n variadic: false,\n description: `finding code (spine.op-undefined), refusal code (docs-busy), or concept term (${TERM_LIST}); omit to list the terms`,\n },\n ],\n flags: [],\n },\n {\n name: \"loam_instructions\",\n command: \"instructions\",\n description:\n \"Print a workflow, support protocol or reference page, version-matched to this binary; reads no config and no docs repo, so it answers \" +\n \"before the repository is wired. Ask for loam-check DELIBERATELY: it is by far the largest protocol \" +\n \"(its per-code fix tables are ~83 KB of the ~84 KB it prints), and noFixTables true returns the narrowed page \" +\n \"— every paragraph that introduces a table, none of the rows — after which loam_explain answers any one code \" +\n \"a run reports in under 500 bytes. \" +\n \"CLI equivalent: loam instructions [workflow] [args...] [--no-fix-tables] --json\",\n positionals: [\n {\n property: \"workflow\",\n required: false,\n variadic: false,\n description: \"workflow, support or reference name (loam-adopt, loam-report, loam-codes, …); omit to list them\",\n },\n {\n property: \"args\",\n required: false,\n variadic: true,\n description: \"values substituted for the protocol's $1, $2, … placeholders\",\n },\n ],\n flags: [\n {\n // `noFixTables`, not `fixTables`, and the mismatch with commander's own\n // attribute name (`fixTables`, because `--no-` negates) is the point:\n // `toArgv` spells a true boolean as its flag string, so a property named\n // for the option's ATTRIBUTE would make `{fixTables: true}` emit\n // `--no-fix-tables` and turn the tables off. The JSON property is named\n // for what setting it true DOES.\n property: \"noFixTables\",\n flag: \"--no-fix-tables\",\n kind: \"boolean\",\n description: \"drop the per-code fix tables; loam_explain answers any code a run reports\",\n },\n ],\n },\n];\n\nexport function toolByName(\n name: string,\n tools: readonly McpTool[] = MCP_TOOLS,\n): McpTool | undefined {\n return tools.find((tool) => tool.name === name);\n}\n\n/** The MCP inputSchema for one tool: a closed object, so a typo'd argument refuses instead of vanishing. */\nexport function toInputSchema(tool: McpTool): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n for (const positional of tool.positionals) {\n properties[positional.property] = positional.variadic\n ? { type: \"array\", items: { type: \"string\" }, description: positional.description }\n : { type: \"string\", description: positional.description };\n }\n for (const flag of tool.flags) {\n properties[flag.property] =\n flag.kind === \"boolean\"\n ? { type: \"boolean\", description: flag.description }\n : flag.kind === \"strings\"\n ? { type: \"array\", items: { type: \"string\" }, description: flag.description }\n : { type: \"string\", description: flag.description };\n }\n const required = [\n ...tool.positionals.filter((p) => p.required).map((p) => p.property),\n ...tool.flags.filter((f) => f.required === true).map((f) => f.property),\n ];\n return {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n additionalProperties: false,\n };\n}\n\n// How a tool call's JSON arguments become an argv — including the refusal of\n// any string a shell-less argv would still read as a flag — lives in\n// `./argv.ts`: the table above says WHAT the tools are, that module says how\n// a call crosses into the CLI's own parsing.\n"]}
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../../src/core/mcp/tools.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The curated MCP tool table: which loam commands an MCP client can reach,\n * and how a JSON argument object becomes an argv the CLI already trusts.\n *\n * This base table is read-only. Opt-in writers live in `./author-tools.ts`;\n * vouch and a committing archive remain absent: an MCP caller is definitionally\n * an agent, `loam vouch` is a HUMAN act (the CLI refuses unattended runs with\n * vouch-unattended), and exposing it here would rebuild the hole the generated\n * skill files' allowlist was narrowed to close. verify is excluded with them: its read form and its\n * attesting `--record`/`--results`/`--contract-results` form are one command,\n * and a facade that exposes \"only the read half\" of a writer is one\n * flag-mapping bug away from exposing the writer.\n *\n * The inclusion of the two commands that read no CONFIG — `explain` and\n * `instructions` — is equally deliberate, and is recorded here because the\n * gap is otherwise re-derivable as an oversight: an agent meets both BEFORE\n * the repository is wired (every generated skill's first line is `loam\n * instructions <workflow>`, and `loam explain <code>` answers a code from a\n * run that has not happened yet), so an MCP-only host that could not reach\n * them could not fetch the protocol its own generated skill points at.\n *\n * `adopt` is here for the same reason one step later: it writes nothing — it\n * emits the brief an agent then writes a baseline from — and the loam-adopt\n * protocol an MCP-only host fetches through `loam_instructions` opens by\n * running it. Without the tool that host could read the protocol and never\n * receive the brief the protocol is about.\n *\n * Every table entry mirrors a real registration in `src/commands/` — same\n * positionals, same flags, same spellings — so the contract an MCP client\n * sees is the CLI contract, not a second one. `--json` is appended by\n * `toArgv` unconditionally: the tool result IS the machine envelope.\n */\n\nimport { TERMS } from \"../explain/terms.js\";\n\n/**\n * The concept-term names, from the registry that owns them — `loam_explain`'s\n * schema description must not be a hand copy that silently trails TERMS.\n */\nconst TERM_LIST = TERMS.map(({ term }) => term).join(\", \");\n\n/** A positional argument, in declaration order. A variadic one is always last. */\nexport interface ToolPositional {\n readonly property: string;\n readonly required: boolean;\n /** True when the JSON argument is an array of strings spread as trailing positionals. */\n readonly variadic: boolean;\n readonly description: string;\n}\n\n/** One CLI flag: `kind` decides both the JSON Schema type and the argv shape. */\nexport interface ToolFlag {\n readonly property: string;\n readonly flag: string;\n readonly kind: \"string\" | \"boolean\" | \"strings\";\n /**\n * Set when the CLI declares the option with `requiredOption` — the schema\n * then requires the property and the argv builder refuses its absence, so\n * a client learns the requirement from the schema instead of from an\n * invalid-option envelope after the call. The shape test asserts this\n * mirrors commander's own `mandatory`, both ways.\n */\n readonly required?: true;\n readonly description: string;\n}\n\nexport interface McpTool {\n readonly name: string;\n readonly command: string;\n readonly description: string;\n readonly positionals: readonly ToolPositional[];\n readonly flags: readonly ToolFlag[];\n /** Arguments enforced by the server rather than exposed to the caller. */\n readonly fixed?: readonly string[];\n readonly annotations?: Readonly<Record<string, boolean>>;\n}\n\nconst SERVICE_FLAG = {\n property: \"service\",\n flag: \"--service\",\n kind: \"string\",\n description: \"service id (defaults to the one loam.json configures)\",\n} as const;\n\n/**\n * The tool annotations EVERY entry in this table carries — one shared literal,\n * because the table is read-only by construction and a per-tool copy is a\n * place for one of them to drift into claiming something else.\n *\n * `readOnlyHint` is the whole point: without it a host has no machine signal\n * that `loam_validate` or `loam_context` is safe, so a call that only reads\n * files falls into the same approval prompt as a mutating tool. Read-only\n * hints are what let a host auto-approve, and the reason the writers are\n * excluded from the table above is precisely so this hint can be true of\n * everything left. `openWorldHint: false` states the other half a host acts\n * on: loam reaches no network and no service — it reads the files in the\n * directory the server started in, and nothing else.\n *\n * `idempotentHint` and `destructiveHint` are deliberately ABSENT rather than\n * spelled `true`/`false`: MCP defines both as meaningful only when\n * `readOnlyHint` is false, so shipping them would be noise a reviewer has to\n * justify before deciding they mean nothing here.\n *\n * `outputSchema` lives in `./protocol.ts`, beside `toolReply`: the declaration\n * and the fallback structured envelope have to change together or a client is\n * promised structured content one branch can omit.\n */\nexport const READ_ONLY_ANNOTATIONS = { readOnlyHint: true, openWorldHint: false } as const;\n\n/**\n * The `loam_` prefix on every name: multi-server MCP hosts flatten tool names\n * into one namespace, and a bare `validate` collides with anybody else's.\n * Each description names the CLI command it mirrors, so the equivalence is\n * stated where the client reads it.\n */\nexport const MCP_TOOLS: readonly McpTool[] = [\n {\n name: \"loam_validate\",\n command: \"validate\",\n description:\n \"Validate a service (C4 + requirement coverage), a feature (delta + coverage), or the whole fleet. \" +\n \"CLI equivalent: loam validate [target] [--service <id>] [--feature <id>] [--all] [--strict] [--errors-only] --json\",\n positionals: [\n {\n property: \"target\",\n required: false,\n variadic: false,\n description: \"service or feature id (a feature wins when both match; service/feature force the reading)\",\n },\n ],\n flags: [\n { ...SERVICE_FLAG, description: \"service to validate (defaults to the configured service)\" },\n { property: \"feature\", flag: \"--feature\", kind: \"string\", description: \"validate a feature delta instead of a service\" },\n { property: \"all\", flag: \"--all\", kind: \"boolean\", description: \"validate every service and every active feature\" },\n { property: \"strict\", flag: \"--strict\", kind: \"boolean\", description: \"exit 1 on any warning too; the payload does not change\" },\n { property: \"errorsOnly\", flag: \"--errors-only\", kind: \"boolean\", description: \"print only errors and warnings; the payload does not change\" },\n ],\n },\n {\n name: \"loam_status\",\n command: \"status\",\n description:\n \"Where the work stands and what to do next, derived from the files. \" +\n \"CLI equivalent: loam status [feature] [--service <id>] --json\",\n positionals: [\n { property: \"feature\", required: false, variadic: false, description: \"feature id or directory name; omit for the whole repository\" },\n ],\n flags: [{ ...SERVICE_FLAG, description: \"narrow the per-service view to one service\" }],\n },\n {\n name: \"loam_list\",\n command: \"list\",\n description:\n \"List the services and features in the docs repo. \" +\n \"CLI equivalent: loam list [section] [name] [--archived] [--needs-work] [--review-order] [--subsystem <name>] [--owners <path>] --json\",\n positionals: [\n { property: \"section\", required: false, variadic: false, description: \"services | features | capabilities | glossary | suites (default: services + features)\" },\n { property: \"name\", required: false, variadic: false, description: \"suites only: the one suite to show\" },\n ],\n flags: [\n { property: \"archived\", flag: \"--archived\", kind: \"boolean\", description: \"include archived features\" },\n { property: \"needsWork\", flag: \"--needs-work\", kind: \"boolean\", description: \"services only: every service below vouched, with what it is missing\" },\n { property: \"reviewOrder\", flag: \"--review-order\", kind: \"boolean\", description: \"with needsWork: order the worklist by fan-in, highest blast radius first\" },\n { property: \"subsystem\", flag: \"--subsystem\", kind: \"string\", description: \"services only: limit the listing to services filed under this subsystem, at any depth ('unfiled' selects the ones filed under none)\" },\n { property: \"owners\", flag: \"--owners\", kind: \"string\", description: \"services only: group the listing by owning team from this CODEOWNERS file (directory-pattern rules only; unsupported rules are listed as skipped, never guessed)\" },\n ],\n },\n {\n name: \"loam_show\",\n command: \"show\",\n description:\n \"Everything loam knows about a service or a feature. \" +\n \"CLI equivalent: loam show <target> [--type service|feature] --json\",\n positionals: [\n { property: \"target\", required: true, variadic: false, description: \"service id or feature id\" },\n ],\n flags: [\n { property: \"type\", flag: \"--type\", kind: \"string\", description: \"force the reading: service | feature\" },\n ],\n },\n {\n name: \"loam_delta\",\n command: \"delta\",\n description:\n \"Project a feature onto a service: why + requirement delta + C4 changes. \" +\n \"CLI equivalent: loam delta <featureId> [--service <id>] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id, e.g. FEAT-101\" },\n ],\n flags: [{ ...SERVICE_FLAG, description: \"service to project onto (defaults to the configured service)\" }],\n },\n {\n name: \"loam_tasks\",\n command: \"tasks\",\n description:\n \"What is still open on a feature, at which step, and what closes each unit — a read-only projection that writes nothing. \" +\n \"CLI equivalent: loam tasks <featureId> [--service <id>] [--next] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id, e.g. FEAT-101\" },\n ],\n flags: [\n { ...SERVICE_FLAG, description: \"narrow the packet to the units one service owns (a lens: no binding needed)\" },\n { property: \"next\", flag: \"--next\", kind: \"boolean\", description: \"the frontier head alone — the single leaf to hand to a worker\" },\n ],\n },\n {\n name: \"loam_explore\",\n command: \"explore\",\n description:\n \"Read the fleet around a change nobody has written down yet — writes nothing. \" +\n \"CLI equivalent: loam explore [service...] [--op <id>] [--capability <id>] [--as <FEAT>] --json\",\n positionals: [\n { property: \"services\", required: false, variadic: true, description: \"service ids the change starts from\" },\n ],\n flags: [\n { property: \"op\", flag: \"--op\", kind: \"strings\", description: \"seed from an operation instead of a service; repeatable\" },\n { property: \"capability\", flag: \"--capability\", kind: \"strings\", description: \"seed from a declared capability's realizing services; repeatable\" },\n { property: \"as\", flag: \"--as\", kind: \"string\", description: \"feature id for the suggested command line\" },\n ],\n },\n {\n name: \"loam_dependencies\",\n command: \"dependencies\",\n description:\n \"Dependencies and conflicts derived from active feature artifacts. \" +\n \"CLI equivalent: loam dependencies [featureId] --json\",\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"active feature id; omit for the whole in-flight graph\" },\n ],\n flags: [],\n },\n {\n name: \"loam_diff\",\n command: \"diff\",\n description:\n \"Semantic diff of the living docs against a base git ref of the docs repo — removals graded against their current consumers; read-only. \" +\n \"CLI equivalent: loam diff --base <ref> --json\",\n positionals: [],\n flags: [\n {\n property: \"base\",\n flag: \"--base\",\n kind: \"string\",\n required: true,\n description: \"base git ref of the docs repo (e.g. main, origin/main, a commit sha)\",\n },\n ],\n },\n {\n name: \"loam_doctor\",\n command: \"doctor\",\n description:\n \"Diagnose local loam configuration and docs-repo accessibility without writing. \" +\n \"CLI equivalent: loam doctor --json\",\n positionals: [],\n flags: [],\n },\n {\n name: \"loam_context\",\n command: \"context\",\n description:\n \"Assemble one service's whole docs slice as one deterministic briefing. \" +\n \"CLI equivalent: loam context <service> [--feature <FEAT>] --json\",\n positionals: [\n { property: \"service\", required: true, variadic: false, description: \"service id, e.g. payment-service\" },\n ],\n flags: [\n { property: \"feature\", flag: \"--feature\", kind: \"string\", description: \"narrow the in-flight section to this one feature\" },\n ],\n },\n {\n name: \"loam_adopt\",\n command: \"adopt\",\n description:\n \"Brief an agent to write one service's baseline docs from its code, and say what will be checked — writes nothing. \" +\n \"CLI equivalent: loam adopt [--service <id>] [--subsystem <name>] [--targets] --json\",\n positionals: [],\n flags: [\n { ...SERVICE_FLAG, description: \"service to adopt (defaults to the configured service)\" },\n { property: \"subsystem\", flag: \"--subsystem\", kind: \"string\", description: \"brief a NEW service's baseline into this subsystem instead of the services/ root\" },\n { property: \"targets\", flag: \"--targets\", kind: \"boolean\", description: \"only what varies by service; a `full` field names the run that carries the walk, the checks and the unchecked list\" },\n ],\n },\n {\n name: \"loam_gate\",\n command: \"gate\",\n description:\n \"Can this service deploy? A read-only query over recorded evidence — advisory by default. \" +\n \"CLI equivalent: loam gate [--service <id>] [--since <ref>] [--strict] --json\",\n positionals: [],\n flags: [\n { ...SERVICE_FLAG, description: \"the service being deployed (defaults to the configured service)\" },\n { property: \"since\", flag: \"--since\", kind: \"string\", description: \"also grade features archived after this docs-repo git ref; without it only in-flight features are read\" },\n { property: \"strict\", flag: \"--strict\", kind: \"boolean\", description: \"exit 1 on any warning too; the payload does not change\" },\n ],\n },\n {\n name: \"loam_steps\",\n command: \"steps\",\n description:\n \"Inventory the step phrases of a service's scenarios — how many step definitions its suite needs. \" +\n \"CLI equivalent: loam steps [--service <id>] [--duplicates] --json\",\n positionals: [],\n flags: [\n { ...SERVICE_FLAG, description: \"service to inventory (defaults to the configured service)\" },\n {\n property: \"duplicates\",\n flag: \"--duplicates\",\n kind: \"boolean\",\n description: \"list only the near-duplicate groups — phrases that differ by an article or a trailing clause\",\n },\n ],\n },\n {\n name: \"loam_explain\",\n command: \"explain\",\n description:\n \"Explain a finding code, a refusal code, or a loam concept term, version-matched to this binary; reads no config and no docs repo. \" +\n \"CLI equivalent: loam explain [subject] --json\",\n positionals: [\n {\n property: \"subject\",\n required: false,\n variadic: false,\n description: `finding code (spine.op-undefined), refusal code (docs-busy), or concept term (${TERM_LIST}); omit to list the terms`,\n },\n ],\n flags: [],\n },\n {\n name: \"loam_instructions\",\n command: \"instructions\",\n description:\n \"Print a workflow, support protocol or reference page, version-matched to this binary; reads no config and no docs repo, so it answers \" +\n \"before the repository is wired. Ask for loam-check DELIBERATELY: it is by far the largest protocol \" +\n \"(almost all of what it prints is its per-code fix tables), and noFixTables true returns the narrowed page \" +\n \"— every paragraph that introduces a table, none of the rows — after which loam_explain answers any one code \" +\n \"a run reports, on its own. \" +\n \"CLI equivalent: loam instructions [workflow] [args...] [--no-fix-tables] --json\",\n positionals: [\n {\n property: \"workflow\",\n required: false,\n variadic: false,\n description: \"workflow, support or reference name (loam-adopt, loam-report, loam-codes, …); omit to list them\",\n },\n {\n property: \"args\",\n required: false,\n variadic: true,\n description: \"values substituted for the protocol's $1, $2, … placeholders\",\n },\n ],\n flags: [\n {\n // `noFixTables`, not `fixTables`, and the mismatch with commander's own\n // attribute name (`fixTables`, because `--no-` negates) is the point:\n // `toArgv` spells a true boolean as its flag string, so a property named\n // for the option's ATTRIBUTE would make `{fixTables: true}` emit\n // `--no-fix-tables` and turn the tables off. The JSON property is named\n // for what setting it true DOES.\n property: \"noFixTables\",\n flag: \"--no-fix-tables\",\n kind: \"boolean\",\n description: \"drop the per-code fix tables; loam_explain answers any code a run reports\",\n },\n ],\n },\n];\n\nexport function toolByName(\n name: string,\n tools: readonly McpTool[] = MCP_TOOLS,\n): McpTool | undefined {\n return tools.find((tool) => tool.name === name);\n}\n\n// How a tool call's JSON arguments become an argv — including the refusal of\n// any string a shell-less argv would still read as a flag — lives in\n// `./argv.ts`: the table above says WHAT the tools are, that module says how\n// a call crosses into the CLI's own parsing. The inputSchema each tool is\n// advertised with (`toInputSchema`) lives there too: it DECLARES the argument\n// contract `toArgv` ENFORCES — the closed object, the required set, the order\n// the positionals are read in — and the two halves change together or a\n// client validates against one rule and is refused by another.\n"]}
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * The baseline axis of the feature gate: which of the surfaces this delta
3
- * SPELLS does it actually edit? A feature's openapi.yaml is a complete
4
- * document, so most of it is quotation — and until the pins existed the merge
3
+ * SPELLS does it actually edit? A feature's openapi.yaml needs only what it
4
+ * changes, but it may quote more — and until the pins existed the merge
5
5
  * upserted quotations too, which reverted whatever had landed on them since.
6
6
  *
7
7
  * Extracted from `coherence/declared.ts` when the operation pin grew its two
@@ -25,14 +25,25 @@ import { entryFor, readBaselineRecord, restatedSurfaces, surfaceIn } from "./rec
25
25
  export function openapiBaselineIssues(input) {
26
26
  const { featDoc, livingDoc, service, featureId } = input;
27
27
  const issues = [];
28
- const livingBySlot = new Map(livingDoc.ops.map((op) => [`${op.method} ${op.path}`, op]));
29
- let unpinned = 0;
30
- for (const op of featDoc.ops) {
28
+ // Slot-keyed on BOTH sides, an operation with no operationId included: the
29
+ // merge replaces whatever stands at a method and path, and `loam rebase`
30
+ // pins against whatever stands there, named or not. Reading named
31
+ // operations alone, this gate refused as pinned over "no operation at that
32
+ // slot" the very pin rebase had just written over an unnamed one — the two
33
+ // could never agree — and an unpinned quote over it drew no
34
+ // `openapi.baseline-missing` at all.
35
+ const livingBySlot = new Map([...livingDoc.ops, ...livingDoc.anonymousOps].map((op) => [`${op.method} ${op.path}`, op]));
36
+ const restated = [
31
37
  // A removal marker is not a restatement of anything; its own exactness
32
38
  // check (`openapi.remove-target-mismatch`) already guards the slot.
33
- if (op.remove)
34
- continue;
39
+ ...featDoc.ops.filter((op) => !op.remove),
40
+ ...featDoc.anonymousOps,
41
+ ];
42
+ let unpinned = 0;
43
+ for (const op of restated) {
35
44
  const where = `${op.method.toUpperCase()} ${op.path}`;
45
+ // How the messages name it: the slot, and the operationId where it has one.
46
+ const named = op.id === undefined ? where : `${where} ('${op.id}')`;
36
47
  const livingOp = livingBySlot.get(`${op.method} ${op.path}`);
37
48
  if (op.basedOn !== undefined && !OPERATION_DIGEST_RE.test(op.basedOn)) {
38
49
  issues.push({
@@ -45,11 +56,36 @@ export function openapiBaselineIssues(input) {
45
56
  }
46
57
  const verdict = classifyBaselineDigests(op.basedOn, op.digest, livingOp?.digest);
47
58
  if (verdict === "unfounded") {
59
+ // Three ways here, and the message must not pick the wrong one for the
60
+ // author. A pin is only ever written over a living operation, so a pin
61
+ // with nothing living behind it usually means the operation was there
62
+ // and LEFT — a parallel feature retired it, or MOVED it to another slot
63
+ // (moving an endpoint is the most common contract edit there is). This
64
+ // used to say "drop the marker", and dropping it is exactly how the
65
+ // quote then archived as an addition and put the operation back — and
66
+ // for a move the retirement advice is wrong too: the id still lives, so
67
+ // archiving past `openapi.op-revived` would answer it at both slots.
68
+ // The living contract says which: a move leaves the id at another slot
69
+ // (and so does a retirement here followed by a re-add there, which
70
+ // reads the same from this side). The third way — a pin hand-written
71
+ // onto a genuinely new operation — is the rare one. The two addresses
72
+ // are a condition ("while it still lives there"), not a forecast: a
73
+ // delta swapping the id back defines another operation at the address
74
+ // it lives at, with or without an operationId, and the merge replaces
75
+ // it there. The revival check (coherence/retired/revival/) reads the
76
+ // contract that merge would write and stands down whenever it answers
77
+ // an id the living contract still holds — as here — at one address, so
78
+ // this must not tell the author otherwise —
79
+ // and for that delta a removal marker at the address cannot be written
80
+ // beside the other operation, hence the second remedy.
81
+ const movedTo = op.id === undefined ? [] : livingDoc.ops.filter((l) => !l.remove && l.id === op.id).map((l) => `${l.method.toUpperCase()} ${l.path}`);
48
82
  issues.push({
49
83
  severity: "error",
50
84
  code: "openapi.baseline-invalid",
51
85
  subject: service,
52
- message: `${service}: ${where} ('${op.id}') carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — a new operation has no living version to be based on; drop the marker`,
86
+ message: movedTo.length > 0
87
+ ? `${service}: ${where} ('${op.id}') carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — '${op.id}' lives at ${movedTo.join(" and ")} now: a parallel feature moved it there (or retired it here, and another re-added it there). Re-read it there and delete this operation from the delta, making any change at its new address; archived while it still lives there, it would put '${op.id}' back at ${where} as well, one operationId at two addresses. To move it back on purpose, drop the pin and add a removal marker for '${op.id}' at ${movedTo.join(" and ")} to this delta, or define another operation there.`
88
+ : `${service}: ${named} carries ${OPENAPI_BASELINE_KEY}, but the living contract has no operation at that slot — the version it was pinned to is gone. If a parallel feature retired it, re-read the living contract and delete this operation from the delta, unless this feature deliberately brings it back (then drop the pin and archive with --approve past \`openapi.op-revived\`). A genuinely new operation has no living version to be based on and carries no pin.`,
53
89
  });
54
90
  }
55
91
  else if (verdict === "stale") {
@@ -57,7 +93,7 @@ export function openapiBaselineIssues(input) {
57
93
  severity: "error",
58
94
  code: "openapi.baseline-stale",
59
95
  subject: service,
60
- message: `${service}: ${where} ('${op.id}') was written against living version ${op.basedOn}, but the living contract now holds ${livingOp.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living operation, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
96
+ message: `${service}: ${named} was written against living version ${op.basedOn}, but the living contract now holds ${livingOp.digest} — somebody landed a change to it in between, and merging this would replace theirs outright. Re-read the living operation, fold in what you still mean, then run \`loam rebase ${featureId}\`.`,
61
97
  });
62
98
  }
63
99
  else if (verdict === "unpinned" && livingOp !== undefined) {
@@ -150,9 +186,14 @@ export function openapiBaselineIssues(input) {
150
186
  // (delta/select.ts): the document is legal, but an unpinned quote is
151
187
  // exactly the shape that reverts another feature's landed change at exit
152
188
  // 0, and every count covers only values the living contract already has —
153
- // a genuinely new operation, key or component never trips it. `loam
154
- // rebase` pins a whole service in one command; `--approve` says the
155
- // unpinned merge is meant.
189
+ // a genuinely new operation, key or component never trips it. That is
190
+ // also why it cannot see a quote of an operation a parallel feature
191
+ // RETIRED: absent from living, it reads exactly like a new one — nor of
192
+ // one a parallel feature MOVED, quoted at the slot it left, since nothing
193
+ // living stands at that slot. Telling either apart from an addition takes
194
+ // the archived features' removal markers, which this gate never reads —
195
+ // `openapi.op-revived` (core/coherence/retired/) asks that question. `loam rebase` pins a whole service in one command;
196
+ // `--approve` says the unpinned merge is meant.
156
197
  issues.push({
157
198
  severity: "warn",
158
199
  gates: true,