@intentius/chant 0.13.1 → 0.15.0

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 (450) hide show
  1. package/dist/audit/catalog.d.ts +45 -5
  2. package/dist/audit/catalog.d.ts.map +1 -1
  3. package/dist/audit/proof.d.ts +3 -0
  4. package/dist/audit/proof.d.ts.map +1 -1
  5. package/dist/audit/report-model.d.ts +4 -1
  6. package/dist/audit/report-model.d.ts.map +1 -1
  7. package/dist/audit/report.d.ts +3 -0
  8. package/dist/audit/report.d.ts.map +1 -1
  9. package/dist/audit/rules-doc.d.ts +8 -2
  10. package/dist/audit/rules-doc.d.ts.map +1 -1
  11. package/dist/cli/commands/audit.d.ts.map +1 -1
  12. package/dist/cli/commands/doctor.d.ts.map +1 -1
  13. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts +37 -0
  14. package/dist/cli/commands/lexicon-rolling-upgrade.d.ts.map +1 -0
  15. package/dist/cli/commands/lexicon-surface-diff.d.ts +48 -0
  16. package/dist/cli/commands/lexicon-surface-diff.d.ts.map +1 -0
  17. package/dist/cli/commands/lint.d.ts.map +1 -1
  18. package/dist/cli/commands/pinned-upgrade.d.ts +41 -0
  19. package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -0
  20. package/dist/cli/handlers/build.d.ts.map +1 -1
  21. package/dist/cli/handlers/components.d.ts +39 -0
  22. package/dist/cli/handlers/components.d.ts.map +1 -0
  23. package/dist/cli/handlers/dev.d.ts +3 -0
  24. package/dist/cli/handlers/dev.d.ts.map +1 -1
  25. package/dist/cli/handlers/graph.d.ts +4 -2
  26. package/dist/cli/handlers/graph.d.ts.map +1 -1
  27. package/dist/cli/handlers/misc.d.ts.map +1 -1
  28. package/dist/cli/handlers/run.d.ts +49 -0
  29. package/dist/cli/handlers/run.d.ts.map +1 -1
  30. package/dist/cli/main.d.ts.map +1 -1
  31. package/dist/cli/registry.d.ts +35 -0
  32. package/dist/cli/registry.d.ts.map +1 -1
  33. package/dist/codegen/fetch.d.ts +22 -0
  34. package/dist/codegen/fetch.d.ts.map +1 -1
  35. package/dist/codegen/lexicon-regen.d.ts +110 -0
  36. package/dist/codegen/lexicon-regen.d.ts.map +1 -0
  37. package/dist/codegen/pinned-upgrade.d.ts +153 -0
  38. package/dist/codegen/pinned-upgrade.d.ts.map +1 -0
  39. package/dist/codegen/rolling-upgrade.d.ts +138 -0
  40. package/dist/codegen/rolling-upgrade.d.ts.map +1 -0
  41. package/dist/codegen/surface-snapshot.d.ts +173 -0
  42. package/dist/codegen/surface-snapshot.d.ts.map +1 -0
  43. package/dist/codegen/version-bump.d.ts +21 -0
  44. package/dist/codegen/version-bump.d.ts.map +1 -0
  45. package/dist/components/auto-release.d.ts +93 -0
  46. package/dist/components/auto-release.d.ts.map +1 -0
  47. package/dist/components/builders.d.ts +37 -0
  48. package/dist/components/builders.d.ts.map +1 -0
  49. package/dist/components/capability-plugin-loader.d.ts +111 -0
  50. package/dist/components/capability-plugin-loader.d.ts.map +1 -0
  51. package/dist/components/capability-plugin-schema.d.ts +24 -0
  52. package/dist/components/capability-plugin-schema.d.ts.map +1 -0
  53. package/dist/components/capability-plugin.d.ts +85 -0
  54. package/dist/components/capability-plugin.d.ts.map +1 -0
  55. package/dist/components/capability.d.ts +89 -0
  56. package/dist/components/capability.d.ts.map +1 -0
  57. package/dist/components/cli-support.d.ts +204 -0
  58. package/dist/components/cli-support.d.ts.map +1 -0
  59. package/dist/components/component.d.ts +179 -0
  60. package/dist/components/component.d.ts.map +1 -0
  61. package/dist/components/config-defaults.d.ts +41 -0
  62. package/dist/components/config-defaults.d.ts.map +1 -0
  63. package/dist/components/discover.d.ts +60 -0
  64. package/dist/components/discover.d.ts.map +1 -0
  65. package/dist/components/driver-output.d.ts +20 -0
  66. package/dist/components/driver-output.d.ts.map +1 -0
  67. package/dist/components/driver.d.ts +209 -0
  68. package/dist/components/driver.d.ts.map +1 -0
  69. package/dist/components/index.d.ts +22 -0
  70. package/dist/components/index.d.ts.map +1 -0
  71. package/dist/components/manifest-persistence.d.ts +79 -0
  72. package/dist/components/manifest-persistence.d.ts.map +1 -0
  73. package/dist/components/pilots/alb-ecs.pilot.d.ts +27 -0
  74. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -0
  75. package/dist/components/pilots/dynamodb.pilot.d.ts +22 -0
  76. package/dist/components/pilots/dynamodb.pilot.d.ts.map +1 -0
  77. package/dist/components/pilots/jar-emr.pilot.d.ts +37 -0
  78. package/dist/components/pilots/jar-emr.pilot.d.ts.map +1 -0
  79. package/dist/components/pilots/lambda.pilot.d.ts +35 -0
  80. package/dist/components/pilots/lambda.pilot.d.ts.map +1 -0
  81. package/dist/components/pilots/neo4j-fanout.pilot.d.ts +17 -0
  82. package/dist/components/pilots/neo4j-fanout.pilot.d.ts.map +1 -0
  83. package/dist/components/pilots/project.d.ts +13 -0
  84. package/dist/components/pilots/project.d.ts.map +1 -0
  85. package/dist/components/presets/ecs-fargate.d.ts +59 -0
  86. package/dist/components/presets/ecs-fargate.d.ts.map +1 -0
  87. package/dist/components/presets/index.d.ts +29 -0
  88. package/dist/components/presets/index.d.ts.map +1 -0
  89. package/dist/components/presets/lambda.d.ts +35 -0
  90. package/dist/components/presets/lambda.d.ts.map +1 -0
  91. package/dist/components/presets/single-host-compose.d.ts +43 -0
  92. package/dist/components/presets/single-host-compose.d.ts.map +1 -0
  93. package/dist/components/registry.d.ts +29 -0
  94. package/dist/components/registry.d.ts.map +1 -0
  95. package/dist/components/starter-plugin.d.ts +51 -0
  96. package/dist/components/starter-plugin.d.ts.map +1 -0
  97. package/dist/components/temporal-codegen-loader.d.ts +27 -0
  98. package/dist/components/temporal-codegen-loader.d.ts.map +1 -0
  99. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts +35 -0
  100. package/dist/components/verbs/__tests__/mock-cloud-executor.d.ts.map +1 -0
  101. package/dist/components/verbs/__tests__/mock-process-runner.d.ts +45 -0
  102. package/dist/components/verbs/__tests__/mock-process-runner.d.ts.map +1 -0
  103. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts +33 -0
  104. package/dist/components/verbs/__tests__/mock-sbom-generator.d.ts.map +1 -0
  105. package/dist/components/verbs/bom-writer.d.ts +155 -0
  106. package/dist/components/verbs/bom-writer.d.ts.map +1 -0
  107. package/dist/components/verbs/build-archive.d.ts +205 -0
  108. package/dist/components/verbs/build-archive.d.ts.map +1 -0
  109. package/dist/components/verbs/build.d.ts +150 -0
  110. package/dist/components/verbs/build.d.ts.map +1 -0
  111. package/dist/components/verbs/cloud-executor.d.ts +88 -0
  112. package/dist/components/verbs/cloud-executor.d.ts.map +1 -0
  113. package/dist/components/verbs/component-bom.d.ts +103 -0
  114. package/dist/components/verbs/component-bom.d.ts.map +1 -0
  115. package/dist/components/verbs/index.d.ts +49 -0
  116. package/dist/components/verbs/index.d.ts.map +1 -0
  117. package/dist/components/verbs/license-policy.d.ts +56 -0
  118. package/dist/components/verbs/license-policy.d.ts.map +1 -0
  119. package/dist/components/verbs/lockfile-sbom-generator.d.ts +81 -0
  120. package/dist/components/verbs/lockfile-sbom-generator.d.ts.map +1 -0
  121. package/dist/components/verbs/process-runner.d.ts +64 -0
  122. package/dist/components/verbs/process-runner.d.ts.map +1 -0
  123. package/dist/components/verbs/reproducibility.d.ts +80 -0
  124. package/dist/components/verbs/reproducibility.d.ts.map +1 -0
  125. package/dist/components/verbs/sbom-generator.d.ts +157 -0
  126. package/dist/components/verbs/sbom-generator.d.ts.map +1 -0
  127. package/dist/components/verbs/sbom.d.ts +79 -0
  128. package/dist/components/verbs/sbom.d.ts.map +1 -0
  129. package/dist/components/verbs/shell.d.ts +35 -0
  130. package/dist/components/verbs/shell.d.ts.map +1 -0
  131. package/dist/components/verbs/sign.d.ts +222 -0
  132. package/dist/components/verbs/sign.d.ts.map +1 -0
  133. package/dist/components/verbs/stub.d.ts +18 -0
  134. package/dist/components/verbs/stub.d.ts.map +1 -0
  135. package/dist/components/verbs/tool-sbom-generator.d.ts +51 -0
  136. package/dist/components/verbs/tool-sbom-generator.d.ts.map +1 -0
  137. package/dist/components/verbs/verify.d.ts +106 -0
  138. package/dist/components/verbs/verify.d.ts.map +1 -0
  139. package/dist/components/verbs/vex.d.ts +65 -0
  140. package/dist/components/verbs/vex.d.ts.map +1 -0
  141. package/dist/components/verbs/vuln-gate.d.ts +91 -0
  142. package/dist/components/verbs/vuln-gate.d.ts.map +1 -0
  143. package/dist/components/verbs/vuln-scan.d.ts +116 -0
  144. package/dist/components/verbs/vuln-scan.d.ts.map +1 -0
  145. package/dist/components/verbs/wait-verify.d.ts +85 -0
  146. package/dist/components/verbs/wait-verify.d.ts.map +1 -0
  147. package/dist/config.d.ts +205 -0
  148. package/dist/config.d.ts.map +1 -1
  149. package/dist/index.d.ts +4 -0
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/lexicon.d.ts +78 -0
  152. package/dist/lexicon.d.ts.map +1 -1
  153. package/dist/lifecycle/build-ledger-store.d.ts +121 -0
  154. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -0
  155. package/dist/lifecycle/build-ledger.d.ts +225 -0
  156. package/dist/lifecycle/build-ledger.d.ts.map +1 -0
  157. package/dist/lifecycle/git.d.ts +84 -0
  158. package/dist/lifecycle/git.d.ts.map +1 -1
  159. package/dist/lifecycle/index.d.ts +5 -0
  160. package/dist/lifecycle/index.d.ts.map +1 -1
  161. package/dist/lifecycle/oras-referrer-lookup.d.ts +41 -0
  162. package/dist/lifecycle/oras-referrer-lookup.d.ts.map +1 -0
  163. package/dist/lifecycle/release-ledger.d.ts +122 -0
  164. package/dist/lifecycle/release-ledger.d.ts.map +1 -0
  165. package/dist/lifecycle/status.d.ts +150 -0
  166. package/dist/lifecycle/status.d.ts.map +1 -0
  167. package/dist/lint/component-checks.d.ts +95 -0
  168. package/dist/lint/component-checks.d.ts.map +1 -0
  169. package/dist/lint/engine.d.ts +23 -0
  170. package/dist/lint/engine.d.ts.map +1 -1
  171. package/dist/lint/presets/strict.json +8 -1
  172. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts +4 -0
  173. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.d.ts.map +1 -0
  174. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts +4 -0
  175. package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.d.ts.map +1 -0
  176. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts +4 -0
  177. package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.d.ts.map +1 -0
  178. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts +4 -0
  179. package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.d.ts.map +1 -0
  180. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts +4 -0
  181. package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.d.ts.map +1 -0
  182. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts +10 -0
  183. package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.d.ts.map +1 -0
  184. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts +3 -0
  185. package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.d.ts.map +1 -0
  186. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts +4 -0
  187. package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.d.ts.map +1 -0
  188. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts +4 -0
  189. package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.d.ts.map +1 -0
  190. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts +4 -0
  191. package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.d.ts.map +1 -0
  192. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts +4 -0
  193. package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.d.ts.map +1 -0
  194. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts +4 -0
  195. package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.d.ts.map +1 -0
  196. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +4 -0
  197. package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -0
  198. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +4 -0
  199. package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -0
  200. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts +4 -0
  201. package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.d.ts.map +1 -0
  202. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts +4 -0
  203. package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.d.ts.map +1 -0
  204. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts +4 -0
  205. package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.d.ts.map +1 -0
  206. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts +4 -0
  207. package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.d.ts.map +1 -0
  208. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts +4 -0
  209. package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.d.ts.map +1 -0
  210. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts +4 -0
  211. package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.d.ts.map +1 -0
  212. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts +3 -0
  213. package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.d.ts.map +1 -0
  214. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts +4 -0
  215. package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.d.ts.map +1 -0
  216. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts +20 -0
  217. package/dist/lint/rules/comp/comp001-publishes-never-applies.d.ts.map +1 -0
  218. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts +28 -0
  219. package/dist/lint/rules/comp/comp002-dangling-wiring-ref.d.ts.map +1 -0
  220. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +39 -0
  221. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -0
  222. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +37 -0
  223. package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +1 -0
  224. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts +43 -0
  225. package/dist/lint/rules/comp/comp005-capability-kind-is-noun.d.ts.map +1 -0
  226. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts +22 -0
  227. package/dist/lint/rules/comp/comp006-shell-needs-reason.d.ts.map +1 -0
  228. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts +33 -0
  229. package/dist/lint/rules/comp/comp007-composition-sprawl.d.ts.map +1 -0
  230. package/dist/lint/rules/comp/index.d.ts +18 -0
  231. package/dist/lint/rules/comp/index.d.ts.map +1 -0
  232. package/dist/lint/rules/comp/support.d.ts +71 -0
  233. package/dist/lint/rules/comp/support.d.ts.map +1 -0
  234. package/dist/lsp/lexicon-providers.d.ts.map +1 -1
  235. package/dist/op/activity-registry.d.ts +11 -6
  236. package/dist/op/activity-registry.d.ts.map +1 -1
  237. package/dist/op/activity-runtime.d.ts +24 -0
  238. package/dist/op/activity-runtime.d.ts.map +1 -0
  239. package/dist/op/builders.d.ts +56 -0
  240. package/dist/op/builders.d.ts.map +1 -1
  241. package/dist/op/index.d.ts +2 -1
  242. package/dist/op/index.d.ts.map +1 -1
  243. package/dist/ownership.d.ts +20 -14
  244. package/dist/ownership.d.ts.map +1 -1
  245. package/package.json +14 -1
  246. package/src/audit/catalog.test.ts +74 -22
  247. package/src/audit/catalog.ts +74 -471
  248. package/src/audit/proof.ts +4 -2
  249. package/src/audit/report-html.test.ts +14 -7
  250. package/src/audit/report-model.ts +20 -9
  251. package/src/audit/report.test.ts +36 -13
  252. package/src/audit/report.ts +2 -0
  253. package/src/audit/rules-doc.test.ts +8 -6
  254. package/src/audit/rules-doc.ts +13 -5
  255. package/src/cli/commands/audit.ts +23 -18
  256. package/src/cli/commands/component-lint.test.ts +158 -0
  257. package/src/cli/commands/doctor.test.ts +116 -2
  258. package/src/cli/commands/doctor.ts +46 -0
  259. package/src/cli/commands/lexicon-rolling-upgrade.ts +198 -0
  260. package/src/cli/commands/lexicon-surface-diff.test.ts +104 -0
  261. package/src/cli/commands/lexicon-surface-diff.ts +185 -0
  262. package/src/cli/commands/lint.ts +142 -1
  263. package/src/cli/commands/pinned-upgrade.ts +204 -0
  264. package/src/cli/handlers/build.ts +58 -1
  265. package/src/cli/handlers/components.test.ts +504 -0
  266. package/src/cli/handlers/components.ts +404 -0
  267. package/src/cli/handlers/dev.ts +60 -1
  268. package/src/cli/handlers/graph.ts +47 -2
  269. package/src/cli/handlers/misc.ts +45 -1
  270. package/src/cli/handlers/run.test.ts +967 -3
  271. package/src/cli/handlers/run.ts +618 -11
  272. package/src/cli/main.test.ts +66 -0
  273. package/src/cli/main.ts +105 -2
  274. package/src/cli/registry.ts +35 -0
  275. package/src/codegen/fetch.test.ts +84 -3
  276. package/src/codegen/fetch.ts +76 -2
  277. package/src/codegen/lexicon-regen.test.ts +298 -0
  278. package/src/codegen/lexicon-regen.ts +545 -0
  279. package/src/codegen/pinned-upgrade.test.ts +399 -0
  280. package/src/codegen/pinned-upgrade.ts +423 -0
  281. package/src/codegen/rolling-upgrade.test.ts +333 -0
  282. package/src/codegen/rolling-upgrade.ts +320 -0
  283. package/src/codegen/surface-snapshot.test.ts +461 -0
  284. package/src/codegen/surface-snapshot.ts +546 -0
  285. package/src/codegen/version-bump.test.ts +47 -0
  286. package/src/codegen/version-bump.ts +39 -0
  287. package/src/components/README.md +130 -0
  288. package/src/components/SPRAWL-VALIDATION.md +181 -0
  289. package/src/components/__fixtures__/alb-ecs-service.json +51 -0
  290. package/src/components/__fixtures__/dynamodb-infra.json +32 -0
  291. package/src/components/__fixtures__/emr-job-consumer.json +26 -0
  292. package/src/components/__fixtures__/jar-lib-producer.json +16 -0
  293. package/src/components/__fixtures__/lambda-image-processor.json +28 -0
  294. package/src/components/__fixtures__/neo4j-fanout.json +34 -0
  295. package/src/components/__fixtures__/single-host-compose.json +29 -0
  296. package/src/components/auto-release.test.ts +217 -0
  297. package/src/components/auto-release.ts +216 -0
  298. package/src/components/builders.test.ts +45 -0
  299. package/src/components/builders.ts +71 -0
  300. package/src/components/capability-plugin-loader.ts +218 -0
  301. package/src/components/capability-plugin-schema.ts +56 -0
  302. package/src/components/capability-plugin.test.ts +235 -0
  303. package/src/components/capability-plugin.ts +108 -0
  304. package/src/components/capability.ts +117 -0
  305. package/src/components/cli-support.test.ts +579 -0
  306. package/src/components/cli-support.ts +481 -0
  307. package/src/components/component-schema.test.ts +265 -0
  308. package/src/components/component.schema.json +235 -0
  309. package/src/components/component.test.ts +251 -0
  310. package/src/components/component.ts +255 -0
  311. package/src/components/config-defaults.test.ts +263 -0
  312. package/src/components/config-defaults.ts +145 -0
  313. package/src/components/discover.test.ts +352 -0
  314. package/src/components/discover.ts +167 -0
  315. package/src/components/driver-output.ts +71 -0
  316. package/src/components/driver.test.ts +638 -0
  317. package/src/components/driver.ts +690 -0
  318. package/src/components/index.ts +113 -0
  319. package/src/components/manifest-persistence.test.ts +152 -0
  320. package/src/components/manifest-persistence.ts +164 -0
  321. package/src/components/pilots/README.md +33 -0
  322. package/src/components/pilots/alb-ecs.pilot.ts +63 -0
  323. package/src/components/pilots/dynamodb.pilot.ts +59 -0
  324. package/src/components/pilots/jar-emr.pilot.ts +69 -0
  325. package/src/components/pilots/lambda.pilot.ts +55 -0
  326. package/src/components/pilots/neo4j-fanout.pilot.ts +92 -0
  327. package/src/components/pilots/pilots-lint-clean.test.ts +78 -0
  328. package/src/components/pilots/pilots.test.ts +126 -0
  329. package/src/components/pilots/project.ts +13 -0
  330. package/src/components/presets/comp007-reduction.test.ts +122 -0
  331. package/src/components/presets/ecs-fargate.test.ts +84 -0
  332. package/src/components/presets/ecs-fargate.ts +103 -0
  333. package/src/components/presets/index.ts +32 -0
  334. package/src/components/presets/lambda.test.ts +35 -0
  335. package/src/components/presets/lambda.ts +53 -0
  336. package/src/components/presets/single-host-compose.test.ts +65 -0
  337. package/src/components/presets/single-host-compose.ts +64 -0
  338. package/src/components/registry.test.ts +112 -0
  339. package/src/components/registry.ts +37 -0
  340. package/src/components/starter-plugin.ts +105 -0
  341. package/src/components/temporal-codegen-loader.ts +41 -0
  342. package/src/components/verbs/__fixtures__/package-lock.json +45 -0
  343. package/src/components/verbs/__fixtures__/pom.xml +37 -0
  344. package/src/components/verbs/__fixtures__/schemas/cyclonedx-1.5.schema.json +3800 -0
  345. package/src/components/verbs/__fixtures__/schemas/cyclonedx-spdx-license.schema.json +621 -0
  346. package/src/components/verbs/__fixtures__/schemas/jsf-0.82.schema.json +240 -0
  347. package/src/components/verbs/__fixtures__/schemas/spdx-2.3.schema.json +740 -0
  348. package/src/components/verbs/__tests__/mock-cloud-executor.ts +102 -0
  349. package/src/components/verbs/__tests__/mock-process-runner.ts +79 -0
  350. package/src/components/verbs/__tests__/mock-sbom-generator.ts +85 -0
  351. package/src/components/verbs/bom-writer.test.ts +331 -0
  352. package/src/components/verbs/bom-writer.ts +386 -0
  353. package/src/components/verbs/build-archive.test.ts +251 -0
  354. package/src/components/verbs/build-archive.ts +296 -0
  355. package/src/components/verbs/build.test.ts +222 -0
  356. package/src/components/verbs/build.ts +252 -0
  357. package/src/components/verbs/cloud-executor.ts +181 -0
  358. package/src/components/verbs/component-bom.test.ts +219 -0
  359. package/src/components/verbs/component-bom.ts +189 -0
  360. package/src/components/verbs/index.ts +49 -0
  361. package/src/components/verbs/license-policy.ts +115 -0
  362. package/src/components/verbs/lockfile-sbom-generator.test.ts +195 -0
  363. package/src/components/verbs/lockfile-sbom-generator.ts +236 -0
  364. package/src/components/verbs/process-runner.test.ts +79 -0
  365. package/src/components/verbs/process-runner.ts +113 -0
  366. package/src/components/verbs/reproducibility.test.ts +24 -0
  367. package/src/components/verbs/reproducibility.ts +100 -0
  368. package/src/components/verbs/sbom-generator.test.ts +96 -0
  369. package/src/components/verbs/sbom-generator.ts +209 -0
  370. package/src/components/verbs/sbom.test.ts +184 -0
  371. package/src/components/verbs/sbom.ts +152 -0
  372. package/src/components/verbs/shell.test.ts +36 -0
  373. package/src/components/verbs/shell.ts +51 -0
  374. package/src/components/verbs/sign.test.ts +210 -0
  375. package/src/components/verbs/sign.ts +350 -0
  376. package/src/components/verbs/stub.ts +34 -0
  377. package/src/components/verbs/tool-sbom-generator.test.ts +194 -0
  378. package/src/components/verbs/tool-sbom-generator.ts +192 -0
  379. package/src/components/verbs/verify.test.ts +159 -0
  380. package/src/components/verbs/verify.ts +179 -0
  381. package/src/components/verbs/vex.ts +182 -0
  382. package/src/components/verbs/vuln-gate.test.ts +201 -0
  383. package/src/components/verbs/vuln-gate.ts +170 -0
  384. package/src/components/verbs/vuln-scan.test.ts +145 -0
  385. package/src/components/verbs/vuln-scan.ts +266 -0
  386. package/src/components/verbs/wait-verify.test.ts +111 -0
  387. package/src/components/verbs/wait-verify.ts +171 -0
  388. package/src/config.test.ts +74 -1
  389. package/src/config.ts +219 -0
  390. package/src/index.ts +32 -0
  391. package/src/lexicon.ts +88 -0
  392. package/src/lifecycle/build-ledger-store.test.ts +217 -0
  393. package/src/lifecycle/build-ledger-store.ts +165 -0
  394. package/src/lifecycle/build-ledger.test.ts +349 -0
  395. package/src/lifecycle/build-ledger.ts +305 -0
  396. package/src/lifecycle/git.test.ts +118 -0
  397. package/src/lifecycle/git.ts +149 -14
  398. package/src/lifecycle/index.ts +5 -0
  399. package/src/lifecycle/oras-referrer-lookup.test.ts +116 -0
  400. package/src/lifecycle/oras-referrer-lookup.ts +110 -0
  401. package/src/lifecycle/release-ledger.test.ts +209 -0
  402. package/src/lifecycle/release-ledger.ts +185 -0
  403. package/src/lifecycle/status.test.ts +330 -0
  404. package/src/lifecycle/status.ts +278 -0
  405. package/src/lint/component-checks.ts +148 -0
  406. package/src/lint/config.test.ts +21 -0
  407. package/src/lint/engine.ts +11 -2
  408. package/src/lint/presets/relaxed.json +8 -1
  409. package/src/lint/presets/strict.json +8 -1
  410. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.ts +9 -0
  411. package/src/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.ts +9 -0
  412. package/src/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.ts +11 -0
  413. package/src/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.ts +13 -0
  414. package/src/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.ts +11 -0
  415. package/src/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.ts +27 -0
  416. package/src/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.ts +10 -0
  417. package/src/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.ts +23 -0
  418. package/src/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.ts +10 -0
  419. package/src/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.ts +19 -0
  420. package/src/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.ts +10 -0
  421. package/src/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.ts +20 -0
  422. package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +23 -0
  423. package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +10 -0
  424. package/src/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.ts +14 -0
  425. package/src/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.ts +18 -0
  426. package/src/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.ts +10 -0
  427. package/src/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.ts +14 -0
  428. package/src/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.ts +13 -0
  429. package/src/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.ts +13 -0
  430. package/src/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.ts +12 -0
  431. package/src/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.ts +18 -0
  432. package/src/lint/rules/comp/comp.test.ts +378 -0
  433. package/src/lint/rules/comp/comp001-publishes-never-applies.ts +78 -0
  434. package/src/lint/rules/comp/comp002-dangling-wiring-ref.ts +94 -0
  435. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +115 -0
  436. package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +66 -0
  437. package/src/lint/rules/comp/comp005-capability-kind-is-noun.ts +113 -0
  438. package/src/lint/rules/comp/comp006-shell-needs-reason.ts +55 -0
  439. package/src/lint/rules/comp/comp007-composition-sprawl.ts +71 -0
  440. package/src/lint/rules/comp/index.ts +37 -0
  441. package/src/lint/rules/comp/support.ts +173 -0
  442. package/src/lsp/lexicon-providers.test.ts +55 -0
  443. package/src/lsp/lexicon-providers.ts +13 -3
  444. package/src/op/activity-registry.test.ts +38 -0
  445. package/src/op/activity-registry.ts +31 -12
  446. package/src/op/activity-runtime.ts +73 -0
  447. package/src/op/builders.ts +92 -0
  448. package/src/op/index.ts +3 -1
  449. package/src/ownership.test.ts +24 -26
  450. package/src/ownership.ts +26 -38
