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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1026) hide show
  1. package/CHANGELOG.md +2570 -61
  2. package/COMPARISON.md +80 -63
  3. package/CONTRIBUTING.md +84 -0
  4. package/MIGRATING-from-OpenSpec.md +213 -54
  5. package/QUICKSTART.md +125 -0
  6. package/README.md +450 -150
  7. package/ROADMAP.md +494 -0
  8. package/SCHEMA.md +2362 -245
  9. package/SECURITY.md +21 -3
  10. package/WORKFLOW.md +701 -0
  11. package/dist/cli.js +113 -19
  12. package/dist/cli.js.map +1 -1
  13. package/dist/commands/adopt/adopt.js +209 -0
  14. package/dist/commands/adopt/adopt.js.map +1 -0
  15. package/dist/commands/adopt/render.js +268 -0
  16. package/dist/commands/adopt/render.js.map +1 -0
  17. package/dist/commands/archive/archive.js +77 -0
  18. package/dist/commands/archive/archive.js.map +1 -0
  19. package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
  20. package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
  21. package/dist/commands/archive/plan/contracts/openapi.js +159 -0
  22. package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
  23. package/dist/commands/archive/plan/gate.js +317 -0
  24. package/dist/commands/archive/plan/gate.js.map +1 -0
  25. package/dist/commands/archive/plan/landscape.js +161 -0
  26. package/dist/commands/archive/plan/landscape.js.map +1 -0
  27. package/dist/commands/archive/plan/refusal.js +111 -0
  28. package/dist/commands/archive/plan/refusal.js.map +1 -0
  29. package/dist/commands/archive/plan/specs.js +237 -0
  30. package/dist/commands/archive/plan/specs.js.map +1 -0
  31. package/dist/commands/archive/plan/state.js +27 -0
  32. package/dist/commands/archive/plan/state.js.map +1 -0
  33. package/dist/commands/archive/run.js +251 -0
  34. package/dist/commands/archive/run.js.map +1 -0
  35. package/dist/commands/context/context.js +99 -0
  36. package/dist/commands/context/context.js.map +1 -0
  37. package/dist/commands/context/print.js +283 -0
  38. package/dist/commands/context/print.js.map +1 -0
  39. package/dist/commands/delta/delta.js +279 -0
  40. package/dist/commands/delta/delta.js.map +1 -0
  41. package/dist/commands/delta/print.js +205 -0
  42. package/dist/commands/delta/print.js.map +1 -0
  43. package/dist/commands/dependencies.js +9 -7
  44. package/dist/commands/dependencies.js.map +1 -1
  45. package/dist/commands/diff/diff.js +93 -0
  46. package/dist/commands/diff/diff.js.map +1 -0
  47. package/dist/commands/diff/print.js +38 -0
  48. package/dist/commands/diff/print.js.map +1 -0
  49. package/dist/commands/doctor.js +5 -4
  50. package/dist/commands/doctor.js.map +1 -1
  51. package/dist/commands/explain/explain.js +151 -0
  52. package/dist/commands/explain/explain.js.map +1 -0
  53. package/dist/commands/explore.js +29 -24
  54. package/dist/commands/explore.js.map +1 -1
  55. package/dist/commands/gate/gate.js +115 -0
  56. package/dist/commands/gate/gate.js.map +1 -0
  57. package/dist/commands/gate/print.js +54 -0
  58. package/dist/commands/gate/print.js.map +1 -0
  59. package/dist/commands/gherkin/commit.js +146 -0
  60. package/dist/commands/gherkin/commit.js.map +1 -0
  61. package/dist/commands/gherkin/gherkin.js +246 -0
  62. package/dist/commands/gherkin/gherkin.js.map +1 -0
  63. package/dist/commands/gherkin/reconcile.js +149 -0
  64. package/dist/commands/gherkin/reconcile.js.map +1 -0
  65. package/dist/commands/gherkin/render.js +77 -0
  66. package/dist/commands/gherkin/render.js.map +1 -0
  67. package/dist/commands/init/example.js +204 -0
  68. package/dist/commands/init/example.js.map +1 -0
  69. package/dist/commands/init/first-hour.js +28 -0
  70. package/dist/commands/init/first-hour.js.map +1 -0
  71. package/dist/commands/{init.js → init/init.js} +146 -71
  72. package/dist/commands/init/init.js.map +1 -0
  73. package/dist/commands/init/mcp.js +131 -0
  74. package/dist/commands/init/mcp.js.map +1 -0
  75. package/dist/commands/init/options.js +78 -0
  76. package/dist/commands/init/options.js.map +1 -0
  77. package/dist/commands/instructions.js +82 -14
  78. package/dist/commands/instructions.js.map +1 -1
  79. package/dist/commands/list/campaign/campaign.js +65 -0
  80. package/dist/commands/list/campaign/campaign.js.map +1 -0
  81. package/dist/commands/list/campaign/owners.js +65 -0
  82. package/dist/commands/list/campaign/owners.js.map +1 -0
  83. package/dist/commands/list/json.js +157 -0
  84. package/dist/commands/list/json.js.map +1 -0
  85. package/dist/commands/list/list.js +343 -0
  86. package/dist/commands/list/list.js.map +1 -0
  87. package/dist/commands/list/print.js +301 -0
  88. package/dist/commands/list/print.js.map +1 -0
  89. package/dist/commands/list/review.js +120 -0
  90. package/dist/commands/list/review.js.map +1 -0
  91. package/dist/commands/list/views.js +105 -0
  92. package/dist/commands/list/views.js.map +1 -0
  93. package/dist/commands/mcp/dispatch.js +183 -0
  94. package/dist/commands/mcp/dispatch.js.map +1 -0
  95. package/dist/commands/mcp/mcp.js +34 -0
  96. package/dist/commands/mcp/mcp.js.map +1 -0
  97. package/dist/commands/mcp/serve.js +55 -0
  98. package/dist/commands/mcp/serve.js.map +1 -0
  99. package/dist/commands/migrate-openspec/materialize/active.js +170 -0
  100. package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
  101. package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
  102. package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
  103. package/dist/commands/migrate-openspec/materialize/living.js +62 -0
  104. package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
  105. package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
  106. package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
  107. package/dist/commands/migrate-openspec/materialize/target.js +219 -0
  108. package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
  109. package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
  110. package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
  111. package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
  112. package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
  113. package/dist/commands/migrate-openspec/openspec/error.js +19 -0
  114. package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
  115. package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
  116. package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
  117. package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
  118. package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
  119. package/dist/commands/migrate-openspec/openspec/read.js +49 -0
  120. package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
  121. package/dist/commands/migrate-openspec/print.js +89 -0
  122. package/dist/commands/migrate-openspec/print.js.map +1 -0
  123. package/dist/commands/new/commit.js +76 -0
  124. package/dist/commands/new/commit.js.map +1 -0
  125. package/dist/commands/new/new.js +283 -0
  126. package/dist/commands/new/new.js.map +1 -0
  127. package/dist/commands/new/templates.js +355 -0
  128. package/dist/commands/new/templates.js.map +1 -0
  129. package/dist/commands/open.js +203 -0
  130. package/dist/commands/open.js.map +1 -0
  131. package/dist/commands/policy/format.js +152 -0
  132. package/dist/commands/policy/format.js.map +1 -0
  133. package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
  134. package/dist/commands/policy/gate.js.map +1 -0
  135. package/dist/commands/rebase/edit.js +106 -0
  136. package/dist/commands/rebase/edit.js.map +1 -0
  137. package/dist/commands/rebase/living.js +185 -0
  138. package/dist/commands/rebase/living.js.map +1 -0
  139. package/dist/commands/rebase/plan.js +245 -0
  140. package/dist/commands/rebase/plan.js.map +1 -0
  141. package/dist/commands/rebase/rebase.js +275 -0
  142. package/dist/commands/rebase/rebase.js.map +1 -0
  143. package/dist/commands/seed/commit.js +192 -0
  144. package/dist/commands/seed/commit.js.map +1 -0
  145. package/dist/commands/seed/plan.js +133 -0
  146. package/dist/commands/seed/plan.js.map +1 -0
  147. package/dist/commands/seed/seed.js +172 -0
  148. package/dist/commands/seed/seed.js.map +1 -0
  149. package/dist/commands/show/feature.js +178 -0
  150. package/dist/commands/show/feature.js.map +1 -0
  151. package/dist/commands/show/marks.js +24 -0
  152. package/dist/commands/show/marks.js.map +1 -0
  153. package/dist/commands/{show.js → show/service.js} +63 -152
  154. package/dist/commands/show/service.js.map +1 -0
  155. package/dist/commands/show/show.js +77 -0
  156. package/dist/commands/show/show.js.map +1 -0
  157. package/dist/commands/status/json.js +45 -0
  158. package/dist/commands/status/json.js.map +1 -0
  159. package/dist/commands/status/print.js +157 -0
  160. package/dist/commands/status/print.js.map +1 -0
  161. package/dist/commands/status/status.js +119 -0
  162. package/dist/commands/status/status.js.map +1 -0
  163. package/dist/commands/steps/steps.js +189 -0
  164. package/dist/commands/steps/steps.js.map +1 -0
  165. package/dist/commands/subsystem/edit.js +192 -0
  166. package/dist/commands/subsystem/edit.js.map +1 -0
  167. package/dist/commands/subsystem/move.js +265 -0
  168. package/dist/commands/subsystem/move.js.map +1 -0
  169. package/dist/commands/subsystem/query.js +115 -0
  170. package/dist/commands/subsystem/query.js.map +1 -0
  171. package/dist/commands/subsystem/subsystem.js +101 -0
  172. package/dist/commands/subsystem/subsystem.js.map +1 -0
  173. package/dist/commands/subsystem/sync.js +103 -0
  174. package/dist/commands/subsystem/sync.js.map +1 -0
  175. package/dist/commands/subsystem/txn/txn.js +94 -0
  176. package/dist/commands/subsystem/txn/txn.js.map +1 -0
  177. package/dist/commands/subsystem/txn/views.js +70 -0
  178. package/dist/commands/subsystem/txn/views.js.map +1 -0
  179. package/dist/commands/unarchive/manifest.js +160 -0
  180. package/dist/commands/unarchive/manifest.js.map +1 -0
  181. package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
  182. package/dist/commands/unarchive/restore.js.map +1 -0
  183. package/dist/commands/unarchive/unarchive.js +67 -0
  184. package/dist/commands/unarchive/unarchive.js.map +1 -0
  185. package/dist/commands/validate/arch-coverage.js +194 -0
  186. package/dist/commands/validate/arch-coverage.js.map +1 -0
  187. package/dist/commands/validate/checks/fleet-shape.js +296 -0
  188. package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
  189. package/dist/commands/validate/checks/health-deps.js +55 -0
  190. package/dist/commands/validate/checks/health-deps.js.map +1 -0
  191. package/dist/commands/validate/checks/requirements.js +254 -0
  192. package/dist/commands/validate/checks/requirements.js.map +1 -0
  193. package/dist/commands/validate/checks/sources.js +76 -0
  194. package/dist/commands/validate/checks/sources.js.map +1 -0
  195. package/dist/commands/validate/checks/vocabulary.js +31 -0
  196. package/dist/commands/validate/checks/vocabulary.js.map +1 -0
  197. package/dist/commands/validate/feature.js +216 -0
  198. package/dist/commands/validate/feature.js.map +1 -0
  199. package/dist/commands/validate/fleet/census.js +69 -0
  200. package/dist/commands/validate/fleet/census.js.map +1 -0
  201. package/dist/commands/validate/fleet/kind-tags.js +39 -0
  202. package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
  203. package/dist/commands/validate/fleet/landscape.js +353 -0
  204. package/dist/commands/validate/fleet/landscape.js.map +1 -0
  205. package/dist/commands/validate/fleet/load.js +52 -0
  206. package/dist/commands/validate/fleet/load.js.map +1 -0
  207. package/dist/commands/validate/fleet/obligations.js +236 -0
  208. package/dist/commands/validate/fleet/obligations.js.map +1 -0
  209. package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
  210. package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
  211. package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
  212. package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
  213. package/dist/commands/validate/fleet/scorecard/print.js +63 -0
  214. package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
  215. package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
  216. package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
  217. package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
  218. package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
  219. package/dist/commands/validate/fleet/usecases/place.js +13 -0
  220. package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
  221. package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
  222. package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
  223. package/dist/commands/validate/fleet/usecases/steps.js +197 -0
  224. package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
  225. package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
  226. package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
  227. package/dist/commands/validate/fleet/views/ids.js +40 -0
  228. package/dist/commands/validate/fleet/views/ids.js.map +1 -0
  229. package/dist/commands/validate/fleet/views/stale.js +59 -0
  230. package/dist/commands/validate/fleet/views/stale.js.map +1 -0
  231. package/dist/commands/validate/links/corpus.js +92 -0
  232. package/dist/commands/validate/links/corpus.js.map +1 -0
  233. package/dist/commands/validate/links/glossary.js +75 -0
  234. package/dist/commands/validate/links/glossary.js.map +1 -0
  235. package/dist/commands/validate/report.js +269 -0
  236. package/dist/commands/validate/report.js.map +1 -0
  237. package/dist/commands/validate/service/api.js +338 -0
  238. package/dist/commands/validate/service/api.js.map +1 -0
  239. package/dist/commands/validate/service/events/events.js +219 -0
  240. package/dist/commands/validate/service/events/events.js.map +1 -0
  241. package/dist/commands/validate/service/events/message-producers.js +77 -0
  242. package/dist/commands/validate/service/events/message-producers.js.map +1 -0
  243. package/dist/commands/validate/service/evidence-pins.js +131 -0
  244. package/dist/commands/validate/service/evidence-pins.js.map +1 -0
  245. package/dist/commands/validate/service/service.js +250 -0
  246. package/dist/commands/validate/service/service.js.map +1 -0
  247. package/dist/commands/validate/service/specs.js +219 -0
  248. package/dist/commands/validate/service/specs.js.map +1 -0
  249. package/dist/commands/validate/service/spine.js +113 -0
  250. package/dist/commands/validate/service/spine.js.map +1 -0
  251. package/dist/commands/validate/validate.js +338 -0
  252. package/dist/commands/validate/validate.js.map +1 -0
  253. package/dist/commands/verify/cross/diff.js +182 -0
  254. package/dist/commands/verify/cross/diff.js.map +1 -0
  255. package/dist/commands/verify/evidence/contract.js +32 -0
  256. package/dist/commands/verify/evidence/contract.js.map +1 -0
  257. package/dist/commands/verify/evidence/pins.js +52 -0
  258. package/dist/commands/verify/evidence/pins.js.map +1 -0
  259. package/dist/commands/verify/evidence/read.js +72 -0
  260. package/dist/commands/verify/evidence/read.js.map +1 -0
  261. package/dist/commands/verify/frozen.js +241 -0
  262. package/dist/commands/verify/frozen.js.map +1 -0
  263. package/dist/commands/verify/record.js +226 -0
  264. package/dist/commands/verify/record.js.map +1 -0
  265. package/dist/commands/verify/report.js +223 -0
  266. package/dist/commands/verify/report.js.map +1 -0
  267. package/dist/commands/verify/results.js +246 -0
  268. package/dist/commands/verify/results.js.map +1 -0
  269. package/dist/commands/verify/verify.js +217 -0
  270. package/dist/commands/verify/verify.js.map +1 -0
  271. package/dist/commands/vouch/contract.js +11 -0
  272. package/dist/commands/vouch/contract.js.map +1 -0
  273. package/dist/commands/vouch/pack/contract.js +2 -0
  274. package/dist/commands/vouch/pack/contract.js.map +1 -0
  275. package/dist/commands/vouch/pack/pack.js +266 -0
  276. package/dist/commands/vouch/pack/pack.js.map +1 -0
  277. package/dist/commands/vouch/pack/print.js +271 -0
  278. package/dist/commands/vouch/pack/print.js.map +1 -0
  279. package/dist/commands/vouch/pack/sections.js +142 -0
  280. package/dist/commands/vouch/pack/sections.js.map +1 -0
  281. package/dist/commands/vouch/prompt/confirm.js +46 -0
  282. package/dist/commands/vouch/prompt/confirm.js.map +1 -0
  283. package/dist/commands/vouch/report.js +101 -0
  284. package/dist/commands/vouch/report.js.map +1 -0
  285. package/dist/commands/vouch/run.js +285 -0
  286. package/dist/commands/vouch/run.js.map +1 -0
  287. package/dist/commands/vouch/sample/plan.js +125 -0
  288. package/dist/commands/vouch/sample/plan.js.map +1 -0
  289. package/dist/commands/vouch/sample/print.js +109 -0
  290. package/dist/commands/vouch/sample/print.js.map +1 -0
  291. package/dist/commands/vouch/vet/verify.js +123 -0
  292. package/dist/commands/vouch/vet/verify.js.map +1 -0
  293. package/dist/commands/vouch/vouch.js +176 -0
  294. package/dist/commands/vouch/vouch.js.map +1 -0
  295. package/dist/core/agent/agents-md/artifacts.js +220 -0
  296. package/dist/core/agent/agents-md/artifacts.js.map +1 -0
  297. package/dist/core/agent/agents-md/command-map.js +324 -0
  298. package/dist/core/agent/agents-md/command-map.js.map +1 -0
  299. package/dist/core/agent/agents-md/cycle.js +165 -0
  300. package/dist/core/agent/agents-md/cycle.js.map +1 -0
  301. package/dist/core/agent/agents-md/map/explain.js +34 -0
  302. package/dist/core/agent/agents-md/map/explain.js.map +1 -0
  303. package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
  304. package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
  305. package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
  306. package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
  307. package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
  308. package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
  309. package/dist/core/agent/agents-md/map/mcp.js +41 -0
  310. package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
  311. package/dist/core/agent/agents-md/map/status.js +62 -0
  312. package/dist/core/agent/agents-md/map/status.js.map +1 -0
  313. package/dist/core/agent/agents-md/map/subsystem.js +32 -0
  314. package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
  315. package/dist/core/agent/agents-md/map/usecases.js +60 -0
  316. package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
  317. package/dist/core/agent/agents-md/refusals.js +246 -0
  318. package/dist/core/agent/agents-md/refusals.js.map +1 -0
  319. package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
  320. package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
  321. package/dist/core/agent/agents-md/spine.js +40 -0
  322. package/dist/core/agent/agents-md/spine.js.map +1 -0
  323. package/dist/core/agent/agents-md.js +170 -0
  324. package/dist/core/agent/agents-md.js.map +1 -0
  325. package/dist/core/agent/agents-stamp.js +155 -0
  326. package/dist/core/agent/agents-stamp.js.map +1 -0
  327. package/dist/core/agent/contract.js +2 -0
  328. package/dist/core/agent/contract.js.map +1 -0
  329. package/dist/core/agent/protocol.js +193 -0
  330. package/dist/core/agent/protocol.js.map +1 -0
  331. package/dist/core/agent/scaffold.js +259 -0
  332. package/dist/core/agent/scaffold.js.map +1 -0
  333. package/dist/core/agent/support/report.js +103 -0
  334. package/dist/core/agent/support/report.js.map +1 -0
  335. package/dist/core/agent/tools/dialects.js +150 -0
  336. package/dist/core/agent/tools/dialects.js.map +1 -0
  337. package/dist/core/agent/tools/registry.js +228 -0
  338. package/dist/core/agent/tools/registry.js.map +1 -0
  339. package/dist/core/agent/workflows/adopt.js +133 -0
  340. package/dist/core/agent/workflows/adopt.js.map +1 -0
  341. package/dist/core/agent/workflows/check.js +334 -0
  342. package/dist/core/agent/workflows/check.js.map +1 -0
  343. package/dist/core/agent/workflows/closing.js +262 -0
  344. package/dist/core/agent/workflows/closing.js.map +1 -0
  345. package/dist/core/agent/workflows/feature.js +105 -0
  346. package/dist/core/agent/workflows/feature.js.map +1 -0
  347. package/dist/core/agent/workflows/implement.js +105 -0
  348. package/dist/core/agent/workflows/implement.js.map +1 -0
  349. package/dist/core/agent/workflows/reference/authoring.js +209 -0
  350. package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
  351. package/dist/core/agent/workflows/reference/codes.js +65 -0
  352. package/dist/core/agent/workflows/reference/codes.js.map +1 -0
  353. package/dist/core/agent/workflows/reference/done-check.js +188 -0
  354. package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
  355. package/dist/core/agent/workflows/reference/reference.js +16 -0
  356. package/dist/core/agent/workflows/reference/reference.js.map +1 -0
  357. package/dist/core/agent/workflows/reference/spine.js +297 -0
  358. package/dist/core/agent/workflows/reference/spine.js.map +1 -0
  359. package/dist/core/asyncapi/baseline/plan.js +110 -0
  360. package/dist/core/asyncapi/baseline/plan.js.map +1 -0
  361. package/dist/core/asyncapi/baseline/surfaces.js +54 -0
  362. package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
  363. package/dist/core/asyncapi/depth.js +164 -0
  364. package/dist/core/asyncapi/depth.js.map +1 -0
  365. package/dist/core/asyncapi/digest.js +141 -0
  366. package/dist/core/asyncapi/digest.js.map +1 -0
  367. package/dist/core/asyncapi/merge/components.js +91 -0
  368. package/dist/core/asyncapi/merge/components.js.map +1 -0
  369. package/dist/core/asyncapi/merge/error.js +33 -0
  370. package/dist/core/asyncapi/merge/error.js.map +1 -0
  371. package/dist/core/asyncapi/merge/markers.js +308 -0
  372. package/dist/core/asyncapi/merge/markers.js.map +1 -0
  373. package/dist/core/asyncapi/merge/merge.js +215 -0
  374. package/dist/core/asyncapi/merge/merge.js.map +1 -0
  375. package/dist/core/asyncapi/merge/pin.js +107 -0
  376. package/dist/core/asyncapi/merge/pin.js.map +1 -0
  377. package/dist/core/asyncapi/model.js +11 -0
  378. package/dist/core/asyncapi/model.js.map +1 -0
  379. package/dist/core/asyncapi/producers.js +50 -0
  380. package/dist/core/asyncapi/producers.js.map +1 -0
  381. package/dist/core/asyncapi/read.js +239 -0
  382. package/dist/core/asyncapi/read.js.map +1 -0
  383. package/dist/core/brief/brief.js +225 -0
  384. package/dist/core/brief/brief.js.map +1 -0
  385. package/dist/core/brief/checks.js +250 -0
  386. package/dist/core/brief/checks.js.map +1 -0
  387. package/dist/core/brief/landscape.js +194 -0
  388. package/dist/core/brief/landscape.js.map +1 -0
  389. package/dist/core/brief/targets.js +226 -0
  390. package/dist/core/brief/targets.js.map +1 -0
  391. package/dist/core/brief/unchecked.js +47 -0
  392. package/dist/core/brief/unchecked.js.map +1 -0
  393. package/dist/core/c4/arch.js +282 -0
  394. package/dist/core/c4/arch.js.map +1 -0
  395. package/dist/core/c4/likec4.js +88 -0
  396. package/dist/core/c4/likec4.js.map +1 -0
  397. package/dist/core/c4/parsed/dynamic-views.js +132 -0
  398. package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
  399. package/dist/core/c4/parsed/specification.js +78 -0
  400. package/dist/core/c4/parsed/specification.js.map +1 -0
  401. package/dist/core/c4/parsed/values.js +57 -0
  402. package/dist/core/c4/parsed/values.js.map +1 -0
  403. package/dist/core/c4/parsed/view-ids.js +75 -0
  404. package/dist/core/c4/parsed/view-ids.js.map +1 -0
  405. package/dist/core/c4/project/architecture.js +45 -0
  406. package/dist/core/c4/project/architecture.js.map +1 -0
  407. package/dist/core/c4/project/documents.js +58 -0
  408. package/dist/core/c4/project/documents.js.map +1 -0
  409. package/dist/core/c4/project/load.js +183 -0
  410. package/dist/core/c4/project/load.js.map +1 -0
  411. package/dist/core/c4/resolve/service.js +113 -0
  412. package/dist/core/c4/resolve/service.js.map +1 -0
  413. package/dist/core/c4/seed/fleet-file.js +201 -0
  414. package/dist/core/c4/seed/fleet-file.js.map +1 -0
  415. package/dist/core/c4/seed/items.js +91 -0
  416. package/dist/core/c4/seed/items.js.map +1 -0
  417. package/dist/core/c4/seed/stamp.js +48 -0
  418. package/dist/core/c4/seed/stamp.js.map +1 -0
  419. package/dist/core/c4/seed/template.js +109 -0
  420. package/dist/core/c4/seed/template.js.map +1 -0
  421. package/dist/core/c4/source-mask.js +82 -0
  422. package/dist/core/c4/source-mask.js.map +1 -0
  423. package/dist/core/c4/source-scan.js +227 -0
  424. package/dist/core/c4/source-scan.js.map +1 -0
  425. package/dist/core/c4/splice/authored-source.js +101 -0
  426. package/dist/core/c4/splice/authored-source.js.map +1 -0
  427. package/dist/core/c4/splice/contract.js +10 -0
  428. package/dist/core/c4/splice/contract.js.map +1 -0
  429. package/dist/core/c4/splice/delta-blocks.js +126 -0
  430. package/dist/core/c4/splice/delta-blocks.js.map +1 -0
  431. package/dist/core/c4/splice/identity/edges.js +36 -0
  432. package/dist/core/c4/splice/identity/edges.js.map +1 -0
  433. package/dist/core/c4/splice/landscape-merge.js +269 -0
  434. package/dist/core/c4/splice/landscape-merge.js.map +1 -0
  435. package/dist/core/c4/splice/placement.js +194 -0
  436. package/dist/core/c4/splice/placement.js.map +1 -0
  437. package/dist/core/c4/workspace.js +172 -0
  438. package/dist/core/c4/workspace.js.map +1 -0
  439. package/dist/core/capabilities/authoring/notes.js +141 -0
  440. package/dist/core/capabilities/authoring/notes.js.map +1 -0
  441. package/dist/core/capabilities/capabilities.js +124 -0
  442. package/dist/core/capabilities/capabilities.js.map +1 -0
  443. package/dist/core/capabilities/delta/doc.js +50 -0
  444. package/dist/core/capabilities/delta/doc.js.map +1 -0
  445. package/dist/core/capabilities/delta/overlay.js +129 -0
  446. package/dist/core/capabilities/delta/overlay.js.map +1 -0
  447. package/dist/core/capabilities/delta/summary.js +57 -0
  448. package/dist/core/capabilities/delta/summary.js.map +1 -0
  449. package/dist/core/capabilities/delta/tree.js +43 -0
  450. package/dist/core/capabilities/delta/tree.js.map +1 -0
  451. package/dist/core/capabilities/delta/uncovered.js +222 -0
  452. package/dist/core/capabilities/delta/uncovered.js.map +1 -0
  453. package/dist/core/capabilities/findings.js +342 -0
  454. package/dist/core/capabilities/findings.js.map +1 -0
  455. package/dist/core/capabilities/realizes/findings.js +181 -0
  456. package/dist/core/capabilities/realizes/findings.js.map +1 -0
  457. package/dist/core/capabilities/realizes/join.js +143 -0
  458. package/dist/core/capabilities/realizes/join.js.map +1 -0
  459. package/dist/core/capabilities/rollup.js +199 -0
  460. package/dist/core/capabilities/rollup.js.map +1 -0
  461. package/dist/core/capabilities/tree.js +126 -0
  462. package/dist/core/capabilities/tree.js.map +1 -0
  463. package/dist/core/capabilities/usecase-join.js +277 -0
  464. package/dist/core/capabilities/usecase-join.js.map +1 -0
  465. package/dist/core/coherence/authoring/scaffold.js +177 -0
  466. package/dist/core/coherence/authoring/scaffold.js.map +1 -0
  467. package/dist/core/coherence/authoring/sentinels.js +74 -0
  468. package/dist/core/coherence/authoring/sentinels.js.map +1 -0
  469. package/dist/core/coherence/coherence.js +251 -0
  470. package/dist/core/coherence/coherence.js.map +1 -0
  471. package/dist/core/coherence/declared.js +269 -0
  472. package/dist/core/coherence/declared.js.map +1 -0
  473. package/dist/core/coherence/events/declared.js +206 -0
  474. package/dist/core/coherence/events/declared.js.map +1 -0
  475. package/dist/core/coherence/events/events.js +204 -0
  476. package/dist/core/coherence/events/events.js.map +1 -0
  477. package/dist/core/coherence/events/grades.js +166 -0
  478. package/dist/core/coherence/events/grades.js.map +1 -0
  479. package/dist/core/coherence/events/lookups.js +122 -0
  480. package/dist/core/coherence/events/lookups.js.map +1 -0
  481. package/dist/core/coherence/events/merged.js +40 -0
  482. package/dist/core/coherence/events/merged.js.map +1 -0
  483. package/dist/core/coherence/living.js +198 -0
  484. package/dist/core/coherence/living.js.map +1 -0
  485. package/dist/core/coherence/lookups.js +155 -0
  486. package/dist/core/coherence/lookups.js.map +1 -0
  487. package/dist/core/coherence/pending.js +39 -0
  488. package/dist/core/coherence/pending.js.map +1 -0
  489. package/dist/core/conflict-markers.js +60 -0
  490. package/dist/core/conflict-markers.js.map +1 -0
  491. package/dist/core/delta/claims.js +73 -0
  492. package/dist/core/delta/claims.js.map +1 -0
  493. package/dist/core/delta/delta.js +296 -0
  494. package/dist/core/delta/delta.js.map +1 -0
  495. package/dist/core/delta/document.js +177 -0
  496. package/dist/core/delta/document.js.map +1 -0
  497. package/dist/core/delta/scope.js +48 -0
  498. package/dist/core/delta/scope.js.map +1 -0
  499. package/dist/core/delta/select.js +237 -0
  500. package/dist/core/delta/select.js.map +1 -0
  501. package/dist/core/dependencies/dependencies.js +141 -0
  502. package/dist/core/dependencies/dependencies.js.map +1 -0
  503. package/dist/core/dependencies/facts.js +165 -0
  504. package/dist/core/dependencies/facts.js.map +1 -0
  505. package/dist/core/dependencies/fanin.js +88 -0
  506. package/dist/core/dependencies/fanin.js.map +1 -0
  507. package/dist/core/dependencies/graph.js +106 -0
  508. package/dist/core/dependencies/graph.js.map +1 -0
  509. package/dist/core/diff/base-git.js +148 -0
  510. package/dist/core/diff/base-git.js.map +1 -0
  511. package/dist/core/diff/base-state.js +209 -0
  512. package/dist/core/diff/base-state.js.map +1 -0
  513. package/dist/core/diff/current-state.js +96 -0
  514. package/dist/core/diff/current-state.js.map +1 -0
  515. package/dist/core/diff/scope/changed-paths.js +188 -0
  516. package/dist/core/diff/scope/changed-paths.js.map +1 -0
  517. package/dist/core/diff/semantic.js +243 -0
  518. package/dist/core/diff/semantic.js.map +1 -0
  519. package/dist/core/diff/victims.js +247 -0
  520. package/dist/core/diff/victims.js.map +1 -0
  521. package/dist/core/docs.js +59 -55
  522. package/dist/core/docs.js.map +1 -1
  523. package/dist/core/doctor/agents.js +222 -0
  524. package/dist/core/doctor/agents.js.map +1 -0
  525. package/dist/core/doctor/config.js +135 -0
  526. package/dist/core/doctor/config.js.map +1 -0
  527. package/dist/core/doctor/doctor.js +275 -0
  528. package/dist/core/doctor/doctor.js.map +1 -0
  529. package/dist/core/doctor/report.js +13 -0
  530. package/dist/core/doctor/report.js.map +1 -0
  531. package/dist/core/doctor/residue.js +110 -0
  532. package/dist/core/doctor/residue.js.map +1 -0
  533. package/dist/core/document/apply.js +77 -0
  534. package/dist/core/document/apply.js.map +1 -0
  535. package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
  536. package/dist/core/document/frontmatter.js.map +1 -0
  537. package/dist/core/document/grammar/directives.js +143 -0
  538. package/dist/core/document/grammar/directives.js.map +1 -0
  539. package/dist/core/document/parse.js +263 -0
  540. package/dist/core/document/parse.js.map +1 -0
  541. package/dist/core/document/scenarios.js +221 -0
  542. package/dist/core/document/scenarios.js.map +1 -0
  543. package/dist/core/document/spec.js +241 -0
  544. package/dist/core/document/spec.js.map +1 -0
  545. package/dist/core/{config.js → envelope/config.js} +79 -18
  546. package/dist/core/envelope/config.js.map +1 -0
  547. package/dist/core/envelope/json.js +175 -0
  548. package/dist/core/envelope/json.js.map +1 -0
  549. package/dist/core/{version.js → envelope/version.js} +3 -3
  550. package/dist/core/envelope/version.js.map +1 -0
  551. package/dist/core/explain/families.js +175 -0
  552. package/dist/core/explain/families.js.map +1 -0
  553. package/dist/core/explain/fix-tables.js +178 -0
  554. package/dist/core/explain/fix-tables.js.map +1 -0
  555. package/dist/core/explain/lookup.js +181 -0
  556. package/dist/core/explain/lookup.js.map +1 -0
  557. package/dist/core/explain/refusals.js +49 -0
  558. package/dist/core/explain/refusals.js.map +1 -0
  559. package/dist/core/explain/terms.js +144 -0
  560. package/dist/core/explain/terms.js.map +1 -0
  561. package/dist/core/explore/describe.js +105 -0
  562. package/dist/core/explore/describe.js.map +1 -0
  563. package/dist/core/{explore.js → explore/explore.js} +50 -101
  564. package/dist/core/explore/explore.js.map +1 -0
  565. package/dist/core/fleet-context.js +132 -77
  566. package/dist/core/fleet-context.js.map +1 -1
  567. package/dist/core/gate/checks.js +201 -0
  568. package/dist/core/gate/checks.js.map +1 -0
  569. package/dist/core/gate/partners.js +205 -0
  570. package/dist/core/gate/partners.js.map +1 -0
  571. package/dist/core/gate/report.js +47 -0
  572. package/dist/core/gate/report.js.map +1 -0
  573. package/dist/core/gate/verification.js +113 -0
  574. package/dist/core/gate/verification.js.map +1 -0
  575. package/dist/core/gherkin/digest.js +60 -0
  576. package/dist/core/gherkin/digest.js.map +1 -0
  577. package/dist/core/gherkin/emit.js +177 -0
  578. package/dist/core/gherkin/emit.js.map +1 -0
  579. package/dist/core/gherkin/read.js +76 -0
  580. package/dist/core/gherkin/read.js.map +1 -0
  581. package/dist/core/gherkin/stale.js +234 -0
  582. package/dist/core/gherkin/stale.js.map +1 -0
  583. package/dist/core/gherkin/stamp.js +77 -0
  584. package/dist/core/gherkin/stamp.js.map +1 -0
  585. package/dist/core/gherkin/steps/catalogue.js +154 -0
  586. package/dist/core/gherkin/steps/catalogue.js.map +1 -0
  587. package/dist/core/gherkin/steps/inventory.js +98 -0
  588. package/dist/core/gherkin/steps/inventory.js.map +1 -0
  589. package/dist/core/gherkin/steps/phrase.js +72 -0
  590. package/dist/core/gherkin/steps/phrase.js.map +1 -0
  591. package/dist/core/glossary/delta.js +106 -0
  592. package/dist/core/glossary/delta.js.map +1 -0
  593. package/dist/core/glossary/tree.js +86 -0
  594. package/dist/core/glossary/tree.js.map +1 -0
  595. package/dist/core/kernel/concurrency.js.map +1 -0
  596. package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
  597. package/dist/core/kernel/document-bytes.js.map +1 -0
  598. package/dist/core/kernel/fences.js +42 -0
  599. package/dist/core/kernel/fences.js.map +1 -0
  600. package/dist/core/kernel/ids/capability.js +72 -0
  601. package/dist/core/kernel/ids/capability.js.map +1 -0
  602. package/dist/core/kernel/ids/dirs.js +33 -0
  603. package/dist/core/kernel/ids/dirs.js.map +1 -0
  604. package/dist/core/kernel/ids/feature.js +75 -0
  605. package/dist/core/kernel/ids/feature.js.map +1 -0
  606. package/dist/core/kernel/ids/service.js +156 -0
  607. package/dist/core/kernel/ids/service.js.map +1 -0
  608. package/dist/core/kernel/ids/subsystem.js +63 -0
  609. package/dist/core/kernel/ids/subsystem.js.map +1 -0
  610. package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
  611. package/dist/core/kernel/path-safety.js.map +1 -0
  612. package/dist/core/kernel/records.js.map +1 -0
  613. package/dist/core/links/backlinks.js +68 -0
  614. package/dist/core/links/backlinks.js.map +1 -0
  615. package/dist/core/links/case.js +74 -0
  616. package/dist/core/links/case.js.map +1 -0
  617. package/dist/core/links/corpus.js +104 -0
  618. package/dist/core/links/corpus.js.map +1 -0
  619. package/dist/core/links/findings.js +110 -0
  620. package/dist/core/links/findings.js.map +1 -0
  621. package/dist/core/links/parse.js +236 -0
  622. package/dist/core/links/parse.js.map +1 -0
  623. package/dist/core/mcp/argv.js +111 -0
  624. package/dist/core/mcp/argv.js.map +1 -0
  625. package/dist/core/mcp/author-tools.js +72 -0
  626. package/dist/core/mcp/author-tools.js.map +1 -0
  627. package/dist/core/mcp/framing.js +46 -0
  628. package/dist/core/mcp/framing.js.map +1 -0
  629. package/dist/core/mcp/protocol.js +280 -0
  630. package/dist/core/mcp/protocol.js.map +1 -0
  631. package/dist/core/mcp/tools.js +314 -0
  632. package/dist/core/mcp/tools.js.map +1 -0
  633. package/dist/core/obligations/obligations.js +106 -0
  634. package/dist/core/obligations/obligations.js.map +1 -0
  635. package/dist/core/openapi/baseline/gate.js +166 -0
  636. package/dist/core/openapi/baseline/gate.js.map +1 -0
  637. package/dist/core/openapi/baseline/plan.js +112 -0
  638. package/dist/core/openapi/baseline/plan.js.map +1 -0
  639. package/dist/core/openapi/baseline/record.js +175 -0
  640. package/dist/core/openapi/baseline/record.js.map +1 -0
  641. package/dist/core/openapi/depth.js +122 -0
  642. package/dist/core/openapi/depth.js.map +1 -0
  643. package/dist/core/openapi/digest.js +189 -0
  644. package/dist/core/openapi/digest.js.map +1 -0
  645. package/dist/core/{openapi.js → openapi/doc.js} +44 -106
  646. package/dist/core/openapi/doc.js.map +1 -0
  647. package/dist/core/openapi/merge/components.js +234 -0
  648. package/dist/core/openapi/merge/components.js.map +1 -0
  649. package/dist/core/openapi/merge/error.js +26 -0
  650. package/dist/core/openapi/merge/error.js.map +1 -0
  651. package/dist/core/openapi/merge/markers.js +208 -0
  652. package/dist/core/openapi/merge/markers.js.map +1 -0
  653. package/dist/core/openapi/merge/merge.js +256 -0
  654. package/dist/core/openapi/merge/merge.js.map +1 -0
  655. package/dist/core/openapi/merge/pin.js +128 -0
  656. package/dist/core/openapi/merge/pin.js.map +1 -0
  657. package/dist/core/openspec/decide/capabilities.js +244 -0
  658. package/dist/core/openspec/decide/capabilities.js.map +1 -0
  659. package/dist/core/openspec/decide/dispositions.js +63 -0
  660. package/dist/core/openspec/decide/dispositions.js.map +1 -0
  661. package/dist/core/openspec/decide/renames.js +179 -0
  662. package/dist/core/openspec/decide/renames.js.map +1 -0
  663. package/dist/core/openspec/decide/verdict.js +84 -0
  664. package/dist/core/openspec/decide/verdict.js.map +1 -0
  665. package/dist/core/openspec/inventory.js +221 -0
  666. package/dist/core/openspec/inventory.js.map +1 -0
  667. package/dist/core/openspec/model/mapping.js +76 -0
  668. package/dist/core/openspec/model/mapping.js.map +1 -0
  669. package/dist/core/openspec/model/model.js +65 -0
  670. package/dist/core/openspec/model/model.js.map +1 -0
  671. package/dist/core/openspec/scan/changes.js +235 -0
  672. package/dist/core/openspec/scan/changes.js.map +1 -0
  673. package/dist/core/openspec/scan/config.js +200 -0
  674. package/dist/core/openspec/scan/config.js.map +1 -0
  675. package/dist/core/openspec/scan/shape.js +260 -0
  676. package/dist/core/openspec/scan/shape.js.map +1 -0
  677. package/dist/core/openspec/scan/walk.js +133 -0
  678. package/dist/core/openspec/scan/walk.js.map +1 -0
  679. package/dist/core/openspec/scan/workspace.js +71 -0
  680. package/dist/core/openspec/scan/workspace.js.map +1 -0
  681. package/dist/core/owners/codeowners.js +141 -0
  682. package/dist/core/owners/codeowners.js.map +1 -0
  683. package/dist/core/pack/features.js +120 -0
  684. package/dist/core/pack/features.js.map +1 -0
  685. package/dist/core/pack/joins.js +112 -0
  686. package/dist/core/pack/joins.js.map +1 -0
  687. package/dist/core/pack/living.js +118 -0
  688. package/dist/core/pack/living.js.map +1 -0
  689. package/dist/core/pack/pack.js +76 -0
  690. package/dist/core/pack/pack.js.map +1 -0
  691. package/dist/core/permissions/permissions.js +87 -0
  692. package/dist/core/permissions/permissions.js.map +1 -0
  693. package/dist/core/projection/api.js +84 -0
  694. package/dist/core/projection/api.js.map +1 -0
  695. package/dist/core/projection/arch-slice.js +63 -0
  696. package/dist/core/projection/arch-slice.js.map +1 -0
  697. package/dist/core/projection/events.js +34 -0
  698. package/dist/core/projection/events.js.map +1 -0
  699. package/dist/core/provenance/findings.js +208 -0
  700. package/dist/core/provenance/findings.js.map +1 -0
  701. package/dist/core/provenance/git.js +225 -0
  702. package/dist/core/provenance/git.js.map +1 -0
  703. package/dist/core/provenance/gitq/moves.js +182 -0
  704. package/dist/core/provenance/gitq/moves.js.map +1 -0
  705. package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
  706. package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
  707. package/dist/core/provenance/sample/scope.js +238 -0
  708. package/dist/core/provenance/sample/scope.js.map +1 -0
  709. package/dist/core/provenance/sample/sections.js +61 -0
  710. package/dist/core/provenance/sample/sections.js.map +1 -0
  711. package/dist/core/provenance/sources.js +263 -0
  712. package/dist/core/provenance/sources.js.map +1 -0
  713. package/dist/core/provenance/stamp.js +232 -0
  714. package/dist/core/provenance/stamp.js.map +1 -0
  715. package/dist/core/provenance/walk.js +157 -0
  716. package/dist/core/provenance/walk.js.map +1 -0
  717. package/dist/core/repo/authored/paths.js +192 -0
  718. package/dist/core/repo/authored/paths.js.map +1 -0
  719. package/dist/core/repo/entries.js +126 -0
  720. package/dist/core/repo/entries.js.map +1 -0
  721. package/dist/core/repo/paths.js +236 -0
  722. package/dist/core/repo/paths.js.map +1 -0
  723. package/dist/core/repo/repo.js +248 -0
  724. package/dist/core/repo/repo.js.map +1 -0
  725. package/dist/core/repo/service-target.js +153 -0
  726. package/dist/core/repo/service-target.js.map +1 -0
  727. package/dist/core/repo/state.js +58 -0
  728. package/dist/core/repo/state.js.map +1 -0
  729. package/dist/core/repo/tree/find.js +52 -0
  730. package/dist/core/repo/tree/find.js.map +1 -0
  731. package/dist/core/repo/tree/fs.js +64 -0
  732. package/dist/core/repo/tree/fs.js.map +1 -0
  733. package/dist/core/repo/tree/marker.js +61 -0
  734. package/dist/core/repo/tree/marker.js.map +1 -0
  735. package/dist/core/repo/tree/views.js +172 -0
  736. package/dist/core/repo/tree/views.js.map +1 -0
  737. package/dist/core/repo/tree/walk.js +234 -0
  738. package/dist/core/repo/tree/walk.js.map +1 -0
  739. package/dist/core/results.js +99 -2
  740. package/dist/core/results.js.map +1 -1
  741. package/dist/core/scaffold/landscape.js +131 -0
  742. package/dist/core/scaffold/landscape.js.map +1 -0
  743. package/dist/core/scaffold/readme.js +84 -0
  744. package/dist/core/scaffold/readme.js.map +1 -0
  745. package/dist/core/staging/commit.js +241 -0
  746. package/dist/core/staging/commit.js.map +1 -0
  747. package/dist/core/staging/interrupted.js +96 -0
  748. package/dist/core/staging/interrupted.js.map +1 -0
  749. package/dist/core/staging/lock.js +206 -0
  750. package/dist/core/staging/lock.js.map +1 -0
  751. package/dist/core/staging/recovery/finding.js +35 -0
  752. package/dist/core/staging/recovery/finding.js.map +1 -0
  753. package/dist/core/staging/recovery/intent.js +98 -0
  754. package/dist/core/staging/recovery/intent.js.map +1 -0
  755. package/dist/core/staging/recovery/recover.js +126 -0
  756. package/dist/core/staging/recovery/recover.js.map +1 -0
  757. package/dist/core/staging/recovery/residue.js +62 -0
  758. package/dist/core/staging/recovery/residue.js.map +1 -0
  759. package/dist/core/staging/snapshot.js +202 -0
  760. package/dist/core/staging/snapshot.js.map +1 -0
  761. package/dist/core/staging/txn/forward.js +171 -0
  762. package/dist/core/staging/txn/forward.js.map +1 -0
  763. package/dist/core/staging/txn/journal.js +139 -0
  764. package/dist/core/staging/txn/journal.js.map +1 -0
  765. package/dist/core/staging/txn/transaction.js +75 -0
  766. package/dist/core/staging/txn/transaction.js.map +1 -0
  767. package/dist/core/staging/writes.js +113 -0
  768. package/dist/core/staging/writes.js.map +1 -0
  769. package/dist/core/status/actions/execution.js +49 -0
  770. package/dist/core/status/actions/execution.js.map +1 -0
  771. package/dist/core/status/contracts.js +102 -0
  772. package/dist/core/status/contracts.js.map +1 -0
  773. package/dist/core/status/feature/artifacts.js +171 -0
  774. package/dist/core/status/feature/artifacts.js.map +1 -0
  775. package/dist/core/status/feature/feature.js +207 -0
  776. package/dist/core/status/feature/feature.js.map +1 -0
  777. package/dist/core/status/feature/next.js +150 -0
  778. package/dist/core/status/feature/next.js.map +1 -0
  779. package/dist/core/status/feature/state.js +21 -0
  780. package/dist/core/status/feature/state.js.map +1 -0
  781. package/dist/core/status/fleet/fleet.js +187 -0
  782. package/dist/core/status/fleet/fleet.js.map +1 -0
  783. package/dist/core/status/fleet/next.js +207 -0
  784. package/dist/core/status/fleet/next.js.map +1 -0
  785. package/dist/core/status/interrupted.js +97 -0
  786. package/dist/core/status/interrupted.js.map +1 -0
  787. package/dist/core/status/report.js +31 -0
  788. package/dist/core/status/report.js.map +1 -0
  789. package/dist/core/status/scan.js +41 -0
  790. package/dist/core/status/scan.js.map +1 -0
  791. package/dist/core/status/verification.js +201 -0
  792. package/dist/core/status/verification.js.map +1 -0
  793. package/dist/core/usecases/capability.js +169 -0
  794. package/dist/core/usecases/capability.js.map +1 -0
  795. package/dist/core/usecases/delta/claims.js +116 -0
  796. package/dist/core/usecases/delta/claims.js.map +1 -0
  797. package/dist/core/usecases/delta/flows.js +103 -0
  798. package/dist/core/usecases/delta/flows.js.map +1 -0
  799. package/dist/core/usecases/delta/overlay.js +235 -0
  800. package/dist/core/usecases/delta/overlay.js.map +1 -0
  801. package/dist/core/usecases/fleet.js +137 -0
  802. package/dist/core/usecases/fleet.js.map +1 -0
  803. package/dist/core/usecases/operations.js +111 -0
  804. package/dist/core/usecases/operations.js.map +1 -0
  805. package/dist/core/usecases/place.js +44 -0
  806. package/dist/core/usecases/place.js.map +1 -0
  807. package/dist/core/usecases/touch.js +101 -0
  808. package/dist/core/usecases/touch.js.map +1 -0
  809. package/dist/core/verify/answers.js +173 -0
  810. package/dist/core/verify/answers.js.map +1 -0
  811. package/dist/core/verify/build.js +150 -0
  812. package/dist/core/verify/build.js.map +1 -0
  813. package/dist/core/verify/checklist.js +201 -0
  814. package/dist/core/verify/checklist.js.map +1 -0
  815. package/dist/core/verify/claims/identity.js +61 -0
  816. package/dist/core/verify/claims/identity.js.map +1 -0
  817. package/dist/core/verify/cross/diff.js +97 -0
  818. package/dist/core/verify/cross/diff.js.map +1 -0
  819. package/dist/core/verify/evidence/contract.js +169 -0
  820. package/dist/core/verify/evidence/contract.js.map +1 -0
  821. package/dist/core/verify/file.js +257 -0
  822. package/dist/core/verify/file.js.map +1 -0
  823. package/dist/core/verify/pins/lint.js +157 -0
  824. package/dist/core/verify/pins/lint.js.map +1 -0
  825. package/dist/core/verify/pins/pin.js +95 -0
  826. package/dist/core/verify/pins/pin.js.map +1 -0
  827. package/dist/core/verify/record.js +142 -0
  828. package/dist/core/verify/record.js.map +1 -0
  829. package/dist/core/verify/store/commit.js +89 -0
  830. package/dist/core/verify/store/commit.js.map +1 -0
  831. package/dist/core/verify/store/render.js +57 -0
  832. package/dist/core/verify/store/render.js.map +1 -0
  833. package/dist/core/vocabulary/health.js +91 -0
  834. package/dist/core/vocabulary/health.js.map +1 -0
  835. package/dist/core/vocabulary/issue.js +55 -0
  836. package/dist/core/vocabulary/issue.js.map +1 -0
  837. package/dist/core/vocabulary/maturity.js +145 -0
  838. package/dist/core/vocabulary/maturity.js.map +1 -0
  839. package/dist/core/{report.js → vocabulary/report.js} +30 -2
  840. package/dist/core/vocabulary/report.js.map +1 -0
  841. package/dist/core/vocabulary/steps.js +266 -0
  842. package/dist/core/vocabulary/steps.js.map +1 -0
  843. package/dist/core/workspace/discover.js +239 -0
  844. package/dist/core/workspace/discover.js.map +1 -0
  845. package/dist/core/workspace/render.js +52 -0
  846. package/dist/core/workspace/render.js.map +1 -0
  847. package/examples/README.md +189 -0
  848. package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
  849. package/examples/docs/architecture/capabilities.yaml +31 -0
  850. package/examples/docs/architecture/landscape.likec4 +280 -0
  851. package/examples/docs/architecture/obligations.yaml +23 -0
  852. package/examples/docs/architecture/permissions.yaml +50 -0
  853. package/examples/docs/architecture/subsystems.likec4 +11 -0
  854. package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
  855. package/examples/docs/capabilities/checkout/spec.md +55 -0
  856. package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
  857. package/examples/docs/capabilities/order-notifications/spec.md +43 -0
  858. package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
  859. package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
  860. package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
  861. package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
  862. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
  863. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
  864. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
  865. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
  866. package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
  867. package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
  868. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
  869. package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
  870. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
  871. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
  872. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
  873. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
  874. package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
  875. package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
  876. package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
  877. package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
  878. package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
  879. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
  880. package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
  881. package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
  882. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
  883. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
  884. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
  885. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
  886. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
  887. package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
  888. package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
  889. package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
  890. package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
  891. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
  892. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
  893. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
  894. package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
  895. package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
  896. package/examples/docs/glossary/order.md +15 -0
  897. package/examples/docs/glossary/payments/authorization.md +14 -0
  898. package/examples/docs/likec4.config.json +9 -0
  899. package/examples/docs/loam.json +3 -0
  900. package/examples/docs/services/checkout-web/model.likec4 +109 -0
  901. package/examples/docs/services/checkout-web/spec.md +91 -0
  902. package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
  903. package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
  904. package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
  905. package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
  906. package/examples/docs/services/order-service/arch.spec.md +127 -0
  907. package/examples/docs/services/order-service/asyncapi.yaml +108 -0
  908. package/examples/docs/services/order-service/health.yaml +57 -0
  909. package/examples/docs/services/order-service/model.likec4 +138 -0
  910. package/examples/docs/services/order-service/openapi.yaml +257 -0
  911. package/examples/docs/services/order-service/runbook.md +62 -0
  912. package/examples/docs/services/order-service/spec.md +134 -0
  913. package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
  914. package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
  915. package/examples/docs/services/payment-service/arch.spec.md +73 -0
  916. package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
  917. package/examples/docs/services/payment-service/health.yaml +39 -0
  918. package/examples/docs/services/payment-service/model.likec4 +67 -0
  919. package/examples/docs/services/payment-service/openapi.yaml +151 -0
  920. package/examples/docs/services/payment-service/runbook.md +37 -0
  921. package/examples/docs/services/payment-service/spec.md +88 -0
  922. package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
  923. package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
  924. package/examples/docs/services/platform/identity-service/health.yaml +70 -0
  925. package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
  926. package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
  927. package/examples/docs/services/platform/identity-service/runbook.md +95 -0
  928. package/examples/docs/services/platform/identity-service/spec.md +119 -0
  929. package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
  930. package/examples/docs/services/platform/notification-service/health.yaml +35 -0
  931. package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
  932. package/examples/docs/services/platform/notification-service/runbook.md +48 -0
  933. package/examples/docs/services/platform/notification-service/spec.md +112 -0
  934. package/examples/docs/services/platform/subsystem.yaml +2 -0
  935. package/examples/fleet.yaml +57 -0
  936. package/package.json +19 -6
  937. package/dist/commands/adopt.js +0 -240
  938. package/dist/commands/adopt.js.map +0 -1
  939. package/dist/commands/archive.js +0 -1313
  940. package/dist/commands/archive.js.map +0 -1
  941. package/dist/commands/delta.js +0 -388
  942. package/dist/commands/delta.js.map +0 -1
  943. package/dist/commands/docs-repo-gate.js.map +0 -1
  944. package/dist/commands/format.js +0 -17
  945. package/dist/commands/format.js.map +0 -1
  946. package/dist/commands/gherkin.js +0 -309
  947. package/dist/commands/gherkin.js.map +0 -1
  948. package/dist/commands/init.js.map +0 -1
  949. package/dist/commands/list.js +0 -291
  950. package/dist/commands/list.js.map +0 -1
  951. package/dist/commands/migrate-openspec.js +0 -950
  952. package/dist/commands/migrate-openspec.js.map +0 -1
  953. package/dist/commands/new.js +0 -413
  954. package/dist/commands/new.js.map +0 -1
  955. package/dist/commands/rebase.js +0 -356
  956. package/dist/commands/rebase.js.map +0 -1
  957. package/dist/commands/show.js.map +0 -1
  958. package/dist/commands/status.js +0 -254
  959. package/dist/commands/status.js.map +0 -1
  960. package/dist/commands/unarchive.js.map +0 -1
  961. package/dist/commands/validate.js +0 -1591
  962. package/dist/commands/validate.js.map +0 -1
  963. package/dist/commands/verify.js +0 -775
  964. package/dist/commands/verify.js.map +0 -1
  965. package/dist/commands/vouch.js +0 -343
  966. package/dist/commands/vouch.js.map +0 -1
  967. package/dist/core/agent.js +0 -2065
  968. package/dist/core/agent.js.map +0 -1
  969. package/dist/core/agents-stamp.js +0 -68
  970. package/dist/core/agents-stamp.js.map +0 -1
  971. package/dist/core/arch.js +0 -130
  972. package/dist/core/arch.js.map +0 -1
  973. package/dist/core/brief.js +0 -733
  974. package/dist/core/brief.js.map +0 -1
  975. package/dist/core/coherence.js +0 -577
  976. package/dist/core/coherence.js.map +0 -1
  977. package/dist/core/concurrency.js.map +0 -1
  978. package/dist/core/config.js.map +0 -1
  979. package/dist/core/delta.js +0 -476
  980. package/dist/core/delta.js.map +0 -1
  981. package/dist/core/dependencies.js +0 -356
  982. package/dist/core/dependencies.js.map +0 -1
  983. package/dist/core/doctor.js +0 -559
  984. package/dist/core/doctor.js.map +0 -1
  985. package/dist/core/document-bytes.js.map +0 -1
  986. package/dist/core/explore.js.map +0 -1
  987. package/dist/core/frontmatter.js.map +0 -1
  988. package/dist/core/gherkin.js +0 -463
  989. package/dist/core/gherkin.js.map +0 -1
  990. package/dist/core/health.js +0 -67
  991. package/dist/core/health.js.map +0 -1
  992. package/dist/core/ids.js +0 -122
  993. package/dist/core/ids.js.map +0 -1
  994. package/dist/core/issue.js +0 -9
  995. package/dist/core/issue.js.map +0 -1
  996. package/dist/core/json.js +0 -74
  997. package/dist/core/json.js.map +0 -1
  998. package/dist/core/likec4.js +0 -479
  999. package/dist/core/likec4.js.map +0 -1
  1000. package/dist/core/maturity.js +0 -66
  1001. package/dist/core/maturity.js.map +0 -1
  1002. package/dist/core/openapi-merge.js +0 -552
  1003. package/dist/core/openapi-merge.js.map +0 -1
  1004. package/dist/core/openapi.js.map +0 -1
  1005. package/dist/core/openspec-inventory.js +0 -1440
  1006. package/dist/core/openspec-inventory.js.map +0 -1
  1007. package/dist/core/path-safety.js.map +0 -1
  1008. package/dist/core/provenance.js +0 -720
  1009. package/dist/core/provenance.js.map +0 -1
  1010. package/dist/core/records.js.map +0 -1
  1011. package/dist/core/repo.js +0 -436
  1012. package/dist/core/repo.js.map +0 -1
  1013. package/dist/core/report.js.map +0 -1
  1014. package/dist/core/spec.js +0 -481
  1015. package/dist/core/spec.js.map +0 -1
  1016. package/dist/core/staging.js +0 -890
  1017. package/dist/core/staging.js.map +0 -1
  1018. package/dist/core/status.js +0 -1104
  1019. package/dist/core/status.js.map +0 -1
  1020. package/dist/core/steps.js +0 -72
  1021. package/dist/core/steps.js.map +0 -1
  1022. package/dist/core/verify.js +0 -807
  1023. package/dist/core/verify.js.map +0 -1
  1024. package/dist/core/version.js.map +0 -1
  1025. /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
  1026. /package/dist/core/{records.js → kernel/records.js} +0 -0
