@intentius/chant 0.6.0 → 0.8.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 (433) hide show
  1. package/dist/attrref.d.ts +35 -0
  2. package/dist/attrref.d.ts.map +1 -0
  3. package/dist/audit/catalog.d.ts +65 -0
  4. package/dist/audit/catalog.d.ts.map +1 -0
  5. package/dist/audit/core.d.ts +76 -0
  6. package/dist/audit/core.d.ts.map +1 -0
  7. package/dist/audit/discover.d.ts +76 -0
  8. package/dist/audit/discover.d.ts.map +1 -0
  9. package/dist/audit/fetch.d.ts +90 -0
  10. package/dist/audit/fetch.d.ts.map +1 -0
  11. package/dist/audit/proof.d.ts +53 -0
  12. package/dist/audit/proof.d.ts.map +1 -0
  13. package/dist/audit/report-html.d.ts +32 -0
  14. package/dist/audit/report-html.d.ts.map +1 -0
  15. package/dist/audit/report-model.d.ts +119 -0
  16. package/dist/audit/report-model.d.ts.map +1 -0
  17. package/dist/audit/report.d.ts +31 -0
  18. package/dist/audit/report.d.ts.map +1 -0
  19. package/dist/audit/rules-doc.d.ts +11 -0
  20. package/dist/audit/rules-doc.d.ts.map +1 -0
  21. package/dist/build.d.ts +120 -0
  22. package/dist/build.d.ts.map +1 -0
  23. package/dist/builder.d.ts +56 -0
  24. package/dist/builder.d.ts.map +1 -0
  25. package/dist/child-project.d.ts +34 -0
  26. package/dist/child-project.d.ts.map +1 -0
  27. package/dist/cli/commands/audit.d.ts +60 -0
  28. package/dist/cli/commands/audit.d.ts.map +1 -0
  29. package/dist/cli/commands/build.d.ts +70 -0
  30. package/dist/cli/commands/build.d.ts.map +1 -0
  31. package/dist/cli/commands/check-lexicon.d.ts +19 -0
  32. package/dist/cli/commands/check-lexicon.d.ts.map +1 -0
  33. package/dist/cli/commands/describe.d.ts +39 -0
  34. package/dist/cli/commands/describe.d.ts.map +1 -0
  35. package/dist/cli/commands/diff.d.ts +32 -0
  36. package/dist/cli/commands/diff.d.ts.map +1 -0
  37. package/dist/cli/commands/doctor.d.ts +11 -0
  38. package/dist/cli/commands/doctor.d.ts.map +1 -0
  39. package/dist/cli/commands/import.d.ts +68 -0
  40. package/dist/cli/commands/import.d.ts.map +1 -0
  41. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +9 -0
  42. package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -0
  43. package/dist/cli/commands/init-lexicon/templates/docs.d.ts +9 -0
  44. package/dist/cli/commands/init-lexicon/templates/docs.d.ts.map +1 -0
  45. package/dist/cli/commands/init-lexicon/templates/examples.d.ts +8 -0
  46. package/dist/cli/commands/init-lexicon/templates/examples.d.ts.map +1 -0
  47. package/dist/cli/commands/init-lexicon/templates/lint.d.ts +8 -0
  48. package/dist/cli/commands/init-lexicon/templates/lint.d.ts.map +1 -0
  49. package/dist/cli/commands/init-lexicon/templates/lsp.d.ts +6 -0
  50. package/dist/cli/commands/init-lexicon/templates/lsp.d.ts.map +1 -0
  51. package/dist/cli/commands/init-lexicon/templates/plugin.d.ts +12 -0
  52. package/dist/cli/commands/init-lexicon/templates/plugin.d.ts.map +1 -0
  53. package/dist/cli/commands/init-lexicon/templates/project.d.ts +19 -0
  54. package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -0
  55. package/dist/cli/commands/init-lexicon/templates/spec.d.ts +6 -0
  56. package/dist/cli/commands/init-lexicon/templates/spec.d.ts.map +1 -0
  57. package/dist/cli/commands/init-lexicon/templates/tests.d.ts +12 -0
  58. package/dist/cli/commands/init-lexicon/templates/tests.d.ts.map +1 -0
  59. package/dist/cli/commands/init-lexicon.d.ts +37 -0
  60. package/dist/cli/commands/init-lexicon.d.ts.map +1 -0
  61. package/dist/cli/commands/init.d.ts +48 -0
  62. package/dist/cli/commands/init.d.ts.map +1 -0
  63. package/dist/cli/commands/licenses.d.ts +23 -0
  64. package/dist/cli/commands/licenses.d.ts.map +1 -0
  65. package/dist/cli/commands/lint.d.ts +52 -0
  66. package/dist/cli/commands/lint.d.ts.map +1 -0
  67. package/dist/cli/commands/list.d.ts +38 -0
  68. package/dist/cli/commands/list.d.ts.map +1 -0
  69. package/dist/cli/commands/migrate.d.ts +51 -0
  70. package/dist/cli/commands/migrate.d.ts.map +1 -0
  71. package/dist/cli/commands/onboard.d.ts +19 -0
  72. package/dist/cli/commands/onboard.d.ts.map +1 -0
  73. package/dist/cli/commands/update.d.ts +29 -0
  74. package/dist/cli/commands/update.d.ts.map +1 -0
  75. package/dist/cli/commands/vendor.d.ts +84 -0
  76. package/dist/cli/commands/vendor.d.ts.map +1 -0
  77. package/dist/cli/conflict-check.d.ts +18 -0
  78. package/dist/cli/conflict-check.d.ts.map +1 -0
  79. package/dist/cli/debug.d.ts +5 -0
  80. package/dist/cli/debug.d.ts.map +1 -0
  81. package/dist/cli/format.d.ts +36 -0
  82. package/dist/cli/format.d.ts.map +1 -0
  83. package/dist/cli/handlers/build.d.ts +3 -0
  84. package/dist/cli/handlers/build.d.ts.map +1 -0
  85. package/dist/cli/handlers/dev.d.ts +7 -0
  86. package/dist/cli/handlers/dev.d.ts.map +1 -0
  87. package/dist/cli/handlers/graph.d.ts +8 -0
  88. package/dist/cli/handlers/graph.d.ts.map +1 -0
  89. package/dist/cli/handlers/init.d.ts +4 -0
  90. package/dist/cli/handlers/init.d.ts.map +1 -0
  91. package/dist/cli/handlers/lifecycle.d.ts +39 -0
  92. package/dist/cli/handlers/lifecycle.d.ts.map +1 -0
  93. package/dist/cli/handlers/lint.d.ts +3 -0
  94. package/dist/cli/handlers/lint.d.ts.map +1 -0
  95. package/dist/cli/handlers/migrate.d.ts +3 -0
  96. package/dist/cli/handlers/migrate.d.ts.map +1 -0
  97. package/dist/cli/handlers/misc.d.ts +8 -0
  98. package/dist/cli/handlers/misc.d.ts.map +1 -0
  99. package/dist/cli/handlers/run-client.d.ts +107 -0
  100. package/dist/cli/handlers/run-client.d.ts.map +1 -0
  101. package/dist/cli/handlers/run-report.d.ts +5 -0
  102. package/dist/cli/handlers/run-report.d.ts.map +1 -0
  103. package/dist/cli/handlers/run.d.ts +27 -0
  104. package/dist/cli/handlers/run.d.ts.map +1 -0
  105. package/dist/cli/handlers/serve.d.ts +5 -0
  106. package/dist/cli/handlers/serve.d.ts.map +1 -0
  107. package/dist/cli/handlers/vendor.d.ts +9 -0
  108. package/dist/cli/handlers/vendor.d.ts.map +1 -0
  109. package/dist/cli/index.d.ts +4 -0
  110. package/dist/cli/index.d.ts.map +1 -0
  111. package/dist/cli/lsp/capabilities.d.ts +21 -0
  112. package/dist/cli/lsp/capabilities.d.ts.map +1 -0
  113. package/dist/cli/lsp/diagnostics.d.ts +30 -0
  114. package/dist/cli/lsp/diagnostics.d.ts.map +1 -0
  115. package/dist/cli/lsp/server.d.ts +106 -0
  116. package/dist/cli/lsp/server.d.ts.map +1 -0
  117. package/dist/cli/main.d.ts +7 -0
  118. package/dist/cli/main.d.ts.map +1 -0
  119. package/dist/cli/mcp/lifecycle-tools.d.ts +15 -0
  120. package/dist/cli/mcp/lifecycle-tools.d.ts.map +1 -0
  121. package/dist/cli/mcp/op-tools.d.ts +7 -0
  122. package/dist/cli/mcp/op-tools.d.ts.map +1 -0
  123. package/dist/cli/mcp/resource-handlers.d.ts +28 -0
  124. package/dist/cli/mcp/resource-handlers.d.ts.map +1 -0
  125. package/dist/cli/mcp/resources/context.d.ts +6 -0
  126. package/dist/cli/mcp/resources/context.d.ts.map +1 -0
  127. package/dist/cli/mcp/server.d.ts +44 -0
  128. package/dist/cli/mcp/server.d.ts.map +1 -0
  129. package/dist/cli/mcp/tools/build.d.ts +31 -0
  130. package/dist/cli/mcp/tools/build.d.ts.map +1 -0
  131. package/dist/cli/mcp/tools/explain.d.ts +27 -0
  132. package/dist/cli/mcp/tools/explain.d.ts.map +1 -0
  133. package/dist/cli/mcp/tools/import.d.ts +26 -0
  134. package/dist/cli/mcp/tools/import.d.ts.map +1 -0
  135. package/dist/cli/mcp/tools/lint.d.ts +26 -0
  136. package/dist/cli/mcp/tools/lint.d.ts.map +1 -0
  137. package/dist/cli/mcp/tools/scaffold.d.ts +31 -0
  138. package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -0
  139. package/dist/cli/mcp/tools/search.d.ts +31 -0
  140. package/dist/cli/mcp/tools/search.d.ts.map +1 -0
  141. package/dist/cli/mcp/types.d.ts +42 -0
  142. package/dist/cli/mcp/types.d.ts.map +1 -0
  143. package/dist/cli/plugins.d.ts +21 -0
  144. package/dist/cli/plugins.d.ts.map +1 -0
  145. package/dist/cli/registry.d.ts +100 -0
  146. package/dist/cli/registry.d.ts.map +1 -0
  147. package/dist/cli/reporters/stylish.d.ts +26 -0
  148. package/dist/cli/reporters/stylish.d.ts.map +1 -0
  149. package/dist/cli/watch.d.ts +29 -0
  150. package/dist/cli/watch.d.ts.map +1 -0
  151. package/dist/codegen/bound-property-types.d.ts +38 -0
  152. package/dist/codegen/bound-property-types.d.ts.map +1 -0
  153. package/dist/codegen/coverage.d.ts +57 -0
  154. package/dist/codegen/coverage.d.ts.map +1 -0
  155. package/dist/codegen/docs-file-markers.d.ts +16 -0
  156. package/dist/codegen/docs-file-markers.d.ts.map +1 -0
  157. package/dist/codegen/docs-rule-scanning.d.ts +14 -0
  158. package/dist/codegen/docs-rule-scanning.d.ts.map +1 -0
  159. package/dist/codegen/docs-rules.d.ts +17 -0
  160. package/dist/codegen/docs-rules.d.ts.map +1 -0
  161. package/dist/codegen/docs-sections.d.ts +11 -0
  162. package/dist/codegen/docs-sections.d.ts.map +1 -0
  163. package/dist/codegen/docs-sidebar.d.ts +6 -0
  164. package/dist/codegen/docs-sidebar.d.ts.map +1 -0
  165. package/dist/codegen/docs-types.d.ts +84 -0
  166. package/dist/codegen/docs-types.d.ts.map +1 -0
  167. package/dist/codegen/docs.d.ts +28 -0
  168. package/dist/codegen/docs.d.ts.map +1 -0
  169. package/dist/codegen/fetch.d.ts +76 -0
  170. package/dist/codegen/fetch.d.ts.map +1 -0
  171. package/dist/codegen/generate-post-synth-barrel.d.ts +32 -0
  172. package/dist/codegen/generate-post-synth-barrel.d.ts.map +1 -0
  173. package/dist/codegen/generate-registry.d.ts +40 -0
  174. package/dist/codegen/generate-registry.d.ts.map +1 -0
  175. package/dist/codegen/generate-runtime-index.d.ts +40 -0
  176. package/dist/codegen/generate-runtime-index.d.ts.map +1 -0
  177. package/dist/codegen/generate-typescript.d.ts +48 -0
  178. package/dist/codegen/generate-typescript.d.ts.map +1 -0
  179. package/dist/codegen/generate.d.ts +92 -0
  180. package/dist/codegen/generate.d.ts.map +1 -0
  181. package/dist/codegen/json-patch.d.ts +12 -0
  182. package/dist/codegen/json-patch.d.ts.map +1 -0
  183. package/dist/codegen/json-schema.d.ts +82 -0
  184. package/dist/codegen/json-schema.d.ts.map +1 -0
  185. package/dist/codegen/naming.d.ts +64 -0
  186. package/dist/codegen/naming.d.ts.map +1 -0
  187. package/dist/codegen/package.d.ts +64 -0
  188. package/dist/codegen/package.d.ts.map +1 -0
  189. package/dist/codegen/topo-sort.d.ts +13 -0
  190. package/dist/codegen/topo-sort.d.ts.map +1 -0
  191. package/dist/codegen/typecheck.d.ts +10 -0
  192. package/dist/codegen/typecheck.d.ts.map +1 -0
  193. package/dist/codegen/validate.d.ts +45 -0
  194. package/dist/codegen/validate.d.ts.map +1 -0
  195. package/dist/composite.d.ts +116 -0
  196. package/dist/composite.d.ts.map +1 -0
  197. package/dist/config.d.ts +78 -0
  198. package/dist/config.d.ts.map +1 -0
  199. package/dist/declarable.d.ts +34 -0
  200. package/dist/declarable.d.ts.map +1 -0
  201. package/dist/detectLexicon.d.ts +10 -0
  202. package/dist/detectLexicon.d.ts.map +1 -0
  203. package/dist/discovery/cache.d.ts +36 -0
  204. package/dist/discovery/cache.d.ts.map +1 -0
  205. package/dist/discovery/collect.d.ts +17 -0
  206. package/dist/discovery/collect.d.ts.map +1 -0
  207. package/dist/discovery/cycles.d.ts +23 -0
  208. package/dist/discovery/cycles.d.ts.map +1 -0
  209. package/dist/discovery/files.d.ts +7 -0
  210. package/dist/discovery/files.d.ts.map +1 -0
  211. package/dist/discovery/graph.d.ts +8 -0
  212. package/dist/discovery/graph.d.ts.map +1 -0
  213. package/dist/discovery/import.d.ts +9 -0
  214. package/dist/discovery/import.d.ts.map +1 -0
  215. package/dist/discovery/index.d.ts +25 -0
  216. package/dist/discovery/index.d.ts.map +1 -0
  217. package/dist/discovery/resolve.d.ts +10 -0
  218. package/dist/discovery/resolve.d.ts.map +1 -0
  219. package/dist/errors.d.ts +49 -0
  220. package/dist/errors.d.ts.map +1 -0
  221. package/dist/import/base-parser.d.ts +19 -0
  222. package/dist/import/base-parser.d.ts.map +1 -0
  223. package/dist/import/generator.d.ts +20 -0
  224. package/dist/import/generator.d.ts.map +1 -0
  225. package/dist/import/ir-utils.d.ts +25 -0
  226. package/dist/import/ir-utils.d.ts.map +1 -0
  227. package/dist/import/parser.d.ts +39 -0
  228. package/dist/import/parser.d.ts.map +1 -0
  229. package/dist/index.d.ts +66 -0
  230. package/dist/index.d.ts.map +1 -0
  231. package/dist/intrinsic-interpolation.d.ts +24 -0
  232. package/dist/intrinsic-interpolation.d.ts.map +1 -0
  233. package/dist/intrinsic.d.ts +24 -0
  234. package/dist/intrinsic.d.ts.map +1 -0
  235. package/dist/lexicon-integrity.d.ts +25 -0
  236. package/dist/lexicon-integrity.d.ts.map +1 -0
  237. package/dist/lexicon-manifest.d.ts +9 -0
  238. package/dist/lexicon-manifest.d.ts.map +1 -0
  239. package/dist/lexicon-output.d.ts +66 -0
  240. package/dist/lexicon-output.d.ts.map +1 -0
  241. package/dist/lexicon-plugin-helpers.d.ts +59 -0
  242. package/dist/lexicon-plugin-helpers.d.ts.map +1 -0
  243. package/dist/lexicon-schema.d.ts +82 -0
  244. package/dist/lexicon-schema.d.ts.map +1 -0
  245. package/dist/lexicon.d.ts +383 -0
  246. package/dist/lexicon.d.ts.map +1 -0
  247. package/dist/lifecycle/affected.d.ts +57 -0
  248. package/dist/lifecycle/affected.d.ts.map +1 -0
  249. package/dist/lifecycle/change-set.d.ts +90 -0
  250. package/dist/lifecycle/change-set.d.ts.map +1 -0
  251. package/dist/lifecycle/digest.d.ts +21 -0
  252. package/dist/lifecycle/digest.d.ts.map +1 -0
  253. package/dist/lifecycle/git.d.ts +72 -0
  254. package/dist/lifecycle/git.d.ts.map +1 -0
  255. package/dist/lifecycle/index.d.ts +8 -0
  256. package/dist/lifecycle/index.d.ts.map +1 -0
  257. package/dist/lifecycle/live-diff.d.ts +67 -0
  258. package/dist/lifecycle/live-diff.d.ts.map +1 -0
  259. package/dist/lifecycle/snapshot.d.ts +20 -0
  260. package/dist/lifecycle/snapshot.d.ts.map +1 -0
  261. package/dist/lifecycle/types.d.ts +61 -0
  262. package/dist/lifecycle/types.d.ts.map +1 -0
  263. package/dist/lint/config.d.ts +100 -0
  264. package/dist/lint/config.d.ts.map +1 -0
  265. package/dist/lint/declarative.d.ts +56 -0
  266. package/dist/lint/declarative.d.ts.map +1 -0
  267. package/dist/lint/discover.d.ts +35 -0
  268. package/dist/lint/discover.d.ts.map +1 -0
  269. package/dist/lint/engine.d.ts +21 -0
  270. package/dist/lint/engine.d.ts.map +1 -0
  271. package/dist/lint/named-checks.d.ts +19 -0
  272. package/dist/lint/named-checks.d.ts.map +1 -0
  273. package/dist/lint/parser.d.ts +9 -0
  274. package/dist/lint/parser.d.ts.map +1 -0
  275. package/dist/lint/policy.d.ts +22 -0
  276. package/dist/lint/policy.d.ts.map +1 -0
  277. package/dist/lint/post-synth.d.ts +69 -0
  278. package/dist/lint/post-synth.d.ts.map +1 -0
  279. package/dist/lint/presets/strict.json +19 -0
  280. package/dist/lint/rule-loader.d.ts +16 -0
  281. package/dist/lint/rule-loader.d.ts.map +1 -0
  282. package/dist/lint/rule-registry.d.ts +37 -0
  283. package/dist/lint/rule-registry.d.ts.map +1 -0
  284. package/dist/lint/rule.d.ts +82 -0
  285. package/dist/lint/rule.d.ts.map +1 -0
  286. package/dist/lint/rules/composite-scope.d.ts +18 -0
  287. package/dist/lint/rules/composite-scope.d.ts.map +1 -0
  288. package/dist/lint/rules/cor017-composite-name-match.d.ts +3 -0
  289. package/dist/lint/rules/cor017-composite-name-match.d.ts.map +1 -0
  290. package/dist/lint/rules/cor018-composite-prefer-lexicon-type.d.ts +3 -0
  291. package/dist/lint/rules/cor018-composite-prefer-lexicon-type.d.ts.map +1 -0
  292. package/dist/lint/rules/declarable-naming-convention.d.ts +3 -0
  293. package/dist/lint/rules/declarable-naming-convention.d.ts.map +1 -0
  294. package/dist/lint/rules/evl001-non-literal-expression.d.ts +3 -0
  295. package/dist/lint/rules/evl001-non-literal-expression.d.ts.map +1 -0
  296. package/dist/lint/rules/evl002-control-flow-resource.d.ts +3 -0
  297. package/dist/lint/rules/evl002-control-flow-resource.d.ts.map +1 -0
  298. package/dist/lint/rules/evl003-dynamic-property-access.d.ts +3 -0
  299. package/dist/lint/rules/evl003-dynamic-property-access.d.ts.map +1 -0
  300. package/dist/lint/rules/evl004-spread-non-const.d.ts +3 -0
  301. package/dist/lint/rules/evl004-spread-non-const.d.ts.map +1 -0
  302. package/dist/lint/rules/evl005-resource-block-body.d.ts +3 -0
  303. package/dist/lint/rules/evl005-resource-block-body.d.ts.map +1 -0
  304. package/dist/lint/rules/evl007-invalid-siblings.d.ts +3 -0
  305. package/dist/lint/rules/evl007-invalid-siblings.d.ts.map +1 -0
  306. package/dist/lint/rules/evl009-composite-no-constant.d.ts +3 -0
  307. package/dist/lint/rules/evl009-composite-no-constant.d.ts.map +1 -0
  308. package/dist/lint/rules/evl010-composite-no-transform.d.ts +3 -0
  309. package/dist/lint/rules/evl010-composite-no-transform.d.ts.map +1 -0
  310. package/dist/lint/rules/export-required.d.ts +3 -0
  311. package/dist/lint/rules/export-required.d.ts.map +1 -0
  312. package/dist/lint/rules/file-declarable-limit.d.ts +3 -0
  313. package/dist/lint/rules/file-declarable-limit.d.ts.map +1 -0
  314. package/dist/lint/rules/flat-declarations.d.ts +3 -0
  315. package/dist/lint/rules/flat-declarations.d.ts.map +1 -0
  316. package/dist/lint/rules/index.d.ts +31 -0
  317. package/dist/lint/rules/index.d.ts.map +1 -0
  318. package/dist/lint/rules/no-cyclic-declarable-ref.d.ts +3 -0
  319. package/dist/lint/rules/no-cyclic-declarable-ref.d.ts.map +1 -0
  320. package/dist/lint/rules/no-redundant-type-import.d.ts +10 -0
  321. package/dist/lint/rules/no-redundant-type-import.d.ts.map +1 -0
  322. package/dist/lint/rules/no-redundant-value-cast.d.ts +3 -0
  323. package/dist/lint/rules/no-redundant-value-cast.d.ts.map +1 -0
  324. package/dist/lint/rules/no-string-ref.d.ts +3 -0
  325. package/dist/lint/rules/no-string-ref.d.ts.map +1 -0
  326. package/dist/lint/rules/no-unused-declarable-import.d.ts +3 -0
  327. package/dist/lint/rules/no-unused-declarable-import.d.ts.map +1 -0
  328. package/dist/lint/rules/no-unused-declarable.d.ts +3 -0
  329. package/dist/lint/rules/no-unused-declarable.d.ts.map +1 -0
  330. package/dist/lint/rules/single-concern-file.d.ts +3 -0
  331. package/dist/lint/rules/single-concern-file.d.ts.map +1 -0
  332. package/dist/lint/selectors.d.ts +21 -0
  333. package/dist/lint/selectors.d.ts.map +1 -0
  334. package/dist/lsp/lexicon-providers.d.ts +61 -0
  335. package/dist/lsp/lexicon-providers.d.ts.map +1 -0
  336. package/dist/lsp/types.d.ts +64 -0
  337. package/dist/lsp/types.d.ts.map +1 -0
  338. package/dist/mcp/types.d.ts +21 -0
  339. package/dist/mcp/types.d.ts.map +1 -0
  340. package/dist/op/activity-registry.d.ts +57 -0
  341. package/dist/op/activity-registry.d.ts.map +1 -0
  342. package/dist/op/builders.d.ts +69 -0
  343. package/dist/op/builders.d.ts.map +1 -0
  344. package/dist/op/discover.d.ts +16 -0
  345. package/dist/op/discover.d.ts.map +1 -0
  346. package/dist/op/index.d.ts +11 -0
  347. package/dist/op/index.d.ts.map +1 -0
  348. package/dist/op/local-executor.d.ts +54 -0
  349. package/dist/op/local-executor.d.ts.map +1 -0
  350. package/dist/op/local-output.d.ts +16 -0
  351. package/dist/op/local-output.d.ts.map +1 -0
  352. package/dist/op/resource.d.ts +7 -0
  353. package/dist/op/resource.d.ts.map +1 -0
  354. package/dist/op/types.d.ts +71 -0
  355. package/dist/op/types.d.ts.map +1 -0
  356. package/dist/ownership.d.ts +75 -0
  357. package/dist/ownership.d.ts.map +1 -0
  358. package/dist/project-validation.d.ts +28 -0
  359. package/dist/project-validation.d.ts.map +1 -0
  360. package/dist/provenance.d.ts +26 -0
  361. package/dist/provenance.d.ts.map +1 -0
  362. package/dist/pseudo-parameter.d.ts +32 -0
  363. package/dist/pseudo-parameter.d.ts.map +1 -0
  364. package/dist/resource-attributes.d.ts +17 -0
  365. package/dist/resource-attributes.d.ts.map +1 -0
  366. package/dist/runtime-adapter.d.ts +41 -0
  367. package/dist/runtime-adapter.d.ts.map +1 -0
  368. package/dist/runtime.d.ts +23 -0
  369. package/dist/runtime.d.ts.map +1 -0
  370. package/dist/serializer-walker.d.ts +21 -0
  371. package/dist/serializer-walker.d.ts.map +1 -0
  372. package/dist/serializer.d.ts +64 -0
  373. package/dist/serializer.d.ts.map +1 -0
  374. package/dist/sort.d.ts +8 -0
  375. package/dist/sort.d.ts.map +1 -0
  376. package/dist/stack-output.d.ts +52 -0
  377. package/dist/stack-output.d.ts.map +1 -0
  378. package/dist/toml-emit.d.ts +22 -0
  379. package/dist/toml-emit.d.ts.map +1 -0
  380. package/dist/toml-parse.d.ts +14 -0
  381. package/dist/toml-parse.d.ts.map +1 -0
  382. package/dist/toml-utils.d.ts +20 -0
  383. package/dist/toml-utils.d.ts.map +1 -0
  384. package/dist/toml.d.ts +9 -0
  385. package/dist/toml.d.ts.map +1 -0
  386. package/dist/types.d.ts +47 -0
  387. package/dist/types.d.ts.map +1 -0
  388. package/dist/utils.d.ts +30 -0
  389. package/dist/utils.d.ts.map +1 -0
  390. package/dist/validation.d.ts +42 -0
  391. package/dist/validation.d.ts.map +1 -0
  392. package/dist/yaml.d.ts +42 -0
  393. package/dist/yaml.d.ts.map +1 -0
  394. package/package.json +31 -6
  395. package/src/audit/bundle-decoupling.test.ts +56 -0
  396. package/src/audit/catalog.test.ts +17 -2
  397. package/src/audit/catalog.ts +357 -4
  398. package/src/audit/core.test.ts +15 -0
  399. package/src/audit/core.ts +0 -0
  400. package/src/audit/detect-bundle.test.ts +35 -0
  401. package/src/audit/discover.test.ts +72 -0
  402. package/src/audit/discover.ts +329 -0
  403. package/src/audit/edge-init-safety.test.ts +43 -0
  404. package/src/audit/fetch.test.ts +86 -55
  405. package/src/audit/fetch.ts +118 -87
  406. package/src/audit/remote-discovery.test.ts +80 -0
  407. package/src/audit/report-html.ts +14 -6
  408. package/src/audit/report-model.ts +13 -1
  409. package/src/audit/report.test.ts +3 -1
  410. package/src/audit/report.ts +13 -5
  411. package/src/audit/rules-doc.ts +4 -0
  412. package/src/cli/commands/__fixtures__/audit-aws/stack.yaml +11 -0
  413. package/src/cli/commands/__fixtures__/audit-aws/template.json +7 -0
  414. package/src/cli/commands/__fixtures__/audit-azure/azuredeploy.json +13 -0
  415. package/src/cli/commands/__fixtures__/audit-gcp/bucket.yaml +6 -0
  416. package/src/cli/commands/__fixtures__/audit-gcp/firewall.yaml +9 -0
  417. package/src/cli/commands/__fixtures__/audit-helm/mychart/Chart.yaml +3 -0
  418. package/src/cli/commands/__fixtures__/audit-helm/mychart/templates/deployment.yaml +12 -0
  419. package/src/cli/commands/__fixtures__/audit-helm/mychart/values.yaml +1 -0
  420. package/src/cli/commands/__fixtures__/audit-mixed/.github/workflows/ci.yml +5 -0
  421. package/src/cli/commands/__fixtures__/audit-mixed/Dockerfile +2 -0
  422. package/src/cli/commands/__fixtures__/audit-mixed/cfn/template.json +1 -0
  423. package/src/cli/commands/__fixtures__/audit-mixed/k8s/deploy.yaml +12 -0
  424. package/src/cli/commands/audit.test.ts +80 -14
  425. package/src/cli/commands/audit.ts +28 -126
  426. package/src/codegen/bound-property-types.test.ts +57 -0
  427. package/src/codegen/bound-property-types.ts +110 -0
  428. package/src/codegen/generate-post-synth-barrel.test.ts +37 -0
  429. package/src/codegen/generate-post-synth-barrel.ts +75 -0
  430. package/src/codegen/post-synth-barrel-guards.test.ts +63 -0
  431. package/src/codegen/validate.ts +13 -1
  432. package/src/lint/discover.ts +1 -1
  433. package/src/meta/peer-deps.test.ts +29 -0