@@ -0,0 +1,546 @@
1
+ /**
2
+ * Lexicon API surface snapshot and diff.
3
+ *
4
+ * Extracts a stable, serializable representation of a lexicon's public API
5
+ * surface from the generated lexicon JSON. Diffs a fresh snapshot against a
6
+ * committed baseline and classifies each change as additive or breaking.
7
+ *
8
+ * The surface is derived from the lexicon registry JSON that every lexicon's
9
+ * `generate` step writes to `src/generated/<name>.json`. Resource and
10
+ * property-type names, together with their structural metadata (attrs, props,
11
+ * kind), form the baseline. The generated .d.ts is not used for diffing
12
+ * because: (a) it is not self-describing without parsing TypeScript, and
13
+ * (b) the registry JSON already encodes everything a consumer needs.
14
+ */
15
+
16
+ // ── Surface types ───────────────────────────────────────────────────
17
+
18
+ /**
19
+ * A single entry in the surface snapshot.
20
+ * "resource" entries carry attrs and props; "property" entries are lightweight.
21
+ */
22
+ export interface SurfaceEntry {
23
+ kind: "resource" | "property";
24
+ /** The cloud-provider resource type string (e.g. "AWS::S3::Bucket"). */
25
+ resourceType: string;
26
+ /** Readonly attribute names (resource entries only). */
27
+ attrs?: string[];
28
+ /**
29
+ * Property names with their required flag. Stored as
30
+ * `name:required` strings (e.g. "BucketName:false", "Tags:false").
31
+ * Sorting is stable so the snapshot is deterministic.
32
+ */
33
+ props?: string[];
34
+ /** Names that are create-only / immutable after creation. */
35
+ createOnly?: string[];
36
+ /**
37
+ * Whether the resource supports tagging.
38
+ * Present when known; absent means not known or not applicable.
39
+ */
40
+ taggable?: boolean;
41
+ }
42
+
43
+ /**
44
+ * The complete surface snapshot for one lexicon.
45
+ */
46
+ export interface SurfaceSnapshot {
47
+ /**
48
+ * Schema version for forward-compatibility. Bump when the shape changes
49
+ * in a way that makes old snapshots unreadable by newer tooling.
50
+ */
51
+ schemaVersion: 1;
52
+ /** When this snapshot was generated (ISO 8601 UTC). */
53
+ generatedAt: string;
54
+ /**
55
+ * Per-entry map keyed by the TS export name (e.g. "Bucket",
56
+ * "Bucket_Tag"). Sorted alphabetically for stable diffs.
57
+ */
58
+ entries: Record<string, SurfaceEntry>;
59
+ }
60
+
61
+ // ── Delta types ─────────────────────────────────────────────────────
62
+
63
+ export type ChangeSeverity = "additive" | "breaking" | "none";
64
+
65
+ export interface AddedEntry {
66
+ name: string;
67
+ entry: SurfaceEntry;
68
+ }
69
+
70
+ export interface RemovedEntry {
71
+ name: string;
72
+ entry: SurfaceEntry;
73
+ }
74
+
75
+ export interface ChangedEntry {
76
+ name: string;
77
+ /** New resourceType (breaking). */
78
+ resourceTypeChanged?: { before: string; after: string };
79
+ /** kind changed from resource to property or vice-versa (breaking). */
80
+ kindChanged?: { before: string; after: string };
81
+ /** Props that were removed (breaking). */
82
+ removedProps?: string[];
83
+ /** Props that switched from optional to required (breaking). */
84
+ nowRequired?: string[];
85
+ /** Attrs that were removed (breaking). */
86
+ removedAttrs?: string[];
87
+ /** Props that were newly added. */
88
+ addedProps?: string[];
89
+ /** Props that switched from required to optional (additive). */
90
+ nowOptional?: string[];
91
+ /** Attrs that were newly added. */
92
+ addedAttrs?: string[];
93
+ /** createOnly set changed. */
94
+ createOnlyChanged?: { before: string[]; after: string[] };
95
+ /** taggable flag changed. */
96
+ taggableChanged?: { before?: boolean; after?: boolean };
97
+ }
98
+
99
+ export interface SurfaceDelta {
100
+ added: AddedEntry[];
101
+ changed: ChangedEntry[];
102
+ removed: RemovedEntry[];
103
+ /**
104
+ * Rolled-up severity. "none" means no surface changes at all.
105
+ * "additive" means only new resources / new optional props / new attrs.
106
+ * "breaking" means any removal or change that could break existing consumers.
107
+ */
108
+ severity: ChangeSeverity;
109
+ }
110
+
111
+ // ── LexiconEntry ── raw shape from lexicon JSON ──────────────────────
112
+
113
+ interface LexiconEntry {
114
+ kind?: "resource" | "property";
115
+ resourceType?: string;
116
+ attrs?: Record<string, string>;
117
+ createOnly?: string[];
118
+ tagging?: { taggable?: boolean };
119
+ }
120
+
121
+ // ── Extraction ───────────────────────────────────────────────────────
122
+
123
+ /**
124
+ * Extract a surface snapshot from the lexicon JSON and the generated index.d.ts.
125
+ *
126
+ * The lexicon JSON contains the resource/property registry (names, kinds,
127
+ * attrs, createOnly, tagging). The .d.ts provides per-prop names and their
128
+ * required flags for resource constructor shapes.
129
+ *
130
+ * @param lexiconJSON Contents of `src/generated/<name>.json`
131
+ * @param typesDTS Contents of `src/generated/index.d.ts`
132
+ */
133
+ export function extractSurface(lexiconJSON: string, typesDTS: string): SurfaceSnapshot {
134
+ const registry = JSON.parse(lexiconJSON) as Record<string, LexiconEntry>;
135
+
136
+ // Build prop map from .d.ts
137
+ const propsMap = extractPropsFromDts(typesDTS);
138
+
139
+ const entries: Record<string, SurfaceEntry> = {};
140
+
141
+ for (const [name, raw] of Object.entries(registry)) {
142
+ const kind = raw.kind ?? "property";
143
+ const resourceType = raw.resourceType ?? "";
144
+
145
+ const entry: SurfaceEntry = { kind, resourceType };
146
+
147
+ if (kind === "resource") {
148
+ const attrs = raw.attrs ? Object.keys(raw.attrs).sort() : [];
149
+ if (attrs.length > 0) entry.attrs = attrs;
150
+
151
+ // Props from .d.ts
152
+ const props = propsMap.get(name);
153
+ if (props && props.length > 0) entry.props = props;
154
+
155
+ const createOnly = raw.createOnly ? [...raw.createOnly].sort() : [];
156
+ if (createOnly.length > 0) entry.createOnly = createOnly;
157
+
158
+ if (raw.tagging?.taggable !== undefined) {
159
+ entry.taggable = raw.tagging.taggable;
160
+ }
161
+ }
162
+
163
+ entries[name] = entry;
164
+ }
165
+
166
+ // Sort keys for stable output
167
+ const sorted: Record<string, SurfaceEntry> = {};
168
+ for (const key of Object.keys(entries).sort()) {
169
+ sorted[key] = entries[key];
170
+ }
171
+
172
+ return {
173
+ schemaVersion: 1,
174
+ generatedAt: new Date().toISOString(),
175
+ entries: sorted,
176
+ };
177
+ }
178
+
179
+ /**
180
+ * Lightweight extractor: pull constructor prop names and required flags
181
+ * from a `.d.ts` string.
182
+ *
183
+ * Handles the pattern generated by writeConstructor:
184
+ * ```
185
+ * export declare class Bucket {
186
+ * constructor(props: {
187
+ * BucketName?: string;
188
+ * Tags: Bucket_Tag[];
189
+ * }, attributes?: CFResourceAttributes);
190
+ * }
191
+ * ```
192
+ *
193
+ * Returns a Map<className, ["PropName:required", ...]>
194
+ * where each entry is sorted alphabetically.
195
+ */
196
+ export function extractPropsFromDts(dts: string): Map<string, string[]> {
197
+ const map = new Map<string, string[]>();
198
+ const lines = dts.split("\n");
199
+
200
+ let className: string | null = null;
201
+ let inConstructorProps = false;
202
+ let braceDepth = 0;
203
+ const currentProps: string[] = [];
204
+ // Track class-body brace depth separately
205
+ let classBraceDepth = 0;
206
+
207
+ for (const line of lines) {
208
+ const trimmed = line.trim();
209
+
210
+ // Start of a class
211
+ const classMatch = /^export declare class (\w+)/.exec(trimmed);
212
+ if (classMatch) {
213
+ className = classMatch[1];
214
+ inConstructorProps = false;
215
+ braceDepth = 0;
216
+ classBraceDepth = 1; // opening { is on this line
217
+ currentProps.length = 0;
218
+ continue;
219
+ }
220
+
221
+ if (!className) continue;
222
+
223
+ // Track class-body braces when not in constructor props
224
+ if (!inConstructorProps) {
225
+ // End of class block (classBraceDepth back to 0)
226
+ let delta = 0;
227
+ for (const ch of trimmed) {
228
+ if (ch === "{") delta++;
229
+ if (ch === "}") delta--;
230
+ }
231
+ classBraceDepth += delta;
232
+
233
+ if (classBraceDepth <= 0) {
234
+ // Leaving class body — record and reset
235
+ if (currentProps.length > 0) {
236
+ map.set(className, [...currentProps].sort());
237
+ currentProps.length = 0;
238
+ }
239
+ className = null;
240
+ classBraceDepth = 0;
241
+ continue;
242
+ }
243
+
244
+ // Constructor start
245
+ if (trimmed.startsWith("constructor(props: {")) {
246
+ inConstructorProps = true;
247
+ braceDepth = 1;
248
+ currentProps.length = 0;
249
+ continue;
250
+ }
251
+ // Constructor with empty props object on one line (no sub-braces needed)
252
+ // constructor(props: Record<string, unknown>) — skip
253
+ continue;
254
+ }
255
+
256
+ // Inside constructor props block
257
+
258
+ // Track brace depth
259
+ let delta = 0;
260
+ for (const ch of trimmed) {
261
+ if (ch === "{") delta++;
262
+ if (ch === "}") delta--;
263
+ }
264
+ braceDepth += delta;
265
+
266
+ // End of constructor props block
267
+ if (braceDepth <= 0) {
268
+ inConstructorProps = false;
269
+ braceDepth = 0;
270
+ // Record the props collected so far
271
+ if (!map.has(className) && currentProps.length > 0) {
272
+ map.set(className, [...currentProps].sort());
273
+ currentProps.length = 0;
274
+ }
275
+ continue;
276
+ }
277
+
278
+ // Skip comments
279
+ if (trimmed.startsWith("/**") || trimmed.startsWith("*") || trimmed.startsWith("//")) continue;
280
+
281
+ // Match a prop: `PropName?: type;` or `PropName: type;`
282
+ // Prop names may be quoted for non-identifier keys
283
+ const propMatch = /^(?:"([^"]+)"|(\w+))(\??):/.exec(trimmed);
284
+ if (propMatch) {
285
+ const propName = propMatch[1] ?? propMatch[2];
286
+ const optional = propMatch[3] === "?";
287
+ // Encode as "name:required" — "true" means required
288
+ currentProps.push(`${propName}:${!optional}`);
289
+ }
290
+ }
291
+
292
+ return map;
293
+ }
294
+
295
+ // ── Diff ─────────────────────────────────────────────────────────────
296
+
297
+ /**
298
+ * Diff a fresh snapshot against a committed baseline.
299
+ *
300
+ * Classification rules:
301
+ * - Added entry → additive
302
+ * - Removed entry → breaking
303
+ * - Changed entry:
304
+ * - resourceType changed → breaking
305
+ * - kind changed → breaking
306
+ * - prop removed → breaking
307
+ * - prop now required (was optional) → breaking
308
+ * - attr removed → breaking
309
+ * - createOnly changed → breaking (changes immutability contract)
310
+ * - taggable: false→undefined or true→false → breaking
311
+ * - prop added (optional) → additive
312
+ * - prop now optional (was required) → additive
313
+ * - attr added → additive
314
+ * - taggable: false→true or undefined→true → additive
315
+ */
316
+ export function diffSurface(baseline: SurfaceSnapshot, fresh: SurfaceSnapshot): SurfaceDelta {
317
+ const added: AddedEntry[] = [];
318
+ const changed: ChangedEntry[] = [];
319
+ const removed: RemovedEntry[] = [];
320
+
321
+ const baseNames = new Set(Object.keys(baseline.entries));
322
+ const freshNames = new Set(Object.keys(fresh.entries));
323
+
324
+ // Added
325
+ for (const name of freshNames) {
326
+ if (!baseNames.has(name)) {
327
+ added.push({ name, entry: fresh.entries[name] });
328
+ }
329
+ }
330
+
331
+ // Removed
332
+ for (const name of baseNames) {
333
+ if (!freshNames.has(name)) {
334
+ removed.push({ name, entry: baseline.entries[name] });
335
+ }
336
+ }
337
+
338
+ // Changed
339
+ for (const name of baseNames) {
340
+ if (!freshNames.has(name)) continue;
341
+
342
+ const before = baseline.entries[name];
343
+ const after = fresh.entries[name];
344
+
345
+ const change: ChangedEntry = { name };
346
+ let hasChange = false;
347
+
348
+ if (before.resourceType !== after.resourceType) {
349
+ change.resourceTypeChanged = { before: before.resourceType, after: after.resourceType };
350
+ hasChange = true;
351
+ }
352
+
353
+ if (before.kind !== after.kind) {
354
+ change.kindChanged = { before: before.kind, after: after.kind };
355
+ hasChange = true;
356
+ }
357
+
358
+ // Props diff (only meaningful for resource entries)
359
+ const beforeProps = new Map(
360
+ (before.props ?? []).map((p) => {
361
+ const [nm, req] = splitProp(p);
362
+ return [nm, req === "true"];
363
+ }),
364
+ );
365
+ const afterProps = new Map(
366
+ (after.props ?? []).map((p) => {
367
+ const [nm, req] = splitProp(p);
368
+ return [nm, req === "true"];
369
+ }),
370
+ );
371
+
372
+ const removedProps = [...beforeProps.keys()].filter((k) => !afterProps.has(k));
373
+ const addedProps = [...afterProps.keys()].filter((k) => !beforeProps.has(k));
374
+ const nowRequired = [...beforeProps.keys()].filter(
375
+ (k) => afterProps.has(k) && !beforeProps.get(k) && afterProps.get(k),
376
+ );
377
+ const nowOptional = [...beforeProps.keys()].filter(
378
+ (k) => afterProps.has(k) && beforeProps.get(k) && !afterProps.get(k),
379
+ );
380
+
381
+ if (removedProps.length > 0) { change.removedProps = removedProps.sort(); hasChange = true; }
382
+ if (addedProps.length > 0) { change.addedProps = addedProps.sort(); hasChange = true; }
383
+ if (nowRequired.length > 0) { change.nowRequired = nowRequired.sort(); hasChange = true; }
384
+ if (nowOptional.length > 0) { change.nowOptional = nowOptional.sort(); hasChange = true; }
385
+
386
+ // Attrs diff
387
+ const beforeAttrs = new Set(before.attrs ?? []);
388
+ const afterAttrs = new Set(after.attrs ?? []);
389
+ const removedAttrs = [...beforeAttrs].filter((a) => !afterAttrs.has(a));
390
+ const addedAttrs = [...afterAttrs].filter((a) => !beforeAttrs.has(a));
391
+ if (removedAttrs.length > 0) { change.removedAttrs = removedAttrs.sort(); hasChange = true; }
392
+ if (addedAttrs.length > 0) { change.addedAttrs = addedAttrs.sort(); hasChange = true; }
393
+
394
+ // createOnly diff
395
+ const beforeCO = JSON.stringify((before.createOnly ?? []).sort());
396
+ const afterCO = JSON.stringify((after.createOnly ?? []).sort());
397
+ if (beforeCO !== afterCO) {
398
+ change.createOnlyChanged = {
399
+ before: before.createOnly ?? [],
400
+ after: after.createOnly ?? [],
401
+ };
402
+ hasChange = true;
403
+ }
404
+
405
+ // taggable diff
406
+ if (before.taggable !== after.taggable) {
407
+ change.taggableChanged = { before: before.taggable, after: after.taggable };
408
+ hasChange = true;
409
+ }
410
+
411
+ if (hasChange) changed.push(change);
412
+ }
413
+
414
+ // Severity
415
+ let severity: ChangeSeverity = "none";
416
+
417
+ if (added.length > 0) {
418
+ severity = "additive";
419
+ }
420
+
421
+ // Additive-only changes in the changed[] set
422
+ const hasAdditiveChanges = changed.some((c) =>
423
+ (c.addedProps?.length ?? 0) > 0 ||
424
+ (c.nowOptional?.length ?? 0) > 0 ||
425
+ (c.addedAttrs?.length ?? 0) > 0 ||
426
+ // gaining tagging is additive
427
+ (c.taggableChanged !== undefined && c.taggableChanged.after === true && c.taggableChanged.before !== true),
428
+ );
429
+
430
+ if (hasAdditiveChanges && severity === "none") {
431
+ severity = "additive";
432
+ }
433
+
434
+ const hasBreaking =
435
+ removed.length > 0 ||
436
+ changed.some(
437
+ (c) =>
438
+ c.resourceTypeChanged !== undefined ||
439
+ c.kindChanged !== undefined ||
440
+ (c.removedProps?.length ?? 0) > 0 ||
441
+ (c.nowRequired?.length ?? 0) > 0 ||
442
+ (c.removedAttrs?.length ?? 0) > 0 ||
443
+ (c.createOnlyChanged !== undefined) ||
444
+ // losing taggable is breaking
445
+ (c.taggableChanged !== undefined && c.taggableChanged.before === true && c.taggableChanged.after !== true),
446
+ );
447
+
448
+ if (hasBreaking) severity = "breaking";
449
+
450
+ return { added, changed, removed, severity };
451
+ }
452
+
453
+ // ── Serialization ────────────────────────────────────────────────────
454
+
455
+ /**
456
+ * Serialize a snapshot to stable JSON. Suitable for writing to
457
+ * `surface.snapshot.json` at the lexicon root.
458
+ */
459
+ export function serializeSnapshot(snapshot: SurfaceSnapshot): string {
460
+ return JSON.stringify(snapshot, null, 2) + "\n";
461
+ }
462
+
463
+ /**
464
+ * Parse a snapshot from JSON.
465
+ */
466
+ export function parseSnapshot(json: string): SurfaceSnapshot {
467
+ return JSON.parse(json) as SurfaceSnapshot;
468
+ }
469
+
470
+ // ── Human-readable output ────────────────────────────────────────────
471
+
472
+ /**
473
+ * Render a surface delta as human-readable text.
474
+ */
475
+ export function formatDelta(delta: SurfaceDelta): string {
476
+ const lines: string[] = [];
477
+
478
+ if (delta.added.length > 0) {
479
+ lines.push(`Added (${delta.added.length}):`);
480
+ for (const e of delta.added) {
481
+ lines.push(` + ${e.name} [${e.entry.kind}] (${e.entry.resourceType})`);
482
+ }
483
+ }
484
+
485
+ if (delta.removed.length > 0) {
486
+ lines.push(`Removed (${delta.removed.length}):`);
487
+ for (const e of delta.removed) {
488
+ lines.push(` - ${e.name} [${e.entry.kind}] (${e.entry.resourceType})`);
489
+ }
490
+ }
491
+
492
+ if (delta.changed.length > 0) {
493
+ lines.push(`Changed (${delta.changed.length}):`);
494
+ for (const c of delta.changed) {
495
+ lines.push(` ~ ${c.name}`);
496
+ if (c.resourceTypeChanged) {
497
+ lines.push(` resourceType: ${c.resourceTypeChanged.before} -> ${c.resourceTypeChanged.after}`);
498
+ }
499
+ if (c.kindChanged) {
500
+ lines.push(` kind: ${c.kindChanged.before} -> ${c.kindChanged.after}`);
501
+ }
502
+ if (c.removedProps?.length) {
503
+ lines.push(` removed props: ${c.removedProps.join(", ")}`);
504
+ }
505
+ if (c.nowRequired?.length) {
506
+ lines.push(` now required: ${c.nowRequired.join(", ")}`);
507
+ }
508
+ if (c.addedProps?.length) {
509
+ lines.push(` added props: ${c.addedProps.join(", ")}`);
510
+ }
511
+ if (c.nowOptional?.length) {
512
+ lines.push(` now optional: ${c.nowOptional.join(", ")}`);
513
+ }
514
+ if (c.removedAttrs?.length) {
515
+ lines.push(` removed attrs: ${c.removedAttrs.join(", ")}`);
516
+ }
517
+ if (c.addedAttrs?.length) {
518
+ lines.push(` added attrs: ${c.addedAttrs.join(", ")}`);
519
+ }
520
+ if (c.createOnlyChanged) {
521
+ const before = c.createOnlyChanged.before.join(", ") || "(none)";
522
+ const after = c.createOnlyChanged.after.join(", ") || "(none)";
523
+ lines.push(` createOnly: [${before}] -> [${after}]`);
524
+ }
525
+ if (c.taggableChanged) {
526
+ lines.push(` taggable: ${c.taggableChanged.before ?? "(unset)"} -> ${c.taggableChanged.after ?? "(unset)"}`);
527
+ }
528
+ }
529
+ }
530
+
531
+ if (lines.length === 0) {
532
+ lines.push("No surface changes.");
533
+ }
534
+
535
+ lines.push("");
536
+ lines.push(`Severity: ${delta.severity}`);
537
+
538
+ return lines.join("\n");
539
+ }
540
+
541
+ // ── Helpers ──────────────────────────────────────────────────────────
542
+
543
+ function splitProp(encoded: string): [string, string] {
544
+ const idx = encoded.lastIndexOf(":");
545
+ return [encoded.slice(0, idx), encoded.slice(idx + 1)];
546
+ }
@@ -0,0 +1,47 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { mkdtempSync, writeFileSync, readFileSync, rmSync } from "fs";
3
+ import { tmpdir } from "os";
4
+ import { join } from "path";
5
+ import { bumpForSeverity, bumpPackageJsonVersion } from "./version-bump";
6
+
7
+ describe("bumpForSeverity", () => {
8
+ test("pre-1.0: additive bumps the patch, breaking bumps the minor (never auto-1.0.0)", () => {
9
+ expect(bumpForSeverity("0.13.1", "additive")).toBe("0.13.2");
10
+ expect(bumpForSeverity("0.13.1", "breaking")).toBe("0.14.0");
11
+ expect(bumpForSeverity("0.0.9", "breaking")).toBe("0.1.0");
12
+ });
13
+
14
+ test(">= 1.0.0: additive bumps the minor, breaking bumps the major", () => {
15
+ expect(bumpForSeverity("1.2.3", "additive")).toBe("1.3.0");
16
+ expect(bumpForSeverity("1.2.3", "breaking")).toBe("2.0.0");
17
+ });
18
+
19
+ test("tolerates a leading v", () => {
20
+ expect(bumpForSeverity("v0.14.0", "additive")).toBe("0.14.1");
21
+ });
22
+
23
+ test("returns null for none or an unparseable version", () => {
24
+ expect(bumpForSeverity("0.13.1", "none")).toBeNull();
25
+ expect(bumpForSeverity("1.2", "additive")).toBeNull();
26
+ expect(bumpForSeverity("not-a-version", "breaking")).toBeNull();
27
+ });
28
+ });
29
+
30
+ describe("bumpPackageJsonVersion", () => {
31
+ test("rewrites only the version, preserving other fields + trailing newline", () => {
32
+ const dir = mkdtempSync(join(tmpdir(), "vbump-"));
33
+ try {
34
+ const pkgPath = join(dir, "package.json");
35
+ writeFileSync(pkgPath, JSON.stringify({ name: "x", version: "0.13.1", scripts: { build: "tsc" } }, null, 2));
36
+ bumpPackageJsonVersion(pkgPath, "0.14.0");
37
+ const raw = readFileSync(pkgPath, "utf-8");
38
+ const pkg = JSON.parse(raw) as { name: string; version: string; scripts: Record<string, string> };
39
+ expect(pkg.version).toBe("0.14.0");
40
+ expect(pkg.name).toBe("x");
41
+ expect(pkg.scripts.build).toBe("tsc");
42
+ expect(raw.endsWith("\n")).toBe(true);
43
+ } finally {
44
+ rmSync(dir, { recursive: true, force: true });
45
+ }
46
+ });
47
+ });
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 0.x-aware version bumping, shared by the pinned upgrade Op (#549) and the
3
+ * rolling drift re-baseline (#616). Centralised here so the single source of
4
+ * truth for the semver rule can't drift between the two callers.
5
+ */
6
+
7
+ import { readFileSync, writeFileSync } from "fs";
8
+
9
+ /** Surface-change severity that drives a bump. */
10
+ export type BumpSeverity = "additive" | "breaking" | "none";
11
+
12
+ /**
13
+ * Compute a bumped semver from a current version and a surface severity.
14
+ *
15
+ * Pre-1.0 (major 0) never auto-promotes to 1.0.0: breaking → minor, additive →
16
+ * patch. At >= 1.0.0: breaking → major, additive → minor. Returns null for
17
+ * "none" or a version string that can't be parsed as MAJOR.MINOR.PATCH.
18
+ */
19
+ export function bumpForSeverity(current: string, severity: BumpSeverity): string | null {
20
+ if (severity === "none") return null;
21
+ const parts = current.replace(/^v/, "").split(".").map(Number);
22
+ if (parts.length < 3 || parts.some((n) => Number.isNaN(n) || n < 0)) return null;
23
+ const [major, minor, patch] = parts as [number, number, number];
24
+ if (major === 0) {
25
+ return severity === "breaking" ? `0.${minor + 1}.0` : `0.${minor}.${patch + 1}`;
26
+ }
27
+ return severity === "breaking" ? `${major + 1}.0.0` : `${major}.${minor + 1}.0`;
28
+ }
29
+
30
+ /**
31
+ * Read a package.json, set its `version`, and write it back — preserving all
32
+ * other fields, 2-space indent, and a trailing newline.
33
+ */
34
+ export function bumpPackageJsonVersion(packageJsonPath: string, newVersion: string): void {
35
+ const raw = readFileSync(packageJsonPath, "utf-8");
36
+ const pkg = JSON.parse(raw) as Record<string, unknown>;
37
+ pkg["version"] = newVersion;
38
+ writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
39
+ }