@@ -1,720 +0,0 @@
1
- /**
2
- * Provenance checks: is this artifact anchored to anything, and has anyone
3
- * vouched for it?
4
- *
5
- * SCHEMA.md has declared `status` / `owner` / `sources` / `last_verified` since
6
- * the beginning and nothing read them. They matter more now that the prose is
7
- * written by an agent: coherence proves the corpus agrees with itself, and only
8
- * `sources` says it has anything to do with the code.
9
- *
10
- * Absence and contradiction are graded differently on purpose. A missing field
11
- * is incompleteness — a warning, something to work through. A field that says
12
- * the wrong thing (a spec claiming to be another service, a status nobody
13
- * defined) is a bug, and gates.
14
- */
15
- import { spawn } from "node:child_process";
16
- import { createHash } from "node:crypto";
17
- import { existsSync } from "node:fs";
18
- import { readdir, readFile, realpath, stat } from "node:fs/promises";
19
- import { join, relative, resolve, sep } from "node:path";
20
- import { listField, parseFrontmatter, rawBody, readFrontmatter, stringField, FEATURE_STATUSES, SERVICE_STATUSES, } from "./frontmatter.js";
21
- import { featurePaths, servicePaths, SPEC_AXES } from "./repo.js";
22
- import { isPathInside, resolveInside } from "./path-safety.js";
23
- /** Fields every artifact is expected to carry, beyond its identity and status. */
24
- const EXPECTED = ["owner"];
25
- export async function serviceProvenance(docsDir, service, opts = {}) {
26
- const paths = servicePaths(docsDir, service);
27
- const findings = [];
28
- // Both requirement-carrying specs get the same pass: arch.spec.md follows
29
- // spec.md's frontmatter conventions exactly, so the checks are one loop —
30
- // only the label tells a reader which file moved. The pair comes from
31
- // SPEC_AXES rather than being respelled, so a third axis is graded here the
32
- // day it is declared instead of the day somebody notices.
33
- for (const { path, file } of SPEC_AXES.map((axis) => ({ path: paths[axis.key], file: axis.file }))) {
34
- if (!existsSync(path))
35
- continue;
36
- const raw = await readFile(path, "utf8");
37
- const fm = parseFrontmatter(raw);
38
- const label = `${service}: ${file}`;
39
- findings.push(...identityFindings(fm, {
40
- label,
41
- idField: "service",
42
- idValue: service,
43
- statuses: [...SERVICE_STATUSES],
44
- }));
45
- // With no frontmatter at all, "it names no sources" says nothing the missing
46
- // header did not already say — and a malformed one proves nothing either:
47
- // `sources.absent` against a header nobody can read is the same false
48
- // advice as the field cascade, so frontmatter.malformed stands alone.
49
- if (fm.present && !fm.malformed) {
50
- findings.push(...(await sourceFindings(fm, service, label, opts.repoDir)));
51
- findings.push(...contentFindings(fm, raw, service, label));
52
- }
53
- }
54
- return findings;
55
- }
56
- export async function featureProvenance(featureDir, featureId) {
57
- const path = featurePaths(featureDir).intent;
58
- if (!existsSync(path))
59
- return [];
60
- const fm = await readFrontmatter(path);
61
- return identityFindings(fm, {
62
- label: "intent.md",
63
- idField: "feature",
64
- idValue: featureId,
65
- statuses: [...FEATURE_STATUSES],
66
- });
67
- }
68
- function identityFindings(fm, spec) {
69
- const findings = [];
70
- if (!fm.present) {
71
- return [
72
- {
73
- severity: "warn",
74
- code: "frontmatter.missing",
75
- subject: spec.idValue,
76
- message: `${spec.label} has no frontmatter — no owner, no status, no link to the code it describes`,
77
- },
78
- ];
79
- }
80
- // One honest error instead of the cascade: with an unreadable header the
81
- // field checks below would grade owner/status/service "missing" and send the
82
- // author adding fields to a block YAML refuses to parse. Nothing can be
83
- // concluded from a header nobody can read — including that it lacks fields.
84
- if (fm.malformed) {
85
- return [
86
- {
87
- severity: "error",
88
- code: "frontmatter.malformed",
89
- subject: spec.idValue,
90
- message: `${spec.label} has frontmatter that does not parse as YAML — owner, status and sources are unreadable until the header is fixed`,
91
- },
92
- ];
93
- }
94
- const id = stringField(fm, spec.idField);
95
- if (id !== undefined && id !== spec.idValue) {
96
- findings.push({
97
- severity: "error",
98
- code: "frontmatter.field-mismatch",
99
- subject: spec.idValue,
100
- message: `${spec.label} declares ${spec.idField}: ${id}, but it lives under ${spec.idValue}`,
101
- });
102
- }
103
- const status = stringField(fm, "status");
104
- if (status !== undefined && !spec.statuses.includes(status)) {
105
- findings.push({
106
- severity: "error",
107
- code: "frontmatter.status-unknown",
108
- subject: spec.idValue,
109
- message: `${spec.label} has status '${status}' — expected one of ${spec.statuses.join(", ")}`,
110
- });
111
- }
112
- const missing = [
113
- ...(id === undefined ? [spec.idField] : []),
114
- ...(status === undefined ? ["status"] : []),
115
- ...EXPECTED.filter((f) => stringField(fm, f) === undefined),
116
- ];
117
- if (missing.length > 0) {
118
- findings.push({
119
- severity: "warn",
120
- code: "frontmatter.field-missing",
121
- subject: spec.idValue,
122
- message: `${spec.label} is missing ${missing.length} frontmatter field(s)`,
123
- details: missing,
124
- text: { detailPrefix: "- " },
125
- });
126
- }
127
- return findings;
128
- }
129
- async function sourceFindings(fm, service, label, repoDir) {
130
- const sources = listField(fm, "sources");
131
- if (sources.length === 0) {
132
- return [
133
- {
134
- severity: "warn",
135
- code: "sources.absent",
136
- message: `${label} names no sources — nothing ties it to the code, so nothing can tell you when it goes out of date`,
137
- },
138
- ];
139
- }
140
- // Someone else's repository: the paths describe a tree loam is not standing in.
141
- if (repoDir === undefined)
142
- return [];
143
- // Before existence: a pattern entry would "not exist" as a literal path, and
144
- // grading it missing would send the author fixing the wrong thing.
145
- const patterns = patternSources(sources);
146
- if (patterns.length > 0) {
147
- return [
148
- {
149
- severity: "error",
150
- code: "sources.path-missing",
151
- message: `${label}: ${patterns.length} source(s) are glob patterns — ${patterns.join(", ")}. Patterns are no longer supported: name files or directories (a directory already covers everything beneath it).`,
152
- details: patterns,
153
- text: { detailPrefix: "- " },
154
- },
155
- ];
156
- }
157
- const unsafe = unsafeSources(repoDir, sources);
158
- if (unsafe.length > 0) {
159
- return [
160
- {
161
- severity: "error",
162
- code: "sources.path-outside",
163
- message: `${label}: ${unsafe.length} source(s) escape the service repo — ${unsafe.join(", ")}. Sources must be relative paths contained by this repository, including through symlinks.`,
164
- details: unsafe,
165
- text: { detailPrefix: "- " },
166
- },
167
- ];
168
- }
169
- const missing = missingSources(repoDir, sources);
170
- if (missing.length > 0) {
171
- return [
172
- {
173
- severity: "error",
174
- code: "sources.path-missing",
175
- message: `${label}: ${missing.length} source(s) do not exist — ${missing.join(", ")}`,
176
- details: missing,
177
- text: { detailPrefix: "- " },
178
- },
179
- ];
180
- }
181
- const resolved = {
182
- severity: "ok",
183
- code: "sources.resolved",
184
- message: `${label}: ${sources.length} source(s) resolve`,
185
- };
186
- // The walk happens here rather than inside the staleness branch below, even
187
- // though only staleness needs the hashes: what the walk REFUSED to follow is
188
- // a hole in the tie to the code whether or not anybody has vouched yet, and
189
- // an unvouched service is exactly where a reader is about to decide the
190
- // sources list is honest.
191
- const { digest, files, index, skipped } = await sourcesDigest(repoDir, sources);
192
- const findings = [resolved, ...skippedFindings(skipped, label)];
193
- // The paths are there; the question staleness answers is whether what is AT
194
- // them is still what somebody read.
195
- const stamped = stringField(fm, "sources_digest");
196
- if (stamped === undefined) {
197
- return [
198
- ...findings,
199
- {
200
- severity: "warn",
201
- code: "sources.unvouched",
202
- message: `${label}: no sources_digest — nobody has vouched for this against the code, so nothing can tell you when it goes stale. Run \`loam vouch --service ${service}\`.`,
203
- },
204
- ];
205
- }
206
- const since = stringField(fm, "last_verified") ?? "it was stamped";
207
- if (digest === stamped) {
208
- return [
209
- ...findings,
210
- {
211
- severity: "ok",
212
- code: "sources.current",
213
- message: `${label}: sources unchanged since ${since} (${files.length} file(s), digest ${digest})`,
214
- },
215
- ];
216
- }
217
- // What MOVED, when the stamp recorded enough to say. Repeating the frontmatter's
218
- // own `sources` entries back at a reader — which is all this finding could do
219
- // before `sources_files` existed — answers a question nobody asked: they wrote
220
- // that list, and "one of these five directories changed somehow" is where the
221
- // search starts, not where it ends.
222
- const moved = movedSources(decodeSourceIndex(stringField(fm, "sources_files")), index);
223
- return [
224
- ...findings,
225
- {
226
- // A warning, not an error: the doc may still be right, and only a person
227
- // can say. What loam knows is that nobody has looked since the code moved.
228
- severity: "warn",
229
- code: "sources.stale",
230
- message: `${label}: sources changed since ${since}${moved.summary} — re-read them and \`loam vouch --service ${service}\``,
231
- details: moved.paths ?? sources,
232
- text: { detailPrefix: "- " },
233
- },
234
- ];
235
- }
236
- /**
237
- * The paths the digest walk would not follow. Never silent: a symlink dropped
238
- * on the floor is a file whose content nobody is watching, while the document
239
- * beside it says `verified` — the digest cannot go stale over bytes it never
240
- * hashed, so the one thing the stamp promises is quietly untrue for them.
241
- *
242
- * A warning, not an error, and for the same reason staleness is: the doc may be
243
- * perfectly right about the code behind that link. What loam can say is that it
244
- * is not watching it.
245
- */
246
- function skippedFindings(skipped, label) {
247
- if (skipped.length === 0)
248
- return [];
249
- return [
250
- {
251
- severity: "warn",
252
- code: "sources.skipped",
253
- message: `${label}: ${skipped.length} path(s) under the listed sources were not hashed — the digest says nothing about what is behind them`,
254
- details: skipped.map((s) => `${s.path} — ${s.reason}`),
255
- text: { detailPrefix: "- " },
256
- },
257
- ];
258
- }
259
- /**
260
- * The doc-side half of the freshness check. `sources_digest` says whether the
261
- * CODE moved since a person looked, and only that service's repo can recompute
262
- * it; `content_digest` says whether the DOCUMENT did, and needs nothing but
263
- * the document — so this runs wherever the spec is readable, `--service` and
264
- * `--all` alike. Without it, editing a spec after it was vouched left
265
- * `status: verified` standing over words nobody read — forged freshness, in
266
- * the exact agent-written-prose threat model this layer exists for.
267
- */
268
- function contentFindings(fm, raw, service, label) {
269
- if (stringField(fm, "status") !== "verified")
270
- return [];
271
- const stamped = stringField(fm, "content_digest");
272
- // A verified doc with no stamp predates the field. Quiet on purpose: the fix
273
- // is re-vouching, and grading years of pre-feature vouches as suspect would
274
- // drown the fleet in warnings nobody chose.
275
- if (stamped === undefined)
276
- return [];
277
- if (contentDigest(raw) === stamped)
278
- return [];
279
- const since = stringField(fm, "last_verified") ?? "it was vouched";
280
- return [
281
- {
282
- // A warning, not an error — the sources.stale doctrine: the doc changed
283
- // since it was vouched, and only a person can say whether verified still
284
- // holds of the new words.
285
- severity: "warn",
286
- code: "content.stale",
287
- message: `${label} changed since ${since} — the doc moved under its vouch, and only a person can say whether 'verified' still holds. Re-read it and \`loam vouch --service ${service}\`.`,
288
- },
289
- ];
290
- }
291
- /**
292
- * The local calendar day, for the two commands that date a stamp. A vouch or a
293
- * verification record is a person saying "today I read this", so it is their
294
- * date, not UTC's — `toISOString` files an evening in the Americas under
295
- * tomorrow. It sits here because this module already owns the stamp vocabulary
296
- * the date is written into.
297
- */
298
- export function today(now) {
299
- const pad = (n) => String(n).padStart(2, "0");
300
- return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
301
- }
302
- /* ------------------------------------------------------------------ */
303
- /* The content digest */
304
- /* ------------------------------------------------------------------ */
305
- /** How much of the sha256 is written into the document. */
306
- const DIGEST_LENGTH = 16;
307
- /** How many source files the digest reads at once — see `sourcesDigest`. */
308
- const DIGEST_READ_BATCH = 32;
309
- /**
310
- * Digest the CONTENT of the files `sources` names. The recipe is spelled out
311
- * because the value is written into documents, and anything reading them has to
312
- * be able to reproduce it:
313
- *
314
- * 1. expand each entry to repo-relative file paths (`/` separators) — a file
315
- * is itself, a directory everything beneath it, minus what the repository
316
- * does not consider its own (see collectSources) — sorted and de-duplicated;
317
- * 2. per file, `sha256(bytes)`;
318
- * 3. feed `<path>\0<hex>\n` for each file, in that order, into an outer
319
- * sha256;
320
- * 4. keep the first 16 hex characters.
321
- *
322
- * Content, not mtime: git does not preserve modification times, so after a
323
- * fresh clone every file looks changed and the check would be false positives
324
- * end to end. Bytes survive the clone. Hashing the path alongside the content
325
- * means a rename registers, which is what a reader of the doc would want.
326
- *
327
- * 64 bits is a change detector, not a seal — it answers "did this move?", and
328
- * an adversary who wants a collision can have one.
329
- */
330
- export async function sourcesDigest(repoDir, sources) {
331
- const { found, skipped } = await collectSources(repoDir, sources);
332
- const outer = createHash("sha256");
333
- const index = [];
334
- // Read in fixed batches, hash in array order. `found` is already sorted and
335
- // every file's own sha depends on nothing but its own bytes, so the sequence
336
- // fed to `outer` — and therefore the digest — is unchanged by construction;
337
- // only the waiting overlaps. A `sources: [src/]` over a real service repo is
338
- // thousands of files, and one-await-per-file spent nearly all of its time
339
- // idle. The batch is bounded rather than a single `Promise.all` over the
340
- // whole list because an unbounded fan-out over a source tree runs the process
341
- // out of file descriptors, which would turn a stamp into an EMFILE.
342
- for (let start = 0; start < found.length; start += DIGEST_READ_BATCH) {
343
- const hashed = await Promise.all(found.slice(start, start + DIGEST_READ_BATCH).map(async (file) => ({
344
- rel: file.rel,
345
- content: createHash("sha256").update(await readFile(file.abs)).digest("hex"),
346
- })));
347
- for (const { rel, content } of hashed) {
348
- outer.update(`${rel}\0${content}\n`);
349
- index.push({ path: rel, sha: content.slice(0, DIGEST_LENGTH) });
350
- }
351
- }
352
- // `empty` is deliberately not set here: it is a sentence about a named
353
- // document, and a digest has no name to put in it. Callers that need it say
354
- // emptySourcesMessage(label, sources) — the same words, from one definition.
355
- return { digest: outer.digest("hex").slice(0, DIGEST_LENGTH), files: index.map((e) => e.path), index, skipped };
356
- }
357
- /**
358
- * What a `sources` list actually covers — the digest's file set without the
359
- * hashing.
360
- *
361
- * Exported because two commands must give the SAME answer to "does this list
362
- * cover anything?". `loam vouch` refuses to stamp an expansion that covers no
363
- * files (a digest over nothing never changes, so the stamp would read as
364
- * current forever), and until `loam validate` could say the same thing in the
365
- * same words, an author got a green validate followed by a vouch that refused —
366
- * two commands contradicting each other about one document, with nothing in the
367
- * green run hinting at it.
368
- */
369
- export async function expandSourceFiles(repoDir, sources, label) {
370
- const { found, skipped } = await collectSources(repoDir, sources);
371
- const files = found.map((f) => f.rel);
372
- return { files, skipped, ...(files.length === 0 ? { empty: emptySourcesMessage(label, sources) } : {}) };
373
- }
374
- /**
375
- * The one sentence for "these paths exist and cover no file". One definition,
376
- * because `vouch`'s refusal and `validate`'s finding are the same diagnosis
377
- * about the same document and must not drift into two descriptions of it — the
378
- * author fixes it once, in the sources list.
379
- */
380
- export function emptySourcesMessage(label, sources) {
381
- return `${label}: the sources listed match no files — ${sources.join(", ")}. A digest over nothing would read as current forever.`;
382
- }
383
- /**
384
- * The stamp `loam vouch` writes into `content_digest`: sha256 of the
385
- * document's own BODY — every byte after the frontmatter block (below the
386
- * closing `---` line and its newline; `rawBody` is the one definition of that
387
- * cut) — first 16 hex characters, the sources recipe's length.
388
- *
389
- * Byte-exact, no normalization. Body-only is load-bearing: vouch itself
390
- * rewrites the frontmatter as it stamps, and a later frontmatter-only edit
391
- * (another vouch, a corrected owner) must not read as the document moving.
392
- */
393
- export function contentDigest(source) {
394
- return createHash("sha256").update(rawBody(source), "utf8").digest("hex").slice(0, DIGEST_LENGTH);
395
- }
396
- /**
397
- * The files a `sources` list names: a file is itself, a directory is everything
398
- * beneath it. Nothing else — glob patterns used to be matched here, by a
399
- * hand-rolled dialect that silently differed from the gitignore/minimatch
400
- * conventions authors assume, so a pattern quietly digested a DIFFERENT file
401
- * set than its author intended. Pattern-looking entries are now refused loudly
402
- * upstream (see patternSources); this function only ever sees literal paths.
403
- *
404
- * Three exclusions, all part of the digest recipe's contract:
405
- *
406
- * - dot-entries are skipped while walking — `.git` is not what the doc was
407
- * written from — though a path naming one outright is still honoured;
408
- * - `node_modules` is skipped the same way, unconditionally: it is the one
409
- * build input every ecosystem agrees is not source, and it is the one that
410
- * makes the walk take minutes;
411
- * - anything the repository's own `.gitignore` covers is dropped, when the
412
- * repo is a git checkout and git is on the PATH (see gitIgnoredPaths).
413
- *
414
- * The third is the one worth stating a reason for. `sources_digest` answers
415
- * "did the code move since a person read it", and BUILD OUTPUT moves on every
416
- * CI run without anybody touching the code — a `sources: [src/]` over a repo
417
- * that compiles into `src/generated/` went stale on a schedule, so the warning
418
- * that means "re-read this" arrived when nothing had been written. A signal
419
- * that fires every night is a signal people learn to close. Git's answer is
420
- * used rather than a list of our own because it is the answer the repository
421
- * already gives every other tool, and it is the author's to change.
422
- *
423
- * The fallback is deliberate: no git, no checkout, a git that errors — hash
424
- * everything. Missing an exclusion costs noise; inventing one costs a file the
425
- * stamp silently stops watching, and this walk exists to have nothing in that
426
- * category.
427
- */
428
- async function collectSources(repoDir, sources) {
429
- const found = new Map();
430
- const skipped = new Map();
431
- const relOf = (abs) => relative(repoDir, abs).split(sep).join("/");
432
- // realpath once, up front: every containment question below is asked against
433
- // the resolved root, so a repo reached through a symlink (a worktree under
434
- // /var -> /private/var on macOS, say) does not make its own files look external.
435
- const repoReal = await realpath(repoDir).catch(() => resolve(repoDir));
436
- // The realpaths of the directories currently being walked — the cycle guard.
437
- // A STACK rather than a set of everything ever entered, because the two rules
438
- // answer different questions: a directory reachable by two spellings (a
439
- // `current -> versions/3` link beside the real tree) is content under both
440
- // names and belongs in the digest twice, while a directory reachable from
441
- // INSIDE itself is a loop. A global visited-set conflates them, and then which
442
- // spelling survives depends on the order readdir happened to return — a
443
- // digest that differs between two machines holding identical bytes.
444
- const walking = [];
445
- const walk = async (dir) => {
446
- const entries = await readdir(dir, { withFileTypes: true }).catch(() => []);
447
- // Sorted, so a tree walks the same way on every filesystem.
448
- entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
449
- for (const entry of entries) {
450
- if (entry.name.startsWith(".") || entry.name === "node_modules")
451
- continue;
452
- const child = join(dir, entry.name);
453
- if (entry.isDirectory())
454
- await enterDir(child);
455
- else if (entry.isFile())
456
- found.set(relOf(child), child);
457
- // readdir reports symlinks by lstat, so isDirectory() and isFile() are
458
- // BOTH false for one: before this branch existed a symlinked file, and a
459
- // whole subtree behind a symlinked directory, fell between the two arms
460
- // and left the digest without a word said. That is the failure this
461
- // module is here to prevent, arriving through its own walk.
462
- else if (entry.isSymbolicLink())
463
- await follow(child);
464
- }
465
- };
466
- const enterDir = async (dir) => {
467
- const real = await realpath(dir).catch(() => null);
468
- if (real === null || walking.includes(real))
469
- return;
470
- walking.push(real);
471
- try {
472
- await walk(dir);
473
- }
474
- finally {
475
- walking.pop();
476
- }
477
- };
478
- const follow = async (link) => {
479
- const real = await realpath(link).catch(() => null);
480
- if (real === null) {
481
- skipped.set(relOf(link), "a symlink that does not resolve");
482
- return;
483
- }
484
- // Outside the repo the file is not this service's to vouch for, and the
485
- // same rule already refuses it as a top-level `sources` entry
486
- // (sources.path-outside). Reported rather than dropped: an author who
487
- // vendored a sibling repo through a symlink needs to know the stamp stops
488
- // at the link.
489
- if (!isPathInside(repoReal, real)) {
490
- skipped.set(relOf(link), "a symlink whose target is outside this repository");
491
- return;
492
- }
493
- const info = await stat(link).catch(() => null);
494
- if (info === null) {
495
- skipped.set(relOf(link), "a symlink that does not resolve");
496
- return;
497
- }
498
- // A link's own spelling is what the doc's author wrote, so that is the path
499
- // that goes into the digest — the content comes from the target either way.
500
- if (info.isFile())
501
- found.set(relOf(link), link);
502
- // A link that closes a loop is not reported: everything behind it is already
503
- // in the digest under the spelling it was reached by, so nothing has stopped
504
- // being watched. Only unhashed CONTENT is worth a warning.
505
- else if (info.isDirectory())
506
- await enterDir(link);
507
- else
508
- skipped.set(relOf(link), "a symlink to neither a file nor a directory");
509
- };
510
- for (const source of sources) {
511
- const cleaned = source.trim();
512
- if (cleaned.length === 0)
513
- continue;
514
- const root = resolveInside(repoDir, cleaned, `source '${source}'`);
515
- const info = await stat(root).catch(() => null);
516
- if (info === null)
517
- continue;
518
- if (info.isFile())
519
- found.set(relOf(root), root);
520
- else if (info.isDirectory())
521
- await enterDir(root);
522
- }
523
- // One git invocation for the whole expansion, not one per file: the skipped
524
- // list rides along so an ignored symlink does not warn about a path the
525
- // repository already says is not its own.
526
- const ignored = await gitIgnoredPaths(repoDir, [...found.keys(), ...skipped.keys()]);
527
- for (const rel of ignored) {
528
- found.delete(rel);
529
- skipped.delete(rel);
530
- }
531
- return {
532
- // Plain codepoint order, not locale order: the digest has to be the same
533
- // everywhere it is computed.
534
- found: [...found.entries()]
535
- .map(([rel, abs]) => ({ rel, abs }))
536
- .sort((a, b) => (a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0)),
537
- skipped: [...skipped.entries()]
538
- .map(([path, reason]) => ({ path, reason }))
539
- .sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0)),
540
- };
541
- }
542
- /** How long the digest waits on git before deciding it learned nothing. */
543
- const GIT_TIMEOUT_MS = 10_000;
544
- /**
545
- * Which of these repo-relative paths the repository ignores, asked once for the
546
- * whole list. `git check-ignore` is the authority on purpose — it reads
547
- * `.gitignore` at every level, `.git/info/exclude` and the user's global
548
- * excludes, and it already knows that a TRACKED file is not ignored no matter
549
- * what a pattern says, which is the distinction a re-implementation always gets
550
- * wrong.
551
- *
552
- * Every failure answers "nothing is ignored": exit 1 is git saying so, exit 128
553
- * is "not a git repository", a spawn error is git not being installed, and a
554
- * timeout is a repository too strange to wait for. None of them justify
555
- * dropping a file from a digest a person is going to sign.
556
- */
557
- async function gitIgnoredPaths(repoDir, rels) {
558
- if (rels.length === 0)
559
- return new Set();
560
- return new Promise((done) => {
561
- const child = spawn("git", ["check-ignore", "--stdin", "-z"], {
562
- cwd: repoDir,
563
- stdio: ["pipe", "pipe", "ignore"],
564
- timeout: GIT_TIMEOUT_MS,
565
- });
566
- let out = "";
567
- child.stdout.setEncoding("utf8");
568
- child.stdout.on("data", (chunk) => {
569
- out += chunk;
570
- });
571
- child.on("error", () => done(new Set()));
572
- child.on("close", (code) => {
573
- // 0: some paths are ignored and are on stdout. 1: none are — an empty
574
- // answer, not a failure. Anything else: we learned nothing.
575
- done(code === 0 || code === 1 ? new Set(out.split("\0").filter((s) => s.length > 0)) : new Set());
576
- });
577
- // A git that died before reading its input hands us EPIPE; the close
578
- // handler above is what decides the outcome either way.
579
- child.stdin.on("error", () => undefined);
580
- child.stdin.end(rels.join("\0") + "\0");
581
- });
582
- }
583
- /* ------------------------------------------------------------------ */
584
- /* The per-file index: what `sources.stale` names */
585
- /* ------------------------------------------------------------------ */
586
- /**
587
- * How many files `sources_files` will list one by one before it gives up and
588
- * records only how many there were.
589
- *
590
- * A readability budget, not a correctness one: the index lives in the header of
591
- * a document a person reads, and a `sources: [src/]` over a legacy service can
592
- * expand to thousands of files. Past the limit `sources.stale` falls back to
593
- * repeating the `sources` entries — worse advice, but a spec.md whose
594
- * frontmatter is longer than its requirements is worse still.
595
- */
596
- const SOURCE_INDEX_LIMIT = 100;
597
- /**
598
- * The `sources_files` value `loam vouch` stamps beside `sources_digest`: one
599
- * `<sha> <path>` line per file (sha256sum's layout, and its column order, so
600
- * the path may contain spaces), or just the file count once the list would run
601
- * past SOURCE_INDEX_LIMIT.
602
- *
603
- * Its whole purpose is the next `sources.stale`. `sources_digest` can say THAT
604
- * the code moved and never which part of it; with the index a reader gets the
605
- * added, removed and changed paths, which is the difference between re-reading
606
- * one file and re-reading a directory. It is also a readable git diff in the
607
- * docs repo: the vouch commit shows exactly which source files the stamp now
608
- * stands over.
609
- */
610
- export function encodeSourceIndex(index) {
611
- if (index.length > SOURCE_INDEX_LIMIT)
612
- return String(index.length);
613
- return index.map((e) => `${e.sha} ${e.path}`).join("\n");
614
- }
615
- /**
616
- * Read back what `encodeSourceIndex` wrote. Anything unrecognised reads as "the
617
- * stamp said nothing" rather than as an empty index: a header nobody can parse
618
- * must not turn into a `sources.stale` claiming every file was deleted.
619
- */
620
- function decodeSourceIndex(stamped) {
621
- if (stamped === undefined)
622
- return { entries: null };
623
- const text = stamped.trim();
624
- if (text.length === 0)
625
- return { entries: null };
626
- if (/^\d+$/.test(text))
627
- return { entries: null, count: Number(text) };
628
- const entries = new Map();
629
- for (const line of text.split("\n")) {
630
- const match = /^([0-9a-f]{16})\s+(.+)$/.exec(line.trim());
631
- if (match === null)
632
- return { entries: null };
633
- entries.set(match[2], match[1]);
634
- }
635
- return { entries, count: entries.size };
636
- }
637
- /**
638
- * added / removed / changed, from the stamped index against the current one.
639
- * The annotation travels IN the detail line rather than in three separate
640
- * lists: a reader scanning a stale report wants the paths in one column, and
641
- * "which of the three" is one word wide.
642
- */
643
- function movedSources(stamp, now) {
644
- if (stamp.entries === null) {
645
- // No index, but the count alone still beats silence: "12 files then, 14
646
- // now" tells a reader to go looking for two new files.
647
- return {
648
- summary: stamp.count === undefined ? "" : ` (${stamp.count} file(s) then, ${now.length} now)`,
649
- };
650
- }
651
- const paths = [];
652
- const current = new Map(now.map((e) => [e.path, e.sha]));
653
- for (const [path, sha] of current) {
654
- const before = stamp.entries.get(path);
655
- if (before === undefined)
656
- paths.push(`added ${path}`);
657
- else if (before !== sha)
658
- paths.push(`changed ${path}`);
659
- }
660
- for (const path of stamp.entries.keys())
661
- if (!current.has(path))
662
- paths.push(`removed ${path}`);
663
- paths.sort();
664
- // An index that agrees with the current tree while the digest does not is a
665
- // contradiction (a truncation collision, or a hand-edited header). Say
666
- // nothing rather than print an empty list under a staleness warning.
667
- if (paths.length === 0)
668
- return { summary: "" };
669
- return { paths, summary: ` (${paths.length} path(s) moved)` };
670
- }
671
- /** The characters that made an entry a pattern under the glob dialect loam no longer ships. */
672
- const PATTERN_CHARS = /[*?[]/;
673
- /**
674
- * The `sources` entries that look like glob patterns — anything containing
675
- * `*`, `?` or `[`. Patterns are refused loudly everywhere sources are consumed
676
- * (`loam vouch` refuses the run, `loam validate` grades an error), never
677
- * resolved: the glob dialect loam used to ship silently differed from the
678
- * gitignore/minimatch conventions authors assume — bracket classes literal,
679
- * its own `**` handling — so a pattern quietly digested a different file set
680
- * than intended, corrupting the staleness signal in both directions. A
681
- * directory already means "everything beneath it", so the fix is to name one.
682
- *
683
- * The cost accepted with the rule: a real file with `[` in its name (a Next.js
684
- * route, say) cannot be listed on its own — its parent directory covers it.
685
- */
686
- export function patternSources(sources) {
687
- return sources.filter((s) => PATTERN_CHARS.test(s.trim()));
688
- }
689
- /** The `sources` entries that resolve to nothing in this repo. */
690
- export function missingSources(repoDir, sources) {
691
- return sources.filter((s) => !sourceExists(repoDir, s));
692
- }
693
- /** Entries that are absolute, traverse upward, or escape through a symlink. */
694
- export function unsafeSources(repoDir, sources) {
695
- return sources.filter((source) => {
696
- const cleaned = source.trim();
697
- if (cleaned.length === 0)
698
- return false;
699
- try {
700
- resolveInside(repoDir, cleaned, `source '${source}'`);
701
- return false;
702
- }
703
- catch {
704
- return true;
705
- }
706
- });
707
- }
708
- /** Does a `sources` entry point at something real? Literal paths only, checked exactly. */
709
- function sourceExists(repoDir, source) {
710
- const cleaned = source.trim();
711
- if (cleaned.length === 0)
712
- return false;
713
- try {
714
- return existsSync(resolveInside(repoDir, cleaned, `source '${source}'`));
715
- }
716
- catch {
717
- return false;
718
- }
719
- }
720
- //# sourceMappingURL=provenance.js.map