@@ -0,0 +1,5 @@
1
+ on: push
2
+ permissions: write-all
3
+ jobs:
4
+ build:
5
+ runs-on: ubuntu-latest
@@ -0,0 +1,2 @@
1
+ FROM ubuntu
2
+ RUN apt-get update
@@ -0,0 +1 @@
1
+ {"AWSTemplateFormatVersion":"2010-09-09","Resources":{"B":{"Type":"AWS::S3::Bucket"}}}
@@ -0,0 +1,12 @@
1
+ apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ name: x
5
+ spec:
6
+ template:
7
+ spec:
8
+ containers:
9
+ - name: c
10
+ image: nginx:latest
11
+ securityContext:
12
+ privileged: true
@@ -1,7 +1,13 @@
1
1
  import { describe, test, expect } from "vitest";
2
2
  import { fileURLToPath } from "url";
3
- import { auditCommand, discoverCiFiles, discoverManifests, discoverDocker, tokenForHost, coverageNotes } from "./audit";
4
- import { MissingLexiconError, type AuditInput } from "../../audit/core";
3
+ import { auditCommand, tokenForHost, coverageNotes } from "./audit";
4
+ import { discoverByDetection, loadAuditPlugins } from "../../audit/discover";
5
+ import { MissingLexiconError, type AuditInput, type AuditLexicon } from "../../audit/core";
6
+
7
+ /** Discover with all audit lexicons loaded, then keep one lexicon's inputs. */
8
+ async function discoverLexicon(repo: string, lexicon: AuditLexicon): Promise<AuditInput[]> {
9
+ return discoverByDetection(repo, await loadAuditPlugins()).filter((i) => i.lexicon === lexicon);
10
+ }
5
11
  import { readFileSync, existsSync, rmSync } from "fs";
6
12
  import { tmpdir } from "os";
7
13
  import { join } from "path";
@@ -32,7 +38,7 @@ describe("auditCommand", () => {
32
38
 
33
39
  test("discovers and audits Kubernetes manifests", async () => {
34
40
  const repo = fileURLToPath(new URL("./__fixtures__/audit-k8s", import.meta.url));
35
- const files = discoverManifests(repo);
41
+ const files = await discoverLexicon(repo, "k8s");
36
42
  expect(files.map((f) => f.path)).toContain("manifests/deploy.yaml");
37
43
  expect(files.every((f) => f.lexicon === "k8s")).toBe(true);
38
44
 
@@ -45,7 +51,7 @@ describe("auditCommand", () => {
45
51
 
46
52
  test("discovers and audits Docker artifacts (nested Dockerfile + compose)", async () => {
47
53
  const repo = fileURLToPath(new URL("./__fixtures__/audit-docker", import.meta.url));
48
- const files = discoverDocker(repo);
54
+ const files = await discoverLexicon(repo, "docker");
49
55
  const paths = files.map((f) => f.path).sort();
50
56
  expect(paths).toContain("app/Dockerfile");
51
57
  expect(paths).toContain("docker-compose.yml");
@@ -58,8 +64,66 @@ describe("auditCommand", () => {
58
64
  expect(ids).toContain("DKRD003"); // compose exposes SSH port 22
59
65
  });
60
66
 
61
- test("discovers CI files under a repo root", () => {
62
- const files = discoverCiFiles(REPO);
67
+ test("discovers and audits CloudFormation (JSON and YAML)", async () => {
68
+ const repo = fileURLToPath(new URL("./__fixtures__/audit-aws", import.meta.url));
69
+ const files = await discoverLexicon(repo, "aws");
70
+ const paths = files.map((f) => f.path).sort();
71
+ expect(paths).toContain("template.json");
72
+ expect(paths).toContain("stack.yaml");
73
+ // YAML is normalized to a JSON string the aws checks can JSON.parse.
74
+ expect(() => JSON.parse(files.find((f) => f.path === "stack.yaml")!.content)).not.toThrow();
75
+
76
+ const result = await auditCommand({ path: repo, format: "stylish" });
77
+ expect(result.success).toBe(true);
78
+ const ids = new Set(result.findings.map((f) => f.checkId));
79
+ expect(ids).toContain("WAW018"); // S3 missing public access block (JSON template)
80
+ expect(ids).toContain("WAW021"); // RDS not encrypted (JSON template)
81
+ expect(ids).toContain("WAW019"); // SG open SSH (YAML template — proves YAML works)
82
+ });
83
+
84
+ test("discovers and audits Azure ARM templates", async () => {
85
+ const repo = fileURLToPath(new URL("./__fixtures__/audit-azure", import.meta.url));
86
+ expect((await discoverLexicon(repo, "azure")).map((f) => f.path)).toContain("azuredeploy.json");
87
+ const result = await auditCommand({ path: repo, format: "stylish" });
88
+ expect(result.success).toBe(true);
89
+ const ids = new Set(result.findings.map((f) => f.checkId));
90
+ expect(ids).toContain("AZR014"); // storage allows public blob access
91
+ });
92
+
93
+ test("discovers and audits GCP Config Connector (not misclassified as k8s)", async () => {
94
+ const repo = fileURLToPath(new URL("./__fixtures__/audit-gcp", import.meta.url));
95
+ const gcp = await discoverLexicon(repo, "gcp");
96
+ expect(gcp.map((f) => f.path).sort()).toEqual(["bucket.yaml", "firewall.yaml"]);
97
+ // cnrm manifests must NOT also be picked up as k8s.
98
+ expect(await discoverLexicon(repo, "k8s")).toEqual([]);
99
+
100
+ const result = await auditCommand({ path: repo, format: "stylish" });
101
+ expect(result.success).toBe(true);
102
+ const ids = new Set(result.findings.map((f) => f.checkId));
103
+ expect(ids).toContain("WGC109"); // firewall open to 0.0.0.0/0
104
+ // k8s checks did not run on these.
105
+ expect([...ids].some((id) => id.startsWith("WK8"))).toBe(false);
106
+ });
107
+
108
+ test("discovers and audits a Helm chart (as a bundle, not loose manifests)", async () => {
109
+ const repo = fileURLToPath(new URL("./__fixtures__/audit-helm", import.meta.url));
110
+ const charts = await discoverLexicon(repo, "helm");
111
+ expect(charts).toHaveLength(1);
112
+ expect(charts[0].lexicon).toBe("helm");
113
+ expect(charts[0].files!["Chart.yaml"]).toContain("name: mychart");
114
+ expect(charts[0].files!["templates/deployment.yaml"]).toContain("privileged");
115
+
116
+ const result = await auditCommand({ path: repo, format: "stylish" });
117
+ expect(result.success).toBe(true);
118
+ const ids = new Set(result.findings.map((f) => f.checkId));
119
+ expect(ids).toContain("WHM401"); // :latest image in the chart
120
+ expect(ids).toContain("WHM404"); // privileged container in a template
121
+ // the chart's template was NOT double-audited as a loose k8s manifest
122
+ expect([...ids].some((id) => id.startsWith("WK8"))).toBe(false);
123
+ });
124
+
125
+ test("discovers CI files under a repo root", async () => {
126
+ const files = await discoverLexicon(REPO, "github");
63
127
  expect(files.map((f) => f.path)).toContain(".github/workflows/ci.yml");
64
128
  expect(files.every((f) => f.lexicon === "github")).toBe(true);
65
129
  });
@@ -110,7 +174,7 @@ describe("auditCommand", () => {
110
174
  expect(result.success).toBe(true);
111
175
  expect(result.wroteTo).toBe(out);
112
176
  expect(existsSync(out)).toBe(true);
113
- expect(readFileSync(out, "utf-8")).toContain("# CI security audit");
177
+ expect(readFileSync(out, "utf-8")).toContain("# chant audit");
114
178
  rmSync(out);
115
179
  });
116
180
 
@@ -133,7 +197,7 @@ describe("auditCommand", () => {
133
197
  const result = await auditCommand({ path: tmp });
134
198
  expect(result.success).toBe(true);
135
199
  expect(result.exitCode).toBe(0);
136
- expect(result.output).toContain("No CI files found");
200
+ expect(result.output).toContain("No auditable files found");
137
201
  rmSync(tmp, { recursive: true, force: true });
138
202
  });
139
203
 
@@ -142,12 +206,13 @@ describe("auditCommand", () => {
142
206
  const yaml = "name: CI\non:\n push:\npermissions: write-all\njobs:\n build:\n runs-on: ubuntu-latest\n";
143
207
  const impl = (async (url: string | URL | Request) => {
144
208
  const u = String(url);
209
+ if (u.includes("/git/trees/")) {
210
+ return new Response(JSON.stringify({ tree: [{ path: ".github/workflows/ci.yml", type: "blob", size: 100 }] }), { status: 200 });
211
+ }
145
212
  if (u.includes("/contents/.github/workflows/ci.yml")) {
146
213
  return new Response(JSON.stringify({ name: "ci.yml", path: ".github/workflows/ci.yml", type: "file", content: b64(yaml), encoding: "base64" }), { status: 200 });
147
214
  }
148
- if (u.includes("/contents/.github/workflows")) {
149
- return new Response(JSON.stringify([{ name: "ci.yml", path: ".github/workflows/ci.yml", type: "file", size: 100 }]), { status: 200 });
150
- }
215
+ if (/\/repos\/acme\/widgets(\?|$)/.test(u)) return new Response(JSON.stringify({ default_branch: "main" }), { status: 200 });
151
216
  return new Response("not found", { status: 404 });
152
217
  }) as unknown as typeof fetch;
153
218
 
@@ -164,12 +229,13 @@ describe("auditCommand", () => {
164
229
  const impl = (async (url: string | URL | Request) => {
165
230
  const u = String(url);
166
231
  if (u.includes("/commits/v4")) return new Response(JSON.stringify({ sha }), { status: 200 });
232
+ if (u.includes("/git/trees/")) {
233
+ return new Response(JSON.stringify({ tree: [{ path: ".github/workflows/ci.yml", type: "blob", size: 100 }] }), { status: 200 });
234
+ }
167
235
  if (u.includes("/contents/.github/workflows/ci.yml")) {
168
236
  return new Response(JSON.stringify({ name: "ci.yml", path: ".github/workflows/ci.yml", type: "file", content: b64(yaml), encoding: "base64" }), { status: 200 });
169
237
  }
170
- if (u.includes("/contents/.github/workflows")) {
171
- return new Response(JSON.stringify([{ name: "ci.yml", path: ".github/workflows/ci.yml", type: "file", size: 100 }]), { status: 200 });
172
- }
238
+ if (/\/repos\/acme\/widgets(\?|$)/.test(u)) return new Response(JSON.stringify({ default_branch: "main" }), { status: 200 });
173
239
  return new Response("not found", { status: 404 });
174
240
  }) as unknown as typeof fetch;
175
241
 
@@ -1,19 +1,18 @@
1
1
  /**
2
- * `chant audit` — run chant's CI security checks against an existing repo's
2
+ * `chant audit` — run chant's security, correctness, and best-practice checks against an existing repo's
3
3
  * pipeline YAML and emit a tiered report. Does not require a chant project;
4
4
  * it reads `.github/workflows`, `.gitlab-ci.yml`, and `.forgejo/workflows`
5
5
  * directly and runs the real post-synth checks via the audit core.
6
6
  */
7
7
 
8
- import { existsSync, readFileSync, readdirSync, statSync, writeFileSync } from "fs";
9
- import { join, relative, basename } from "path";
10
- import { parseYAML } from "../../yaml";
11
- import { auditFiles, type AuditInput, type AuditFinding, type AuditLexicon, type ChecksProvider } from "../../audit/core";
8
+ import { existsSync, statSync, writeFileSync } from "fs";
9
+ import { auditFiles, type AuditInput, type AuditFinding, type ChecksProvider } from "../../audit/core";
10
+ import { discoverByDetection, classifyFiles, loadAuditPlugins, AUDIT_LEXICONS } from "../../audit/discover";
12
11
  import { RULE_CATALOG } from "../../audit/catalog";
13
12
  import { renderMarkdown } from "../../audit/report";
14
13
  import { renderHtml, type ReportTheme } from "../../audit/report-html";
15
14
  import { buildReportJson, type AuditSnapshot } from "../../audit/report-model";
16
- import { fetchCiFiles, resolveActionSha, resolveImageDigest, resolveRepoCommit, parseRepoUrl, FetchError } from "../../audit/fetch";
15
+ import { fetchRepoFiles, resolveActionSha, resolveImageDigest, resolveRepoCommit, parseRepoUrl, FetchError } from "../../audit/fetch";
17
16
  import { extractUnpinnedActions, extractUnpinnedImages } from "../../audit/proof";
18
17
  import type { ProveOptions } from "../../audit/proof";
19
18
  import type { Severity } from "../../lint/rule";
@@ -89,122 +88,6 @@ function githubToken(env: NodeJS.ProcessEnv = process.env): string | undefined {
89
88
  return env.GITHUB_TOKEN ?? env.CHANT_AUDIT_GITHUB_TOKEN;
90
89
  }
91
90
 
92
- function isYaml(name: string): boolean {
93
- return name.endsWith(".yml") || name.endsWith(".yaml");
94
- }
95
-
96
- function collectDir(root: string, dir: string, lexicon: AuditLexicon, out: AuditInput[]): void {
97
- const abs = join(root, dir);
98
- if (!existsSync(abs) || !statSync(abs).isDirectory()) return;
99
- for (const name of readdirSync(abs).sort()) {
100
- if (!isYaml(name)) continue;
101
- const full = join(abs, name);
102
- if (!statSync(full).isFile()) continue;
103
- out.push({ path: relative(root, full), content: readFileSync(full, "utf-8"), lexicon });
104
- }
105
- }
106
-
107
- /** Discover CI files under a repo root. */
108
- export function discoverCiFiles(root: string): AuditInput[] {
109
- const inputs: AuditInput[] = [];
110
- collectDir(root, ".github/workflows", "github", inputs);
111
- collectDir(root, ".forgejo/workflows", "forgejo", inputs);
112
- const gitlab = join(root, ".gitlab-ci.yml");
113
- if (existsSync(gitlab) && statSync(gitlab).isFile()) {
114
- inputs.push({ path: ".gitlab-ci.yml", content: readFileSync(gitlab, "utf-8"), lexicon: "gitlab" });
115
- }
116
- return inputs;
117
- }
118
-
119
- const WALK_SKIP = new Set(["node_modules", ".git", "dist", ".github", ".forgejo"]);
120
- const MAX_WALK_FILES = 1000;
121
-
122
- /** Recursively collect file paths under a root, skipping noise/dot dirs. */
123
- function walkFiles(dir: string, out: string[]): void {
124
- if (out.length >= MAX_WALK_FILES) return;
125
- let entries;
126
- try {
127
- entries = readdirSync(dir, { withFileTypes: true });
128
- } catch {
129
- return;
130
- }
131
- for (const e of entries.sort((a, b) => (a.name < b.name ? -1 : 1))) {
132
- if (out.length >= MAX_WALK_FILES) return;
133
- if (e.name.startsWith(".") && e.isDirectory()) continue;
134
- if (WALK_SKIP.has(e.name)) continue;
135
- const full = join(dir, e.name);
136
- if (e.isDirectory()) walkFiles(full, out);
137
- else out.push(full);
138
- }
139
- }
140
-
141
- function readSafe(full: string): string | undefined {
142
- try {
143
- return readFileSync(full, "utf-8");
144
- } catch {
145
- return undefined;
146
- }
147
- }
148
-
149
- /** True if any YAML document in the content is a Kubernetes manifest. */
150
- function looksLikeK8s(content: string): boolean {
151
- for (const doc of content.split(/\n---\n/)) {
152
- const t = doc.trim();
153
- if (!t) continue;
154
- try {
155
- const obj = parseYAML(t) as Record<string, unknown>;
156
- if (obj && typeof obj.apiVersion === "string" && typeof obj.kind === "string") return true;
157
- } catch {
158
- // not parseable as a single doc — skip
159
- }
160
- }
161
- return false;
162
- }
163
-
164
- /** Discover Kubernetes manifest files under a repo root (content-detected). */
165
- export function discoverManifests(root: string): AuditInput[] {
166
- const files: string[] = [];
167
- walkFiles(root, files);
168
- const inputs: AuditInput[] = [];
169
- for (const full of files) {
170
- if (!isYaml(basename(full))) continue;
171
- const content = readSafe(full);
172
- if (content !== undefined && looksLikeK8s(content)) {
173
- inputs.push({ path: relative(root, full), content, lexicon: "k8s" });
174
- }
175
- }
176
- return inputs;
177
- }
178
-
179
- function isDockerfileName(name: string): boolean {
180
- return name === "Dockerfile" || name.startsWith("Dockerfile.") || name.endsWith(".Dockerfile") || name.endsWith(".dockerfile");
181
- }
182
-
183
- function looksLikeCompose(content: string): boolean {
184
- try {
185
- const obj = parseYAML(content) as Record<string, unknown>;
186
- return Boolean(obj) && typeof obj === "object" && "services" in obj;
187
- } catch {
188
- return false;
189
- }
190
- }
191
-
192
- /** Discover Docker artifacts: Dockerfiles (by name) and Compose files (by `services:`). */
193
- export function discoverDocker(root: string): AuditInput[] {
194
- const files: string[] = [];
195
- walkFiles(root, files);
196
- const inputs: AuditInput[] = [];
197
- for (const full of files) {
198
- const name = basename(full);
199
- const content = readSafe(full);
200
- if (content === undefined) continue;
201
- if (isDockerfileName(name) || (isYaml(name) && looksLikeCompose(content))) {
202
- inputs.push({ path: relative(root, full), content, lexicon: "docker" });
203
- }
204
- }
205
- return inputs;
206
- }
207
-
208
91
  function isMergeWorthy(f: AuditFinding): boolean {
209
92
  return RULE_CATALOG[f.checkId]?.tier === "merge-worthy";
210
93
  }
@@ -240,7 +123,7 @@ function renderStylish(findings: AuditFinding[], scanned: string[], notes: strin
240
123
  const mw = findings.filter(isMergeWorthy);
241
124
  const ro = findings.filter((f) => !isMergeWorthy(f));
242
125
  lines.push(
243
- `Audited ${scanned.length} CI file${scanned.length === 1 ? "" : "s"} — ` +
126
+ `Audited ${scanned.length} file${scanned.length === 1 ? "" : "s"} — ` +
244
127
  `${findings.length} finding${findings.length === 1 ? "" : "s"} ` +
245
128
  `(${mw.length} merge-worthy, ${ro.length} report-only).`,
246
129
  );
@@ -323,12 +206,19 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
323
206
  const isUrl = /^https?:\/\//.test(options.path);
324
207
 
325
208
  let inputs: AuditInput[];
209
+ // Content-detected lexicons whose package isn't installed can't be detected
210
+ // (detection needs the plugin's `detectTemplate`), so a local audit would
211
+ // silently find nothing. Track the missing packages to turn that into a hint.
212
+ let missingHint = "";
326
213
  if (isUrl) {
327
214
  try {
328
- inputs = await fetchCiFiles(options.path, {
215
+ // Fetch the whole repo's candidate files (all lexicons, not just CI) and
216
+ // run them through the same classifier the local path uses (#420).
217
+ const files = await fetchRepoFiles(options.path, {
329
218
  token: options.token ?? tokenForHost(options.path),
330
219
  fetchImpl: options.fetchImpl,
331
220
  });
221
+ inputs = classifyFiles(files, await loadAuditPlugins());
332
222
  } catch (err) {
333
223
  const msg = err instanceof FetchError ? err.message : err instanceof Error ? err.message : String(err);
334
224
  return { success: false, output: "", findings: [], scanned: [], exitCode: 1, error: msg };
@@ -337,13 +227,25 @@ export async function auditCommand(options: AuditCommandOptions): Promise<AuditC
337
227
  if (!existsSync(options.path)) {
338
228
  return { success: false, output: "", findings: [], scanned: [], exitCode: 1, error: `Path not found: ${options.path}` };
339
229
  }
340
- inputs = [...discoverCiFiles(options.path), ...discoverManifests(options.path), ...discoverDocker(options.path)];
230
+ // One walk, plugin-delegated detection. Each lexicon plugin's own
231
+ // `detectTemplate` classifies the files it recognizes; CI (path), Dockerfiles
232
+ // (name), and Helm charts (bundle) are handled by discoverByDetection's
233
+ // special-cases since content shape alone can't disambiguate them.
234
+ const plugins = await loadAuditPlugins();
235
+ const loaded = new Set(plugins.map((p) => p.name));
236
+ const missing = AUDIT_LEXICONS.filter((n) => !loaded.has(n));
237
+ if (missing.length > 0) {
238
+ missingHint =
239
+ ` Some lexicon packages are not installed, so files of those types were not detected: ${missing.join(", ")}.` +
240
+ ` Install what you need, e.g. npm i ${missing.map((n) => `@intentius/chant-lexicon-${n}`).join(" ")}`;
241
+ }
242
+ inputs = discoverByDetection(options.path, plugins);
341
243
  }
342
244
 
343
245
  const scanned = inputs.map((i) => i.path);
344
246
 
345
247
  if (inputs.length === 0) {
346
- return { success: true, output: `No CI files found under ${options.path}.`, findings: [], scanned: [], exitCode: 0 };
248
+ return { success: true, output: `No auditable files found under ${options.path}.${missingHint}`, findings: [], scanned: [], exitCode: 0 };
347
249
  }
348
250
 
349
251
  let findings: AuditFinding[];
@@ -0,0 +1,57 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { boundPropertyTypes, type BoundablePropertyType } from "./bound-property-types";
3
+
4
+ interface Prop {
5
+ name: string;
6
+ tsType: string;
7
+ }
8
+ interface PT extends BoundablePropertyType {
9
+ name: string;
10
+ specType: string;
11
+ properties: Prop[];
12
+ }
13
+
14
+ function pt(name: string, props: Array<[string, string]>): PT {
15
+ return { name, specType: name.split("_")[1] ?? name, properties: props.map(([n, t]) => ({ name: n, tsType: t })) };
16
+ }
17
+
18
+ describe("boundPropertyTypes", () => {
19
+ test("drops property types unreachable from resource props", () => {
20
+ const props: Prop[] = [{ name: "sku", tsType: "R_Sku" }];
21
+ const types = [pt("R_Sku", [["name", "string"]]), pt("R_Unused", [["x", "string"]])];
22
+ const kept = boundPropertyTypes("R", props, types, new Set(), { maxDepth: 2 });
23
+ expect(kept.map((t) => t.name)).toEqual(["R_Sku"]);
24
+ });
25
+
26
+ test("caps nesting depth and loosens references beyond the cap", () => {
27
+ const props: Prop[] = [{ name: "a", tsType: "R_A" }];
28
+ const types = [
29
+ pt("R_A", [["b", "R_B"]]),
30
+ pt("R_B", [["c", "R_C"]]),
31
+ pt("R_C", [["d", "string"]]),
32
+ ];
33
+ const kept = boundPropertyTypes("R", props, types, new Set(), { maxDepth: 1 });
34
+ // depth 1: R_A kept, its child R_B not expanded -> loosened, R_C dropped
35
+ expect(kept.map((t) => t.name)).toEqual(["R_A"]);
36
+ expect(kept[0].properties[0].tsType).toBe("Record<string, unknown>");
37
+ expect(props[0].tsType).toBe("R_A"); // resource prop ref to a kept type is preserved
38
+ });
39
+
40
+ test("force-keeps curated property types by substring regardless of reachability", () => {
41
+ const props: Prop[] = [];
42
+ const types = [pt("R_SecurityRulePropertiesFormat", [["x", "string"]]), pt("R_Other", [["y", "string"]])];
43
+ const kept = boundPropertyTypes("R", props, types, new Set(), {
44
+ maxDepth: 1,
45
+ curatedDefs: ["SecurityRule"],
46
+ });
47
+ expect(kept.map((t) => t.name)).toEqual(["R_SecurityRulePropertiesFormat"]);
48
+ });
49
+
50
+ test("preserves enum references when loosening", () => {
51
+ const props: Prop[] = [{ name: "a", tsType: "R_A" }];
52
+ const types = [pt("R_A", [["mode", "R_ModeEnum"], ["nested", "R_Deep"]]), pt("R_Deep", [["x", "string"]])];
53
+ const kept = boundPropertyTypes("R", props, types, new Set(["R_ModeEnum"]), { maxDepth: 1 });
54
+ expect(kept[0].properties[0].tsType).toBe("R_ModeEnum"); // enum kept
55
+ expect(kept[0].properties[1].tsType).toBe("Record<string, unknown>"); // deep type loosened
56
+ });
57
+ });
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Bound the set of generated property-type interfaces a lexicon emits.
3
+ *
4
+ * Cloud provider schemas (ARM, CloudFormation, …) embed a named definition for
5
+ * every nested object. Fully expanding all of them per-resource produces huge
6
+ * `.d.ts` declarations (azure was ~273MB — see #438). This helper keeps only
7
+ * the property types reachable from a resource's top-level properties within a
8
+ * depth bound, plus a curated force-keep set; references that fall outside the
9
+ * kept set are rewritten to `Record<string, unknown>`. Enum references are
10
+ * preserved. The input property refs are mutated in place. (#438, #440)
11
+ */
12
+
13
+ /** A reference carrying a TypeScript type string, mutated in place when loosened. */
14
+ export interface BoundablePropertyRef {
15
+ tsType: string;
16
+ }
17
+
18
+ /** A generated property type (named interface) and its properties. */
19
+ export interface BoundablePropertyType {
20
+ name: string;
21
+ specType: string;
22
+ properties: BoundablePropertyRef[];
23
+ }
24
+
25
+ export interface BoundPropertyTypeOptions {
26
+ /** Maximum nesting depth of emitted property-type interfaces. */
27
+ maxDepth: number;
28
+ /**
29
+ * Definition-name substrings to always keep regardless of reachability/depth
30
+ * (e.g. common nested shapes worth typing for authoring ergonomics). Matched
31
+ * by substring against each property type's `specType`.
32
+ */
33
+ curatedDefs?: Iterable<string>;
34
+ }
35
+
36
+ function escapeRegExp(s: string): string {
37
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
38
+ }
39
+
40
+ /** Extract `${shortName}_Ident` type-reference tokens from a tsType string. */
41
+ function referencedTypeNames(tsType: string, shortName: string): string[] {
42
+ const re = new RegExp("\\b" + escapeRegExp(shortName) + "_[A-Za-z0-9_]+", "g");
43
+ return tsType.match(re) ?? [];
44
+ }
45
+
46
+ /**
47
+ * Filter `propertyTypes` to the bounded set and loosen out-of-set references.
48
+ * Mutates the `tsType` of `resourceProps` and retained property types; returns
49
+ * the retained property types.
50
+ */
51
+ export function boundPropertyTypes<PT extends BoundablePropertyType>(
52
+ shortName: string,
53
+ resourceProps: BoundablePropertyRef[],
54
+ propertyTypes: PT[],
55
+ enumNames: Set<string>,
56
+ options: BoundPropertyTypeOptions,
57
+ ): PT[] {
58
+ const { maxDepth } = options;
59
+ const curated = options.curatedDefs ? [...options.curatedDefs] : [];
60
+ const byName = new Map(propertyTypes.map((pt) => [pt.name, pt] as const));
61
+ const reached = new Set<string>();
62
+ const queue: Array<{ name: string; depth: number }> = [];
63
+
64
+ const seed = (tsType: string, depth: number) => {
65
+ for (const n of referencedTypeNames(tsType, shortName)) {
66
+ if (byName.has(n) && !reached.has(n)) {
67
+ reached.add(n);
68
+ queue.push({ name: n, depth });
69
+ }
70
+ }
71
+ };
72
+
73
+ for (const p of resourceProps) seed(p.tsType, 1);
74
+ // Force-keep curated property types (depth-1 seeds), matched by substring so
75
+ // schema variant names (e.g. "SecurityRulePropertiesFormat") are retained.
76
+ if (curated.length > 0) {
77
+ for (const pt of propertyTypes) {
78
+ if (!reached.has(pt.name) && curated.some((c) => pt.specType.includes(c))) {
79
+ reached.add(pt.name);
80
+ queue.push({ name: pt.name, depth: 1 });
81
+ }
82
+ }
83
+ }
84
+ while (queue.length) {
85
+ const { name, depth } = queue.shift()!;
86
+ if (depth >= maxDepth) continue; // do not expand children beyond the cap
87
+ const pt = byName.get(name);
88
+ if (!pt) continue;
89
+ for (const p of pt.properties) seed(p.tsType, depth + 1);
90
+ }
91
+
92
+ // Rewrite references to property types we are not emitting (keep enums).
93
+ const loosen = (tsType: string): string => {
94
+ let out = tsType;
95
+ for (const n of referencedTypeNames(tsType, shortName)) {
96
+ if (reached.has(n) || enumNames.has(n) || !byName.has(n)) continue;
97
+ out = out.replace(new RegExp("\\b" + escapeRegExp(n) + "\\b", "g"), "Record<string, unknown>");
98
+ }
99
+ return out;
100
+ };
101
+
102
+ for (const p of resourceProps) p.tsType = loosen(p.tsType);
103
+ const retained: PT[] = [];
104
+ for (const pt of propertyTypes) {
105
+ if (!reached.has(pt.name)) continue;
106
+ for (const p of pt.properties) p.tsType = loosen(p.tsType);
107
+ retained.push(pt);
108
+ }
109
+ return retained;
110
+ }
@@ -0,0 +1,37 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { generatePostSynthBarrel, type BarrelEntry } from "./generate-post-synth-barrel";
3
+
4
+ describe("generatePostSynthBarrel", () => {
5
+ test("emits a DO NOT EDIT banner, static imports, and an id-sorted array", () => {
6
+ const entries: BarrelEntry[] = [
7
+ { module: "./gha021", exportName: "gha021", id: "GHA021" },
8
+ { module: "./apt-no-recommends", exportName: "dkrd010", id: "DKRD010" },
9
+ { module: "./gha006", exportName: "gha006", id: "GHA006" },
10
+ ];
11
+ const out = generatePostSynthBarrel(entries);
12
+
13
+ expect(out).toContain("// Code generated by chant generate. DO NOT EDIT.");
14
+ expect(out).toContain('import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";');
15
+ // Export name may differ from the module name (docker/helm/temporal).
16
+ expect(out).toContain('import { dkrd010 } from "./apt-no-recommends";');
17
+ // Array is ordered by id, not insertion order.
18
+ const arrayBody = out.slice(out.indexOf("postSynthChecks: PostSynthCheck[] = ["));
19
+ expect(arrayBody.indexOf("dkrd010")).toBeLessThan(arrayBody.indexOf("gha006"));
20
+ expect(arrayBody.indexOf("gha006")).toBeLessThan(arrayBody.indexOf("gha021"));
21
+ });
22
+
23
+ test("is deterministic regardless of input order", () => {
24
+ const a: BarrelEntry[] = [
25
+ { module: "./b", exportName: "b", id: "X2" },
26
+ { module: "./a", exportName: "a", id: "X1" },
27
+ ];
28
+ const b = [...a].reverse();
29
+ expect(generatePostSynthBarrel(a)).toBe(generatePostSynthBarrel(b));
30
+ });
31
+
32
+ test("empty input yields an empty array, still valid", () => {
33
+ const out = generatePostSynthBarrel([]);
34
+ expect(out).toContain("export const postSynthChecks: PostSynthCheck[] = [");
35
+ expect(out).toContain("];");
36
+ });
37
+ });
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Generate a static, importable barrel of a lexicon's post-synth checks.
3
+ *
4
+ * The runtime loader (`discoverPostSynthChecks`) readdir-globs the directory and
5
+ * `require()`s each file via tsx — fs- and tsx-coupled, so it can't run in a
6
+ * bundle or on an edge runtime (Cloudflare Workers). This generator produces a
7
+ * committed `lint/post-synth/index.ts` with explicit static imports + an exported
8
+ * `postSynthChecks` array, which bundlers can follow with no fs/tsx/require. See #409.
9
+ *
10
+ * Detection reuses the runtime's own `isPostSynthCheck`, so the barrel contains
11
+ * exactly the checks discovery would — including files whose export name differs
12
+ * from the filename (docker/helm/temporal) and excluding helper modules
13
+ * (cf-refs, arm-refs, …) that export no check.
14
+ */
15
+
16
+ import { createRequire } from "module";
17
+ import { listRuleFiles } from "../lint/discover";
18
+ import { isPostSynthCheck } from "../lint/post-synth";
19
+
20
+ export interface BarrelEntry {
21
+ /** Module specifier relative to the barrel, e.g. "./gha021" or "./apt-no-recommends". */
22
+ module: string;
23
+ /** Exported binding holding the check, e.g. "gha021" or "dkrd010". */
24
+ exportName: string;
25
+ /** The check's id (e.g. "GHA021"), used for stable ordering. */
26
+ id: string;
27
+ }
28
+
29
+ /**
30
+ * Scan a post-synth directory and return one entry per exported check.
31
+ * Runs at codegen time on Node (tsx-powered require), never in the shipped path.
32
+ */
33
+ export function scanPostSynthChecks(dir: string, importMetaUrl: string): BarrelEntry[] {
34
+ const require = createRequire(importMetaUrl);
35
+ const entries: BarrelEntry[] = [];
36
+ for (const file of listRuleFiles(dir)) {
37
+ const base = file.replace(/\.ts$/, "");
38
+ let mod: Record<string, unknown>;
39
+ try {
40
+ mod = require(`${dir}/${base}`) as Record<string, unknown>;
41
+ } catch {
42
+ continue; // a file that fails to load contributes nothing
43
+ }
44
+ for (const [exportName, value] of Object.entries(mod)) {
45
+ if (isPostSynthCheck(value)) {
46
+ entries.push({ module: `./${base}`, exportName, id: value.id });
47
+ }
48
+ }
49
+ }
50
+ return entries;
51
+ }
52
+
53
+ /** Render the barrel file content from scanned entries (pure — easy to unit test). */
54
+ export function generatePostSynthBarrel(entries: BarrelEntry[]): string {
55
+ const sorted = [...entries].sort((a, b) => a.id.localeCompare(b.id));
56
+ const lines: string[] = [];
57
+ lines.push("// Code generated by chant generate. DO NOT EDIT.");
58
+ lines.push('import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";');
59
+ for (const e of sorted) {
60
+ lines.push(`import { ${e.exportName} } from ${JSON.stringify(e.module)};`);
61
+ }
62
+ lines.push("");
63
+ lines.push("export const postSynthChecks: PostSynthCheck[] = [");
64
+ for (const e of sorted) {
65
+ lines.push(` ${e.exportName},`);
66
+ }
67
+ lines.push("];");
68
+ lines.push("");
69
+ return lines.join("\n");
70
+ }
71
+
72
+ /** Scan a directory and render its barrel in one step. */
73
+ export function renderPostSynthBarrelForDir(dir: string, importMetaUrl: string): string {
74
+ return generatePostSynthBarrel(scanPostSynthChecks(dir, importMetaUrl));
75
+ }