@intentius/chant 0.79.0 → 0.81.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 (462) hide show
  1. package/dist/audit/core.d.ts.map +1 -1
  2. package/dist/audit/discover.d.ts +30 -0
  3. package/dist/audit/discover.d.ts.map +1 -1
  4. package/dist/audit/report-html.d.ts +5 -0
  5. package/dist/audit/report-html.d.ts.map +1 -1
  6. package/dist/audit/report-model.d.ts +13 -0
  7. package/dist/audit/report-model.d.ts.map +1 -1
  8. package/dist/audit/terraform-state.d.ts +13 -0
  9. package/dist/audit/terraform-state.d.ts.map +1 -1
  10. package/dist/cli/command-group.d.ts +6 -0
  11. package/dist/cli/command-group.d.ts.map +1 -1
  12. package/dist/cli/commands/audit.d.ts +44 -3
  13. package/dist/cli/commands/audit.d.ts.map +1 -1
  14. package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
  15. package/dist/cli/commands/check-lexicon.d.ts +8 -0
  16. package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
  17. package/dist/cli/commands/doctor.d.ts.map +1 -1
  18. package/dist/cli/commands/import-agents.d.ts.map +1 -1
  19. package/dist/cli/commands/init.d.ts +6 -0
  20. package/dist/cli/commands/init.d.ts.map +1 -1
  21. package/dist/cli/commands/lint.d.ts.map +1 -1
  22. package/dist/cli/commands/onboard.d.ts.map +1 -1
  23. package/dist/cli/commands/update.d.ts +6 -0
  24. package/dist/cli/commands/update.d.ts.map +1 -1
  25. package/dist/cli/commands/vendor.d.ts +5 -0
  26. package/dist/cli/commands/vendor.d.ts.map +1 -1
  27. package/dist/cli/conflict-check.d.ts +6 -0
  28. package/dist/cli/conflict-check.d.ts.map +1 -1
  29. package/dist/cli/handlers/build.d.ts.map +1 -1
  30. package/dist/cli/handlers/components.d.ts.map +1 -1
  31. package/dist/cli/handlers/dev.d.ts.map +1 -1
  32. package/dist/cli/handlers/fan-out.d.ts.map +1 -1
  33. package/dist/cli/handlers/init.d.ts.map +1 -1
  34. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  35. package/dist/cli/handlers/misc.d.ts.map +1 -1
  36. package/dist/cli/handlers/operator.d.ts +7 -0
  37. package/dist/cli/handlers/operator.d.ts.map +1 -1
  38. package/dist/cli/handlers/promote.d.ts +20 -0
  39. package/dist/cli/handlers/promote.d.ts.map +1 -0
  40. package/dist/cli/handlers/run-generate.d.ts +39 -0
  41. package/dist/cli/handlers/run-generate.d.ts.map +1 -0
  42. package/dist/cli/handlers/run.d.ts +4 -1
  43. package/dist/cli/handlers/run.d.ts.map +1 -1
  44. package/dist/cli/handlers/vendor.d.ts +8 -3
  45. package/dist/cli/handlers/vendor.d.ts.map +1 -1
  46. package/dist/cli/main.d.ts +12 -0
  47. package/dist/cli/main.d.ts.map +1 -1
  48. package/dist/cli/mcp/op-tools.d.ts.map +1 -1
  49. package/dist/cli/plugins.d.ts +14 -0
  50. package/dist/cli/plugins.d.ts.map +1 -1
  51. package/dist/cli/registry.d.ts +46 -1
  52. package/dist/cli/registry.d.ts.map +1 -1
  53. package/dist/codegen/fetch.d.ts +10 -0
  54. package/dist/codegen/fetch.d.ts.map +1 -1
  55. package/dist/components/capability-plugin-loader.d.ts.map +1 -1
  56. package/dist/components/cli-support.d.ts +3 -1
  57. package/dist/components/cli-support.d.ts.map +1 -1
  58. package/dist/components/discover.d.ts.map +1 -1
  59. package/dist/components/driver.d.ts +16 -2
  60. package/dist/components/driver.d.ts.map +1 -1
  61. package/dist/components/fan-out-support.d.ts.map +1 -1
  62. package/dist/components/gate-plan.d.ts +40 -0
  63. package/dist/components/gate-plan.d.ts.map +1 -0
  64. package/dist/components/pilots/alb-ecs.pilot.d.ts +7 -1
  65. package/dist/components/pilots/alb-ecs.pilot.d.ts.map +1 -1
  66. package/dist/components/presets/ecs-fargate.d.ts +10 -4
  67. package/dist/components/presets/ecs-fargate.d.ts.map +1 -1
  68. package/dist/components/promote.d.ts +264 -0
  69. package/dist/components/promote.d.ts.map +1 -0
  70. package/dist/components/sandbox/driver.d.ts.map +1 -1
  71. package/dist/components/sandbox/run.d.ts.map +1 -1
  72. package/dist/components/verbs/build-archive.d.ts +22 -11
  73. package/dist/components/verbs/build-archive.d.ts.map +1 -1
  74. package/dist/components/verbs/run-agent.d.ts.map +1 -1
  75. package/dist/config-static.d.ts +59 -0
  76. package/dist/config-static.d.ts.map +1 -0
  77. package/dist/config.d.ts +104 -5
  78. package/dist/config.d.ts.map +1 -1
  79. package/dist/content-digest.d.ts +17 -0
  80. package/dist/content-digest.d.ts.map +1 -0
  81. package/dist/discovery/files.d.ts +48 -4
  82. package/dist/discovery/files.d.ts.map +1 -1
  83. package/dist/discovery/fold-import.d.ts +32 -1
  84. package/dist/discovery/fold-import.d.ts.map +1 -1
  85. package/dist/discovery/index.d.ts.map +1 -1
  86. package/dist/discovery/sandbox/driver.d.ts +20 -0
  87. package/dist/discovery/sandbox/driver.d.ts.map +1 -1
  88. package/dist/discovery/sandbox/fork.d.ts +20 -0
  89. package/dist/discovery/sandbox/fork.d.ts.map +1 -1
  90. package/dist/discovery/walk.d.ts +119 -0
  91. package/dist/discovery/walk.d.ts.map +1 -0
  92. package/dist/graph-ir.d.ts +17 -1
  93. package/dist/graph-ir.d.ts.map +1 -1
  94. package/dist/join-key.d.ts +31 -0
  95. package/dist/join-key.d.ts.map +1 -0
  96. package/dist/lexicon-module.d.ts +110 -0
  97. package/dist/lexicon-module.d.ts.map +1 -0
  98. package/dist/lexicon.d.ts +82 -1
  99. package/dist/lexicon.d.ts.map +1 -1
  100. package/dist/lifecycle/build-ledger-store.d.ts.map +1 -1
  101. package/dist/lifecycle/digest.d.ts +5 -1
  102. package/dist/lifecycle/digest.d.ts.map +1 -1
  103. package/dist/lifecycle/gate-ledger.d.ts +20 -5
  104. package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
  105. package/dist/lifecycle/git.d.ts +64 -0
  106. package/dist/lifecycle/git.d.ts.map +1 -1
  107. package/dist/lifecycle/lease.d.ts +8 -1
  108. package/dist/lifecycle/lease.d.ts.map +1 -1
  109. package/dist/lifecycle/legacy-digest.d.ts +59 -0
  110. package/dist/lifecycle/legacy-digest.d.ts.map +1 -0
  111. package/dist/lifecycle/member-ledger.d.ts +67 -0
  112. package/dist/lifecycle/member-ledger.d.ts.map +1 -0
  113. package/dist/lifecycle/plan-digest.d.ts +4 -3
  114. package/dist/lifecycle/plan-digest.d.ts.map +1 -1
  115. package/dist/lifecycle/release-ledger.d.ts +42 -1
  116. package/dist/lifecycle/release-ledger.d.ts.map +1 -1
  117. package/dist/lifecycle/status.d.ts +90 -5
  118. package/dist/lifecycle/status.d.ts.map +1 -1
  119. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts +2 -3
  120. package/dist/lint/rules/comp/comp003-mutating-no-rollback.d.ts.map +1 -1
  121. package/dist/op/activities/activity-contracts.d.ts +32 -0
  122. package/dist/op/activities/activity-contracts.d.ts.map +1 -1
  123. package/dist/op/activities/index.d.ts +2 -0
  124. package/dist/op/activities/index.d.ts.map +1 -1
  125. package/dist/op/activities/propose-upgrade.d.ts +75 -0
  126. package/dist/op/activities/propose-upgrade.d.ts.map +1 -0
  127. package/dist/op/activity-contract-registry.d.ts.map +1 -1
  128. package/dist/op/activity-registry.d.ts.map +1 -1
  129. package/dist/op/discover.d.ts.map +1 -1
  130. package/dist/op/gate-approval.d.ts.map +1 -1
  131. package/dist/op/gate-name.d.ts +7 -0
  132. package/dist/op/gate-name.d.ts.map +1 -1
  133. package/dist/op/gate-summary.d.ts +16 -0
  134. package/dist/op/gate-summary.d.ts.map +1 -1
  135. package/dist/op/gate.d.ts +16 -2
  136. package/dist/op/gate.d.ts.map +1 -1
  137. package/dist/op/generate-pipeline.d.ts.map +1 -1
  138. package/dist/op/runtimes/local.d.ts.map +1 -1
  139. package/dist/project-root.d.ts +26 -0
  140. package/dist/project-root.d.ts.map +1 -1
  141. package/dist/workspace/__fixtures__/contract-repo.d.ts +37 -0
  142. package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -0
  143. package/dist/workspace/__fixtures__/two-member-workspace.d.ts +11 -0
  144. package/dist/workspace/__fixtures__/two-member-workspace.d.ts.map +1 -0
  145. package/dist/workspace/checks/generated.d.ts +156 -0
  146. package/dist/workspace/checks/generated.d.ts.map +1 -0
  147. package/dist/workspace/checks/ledgers.d.ts +78 -0
  148. package/dist/workspace/checks/ledgers.d.ts.map +1 -0
  149. package/dist/workspace/checks/links.d.ts +25 -0
  150. package/dist/workspace/checks/links.d.ts.map +1 -0
  151. package/dist/workspace/checks/pipelines.d.ts +76 -0
  152. package/dist/workspace/checks/pipelines.d.ts.map +1 -0
  153. package/dist/workspace/checks.d.ts +161 -0
  154. package/dist/workspace/checks.d.ts.map +1 -0
  155. package/dist/workspace/compose-graph.d.ts +115 -0
  156. package/dist/workspace/compose-graph.d.ts.map +1 -0
  157. package/dist/workspace/compose-reports.d.ts +68 -0
  158. package/dist/workspace/compose-reports.d.ts.map +1 -0
  159. package/dist/workspace/declaration.d.ts +220 -0
  160. package/dist/workspace/declaration.d.ts.map +1 -0
  161. package/dist/workspace/declaration.schema.json +434 -0
  162. package/dist/workspace/generated-files.d.ts +65 -0
  163. package/dist/workspace/generated-files.d.ts.map +1 -0
  164. package/dist/workspace/glob.d.ts +13 -0
  165. package/dist/workspace/glob.d.ts.map +1 -0
  166. package/dist/workspace/graph-cli.d.ts +75 -0
  167. package/dist/workspace/graph-cli.d.ts.map +1 -0
  168. package/dist/workspace/init.d.ts +96 -0
  169. package/dist/workspace/init.d.ts.map +1 -0
  170. package/dist/workspace/jsonc.d.ts +38 -0
  171. package/dist/workspace/jsonc.d.ts.map +1 -0
  172. package/dist/workspace/kinds.d.ts +192 -0
  173. package/dist/workspace/kinds.d.ts.map +1 -0
  174. package/dist/workspace/lineage-check.d.ts +84 -0
  175. package/dist/workspace/lineage-check.d.ts.map +1 -0
  176. package/dist/workspace/lineage-cli.d.ts +31 -0
  177. package/dist/workspace/lineage-cli.d.ts.map +1 -0
  178. package/dist/workspace/lineage-init.d.ts +101 -0
  179. package/dist/workspace/lineage-init.d.ts.map +1 -0
  180. package/dist/workspace/lineage-lock.d.ts +258 -0
  181. package/dist/workspace/lineage-lock.d.ts.map +1 -0
  182. package/dist/workspace/lineage-merge.d.ts +14 -0
  183. package/dist/workspace/lineage-merge.d.ts.map +1 -0
  184. package/dist/workspace/lineage-migrations.d.ts +178 -0
  185. package/dist/workspace/lineage-migrations.d.ts.map +1 -0
  186. package/dist/workspace/lineage-update.d.ts +59 -0
  187. package/dist/workspace/lineage-update.d.ts.map +1 -0
  188. package/dist/workspace/lineage-upgrade-cli.d.ts +40 -0
  189. package/dist/workspace/lineage-upgrade-cli.d.ts.map +1 -0
  190. package/dist/workspace/lineage-upgrade.d.ts +146 -0
  191. package/dist/workspace/lineage-upgrade.d.ts.map +1 -0
  192. package/dist/workspace/lineage-vendor.d.ts +63 -0
  193. package/dist/workspace/lineage-vendor.d.ts.map +1 -0
  194. package/dist/workspace/lineage-version.d.ts +32 -0
  195. package/dist/workspace/lineage-version.d.ts.map +1 -0
  196. package/dist/workspace/links.d.ts +150 -0
  197. package/dist/workspace/links.d.ts.map +1 -0
  198. package/dist/workspace/ls.d.ts +99 -0
  199. package/dist/workspace/ls.d.ts.map +1 -0
  200. package/dist/workspace/member-commands.d.ts +139 -0
  201. package/dist/workspace/member-commands.d.ts.map +1 -0
  202. package/dist/workspace/member-handles.d.ts +54 -0
  203. package/dist/workspace/member-handles.d.ts.map +1 -0
  204. package/dist/workspace/member-pipeline.d.ts +143 -0
  205. package/dist/workspace/member-pipeline.d.ts.map +1 -0
  206. package/dist/workspace/member-run.d.ts +67 -0
  207. package/dist/workspace/member-run.d.ts.map +1 -0
  208. package/dist/workspace/reason-codes.d.ts +65 -0
  209. package/dist/workspace/reason-codes.d.ts.map +1 -0
  210. package/dist/workspace/record-source.d.ts +22 -0
  211. package/dist/workspace/record-source.d.ts.map +1 -0
  212. package/dist/workspace/records-cli.d.ts +81 -0
  213. package/dist/workspace/records-cli.d.ts.map +1 -0
  214. package/dist/workspace/records.d.ts +118 -0
  215. package/dist/workspace/records.d.ts.map +1 -0
  216. package/dist/workspace/root-refusal.d.ts +53 -0
  217. package/dist/workspace/root-refusal.d.ts.map +1 -0
  218. package/dist/workspace/status.d.ts +150 -0
  219. package/dist/workspace/status.d.ts.map +1 -0
  220. package/dist/workspace/template-manifest.d.ts +90 -0
  221. package/dist/workspace/template-manifest.d.ts.map +1 -0
  222. package/dist/workspace/tree.d.ts +36 -0
  223. package/dist/workspace/tree.d.ts.map +1 -0
  224. package/dist/workspace/trust/attestor.d.ts +67 -0
  225. package/dist/workspace/trust/attestor.d.ts.map +1 -0
  226. package/dist/workspace/trust/policy.d.ts +111 -0
  227. package/dist/workspace/trust/policy.d.ts.map +1 -0
  228. package/dist/workspace/trust/provenance.d.ts +67 -0
  229. package/dist/workspace/trust/provenance.d.ts.map +1 -0
  230. package/dist/workspace/trust/ssh-commit.d.ts +43 -0
  231. package/dist/workspace/trust/ssh-commit.d.ts.map +1 -0
  232. package/dist/workspace/trust/test-repo.d.ts +42 -0
  233. package/dist/workspace/trust/test-repo.d.ts.map +1 -0
  234. package/dist/workspace/trust/verify-cli.d.ts +9 -0
  235. package/dist/workspace/trust/verify-cli.d.ts.map +1 -0
  236. package/dist/workspace/trust/verify.d.ts +66 -0
  237. package/dist/workspace/trust/verify.d.ts.map +1 -0
  238. package/dist/workspace/which-chant.d.ts +58 -0
  239. package/dist/workspace/which-chant.d.ts.map +1 -0
  240. package/dist/workspace/workspace-kinds.schema.json +133 -0
  241. package/package.json +4 -3
  242. package/src/audit/core.ts +13 -2
  243. package/src/audit/discover.ts +102 -36
  244. package/src/audit/report-html.ts +3 -1
  245. package/src/audit/report-model.ts +14 -1
  246. package/src/audit/terraform-state.test.ts +81 -1
  247. package/src/audit/terraform-state.ts +25 -0
  248. package/src/cli/command-group.ts +7 -0
  249. package/src/cli/commands/audit-truncation.test.ts +167 -0
  250. package/src/cli/commands/audit.ts +132 -29
  251. package/src/cli/commands/check-lexicon-examples.ts +2 -1
  252. package/src/cli/commands/check-lexicon.ts +24 -0
  253. package/src/cli/commands/doctor.test.ts +30 -0
  254. package/src/cli/commands/doctor.ts +21 -0
  255. package/src/cli/commands/import-agents.ts +15 -4
  256. package/src/cli/commands/init.ts +76 -25
  257. package/src/cli/commands/lint.test.ts +52 -1
  258. package/src/cli/commands/lint.ts +41 -71
  259. package/src/cli/commands/onboard.ts +15 -0
  260. package/src/cli/commands/update.ts +18 -5
  261. package/src/cli/commands/vendor.ts +11 -6
  262. package/src/cli/conflict-check.test.ts +18 -1
  263. package/src/cli/conflict-check.ts +13 -0
  264. package/src/cli/discovery-skip.test.ts +168 -0
  265. package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +38 -0
  266. package/src/cli/handlers/build-member.test.ts +127 -0
  267. package/src/cli/handlers/build.test.ts +11 -0
  268. package/src/cli/handlers/build.ts +35 -1
  269. package/src/cli/handlers/components.test.ts +127 -0
  270. package/src/cli/handlers/components.ts +70 -8
  271. package/src/cli/handlers/dev.ts +6 -1
  272. package/src/cli/handlers/fan-out.ts +9 -2
  273. package/src/cli/handlers/graph.test.ts +20 -0
  274. package/src/cli/handlers/graph.ts +4 -2
  275. package/src/cli/handlers/init.ts +54 -1
  276. package/src/cli/handlers/lifecycle.ts +2 -1
  277. package/src/cli/handlers/misc.ts +16 -0
  278. package/src/cli/handlers/operator.test.ts +68 -0
  279. package/src/cli/handlers/operator.ts +39 -10
  280. package/src/cli/handlers/promote.test.ts +377 -0
  281. package/src/cli/handlers/promote.ts +391 -0
  282. package/src/cli/handlers/run-generate-member.test.ts +83 -0
  283. package/src/cli/handlers/run-generate.test.ts +158 -0
  284. package/src/cli/handlers/run-generate.ts +168 -0
  285. package/src/cli/handlers/run.test.ts +47 -0
  286. package/src/cli/handlers/run.ts +41 -6
  287. package/src/cli/handlers/vendor.ts +147 -43
  288. package/src/cli/main.test.ts +137 -1
  289. package/src/cli/main.ts +290 -24
  290. package/src/cli/mcp/op-tools.ts +2 -1
  291. package/src/cli/path-lexicon-messages.test.ts +152 -0
  292. package/src/cli/plugins.ts +43 -5
  293. package/src/cli/registry.ts +46 -1
  294. package/src/cli/static-config-read.test.ts +208 -0
  295. package/src/codegen/fetch.test.ts +63 -1
  296. package/src/codegen/fetch.ts +30 -1
  297. package/src/components/__fixtures__/alb-ecs-service.json +0 -8
  298. package/src/components/capability-plugin-loader.ts +3 -1
  299. package/src/components/cli-support.ts +9 -3
  300. package/src/components/discover.test.ts +27 -57
  301. package/src/components/discover.ts +20 -51
  302. package/src/components/driver.test.ts +90 -12
  303. package/src/components/driver.ts +43 -5
  304. package/src/components/fan-out-support.ts +2 -1
  305. package/src/components/gate-plan.ts +53 -0
  306. package/src/components/pilots/README.md +1 -1
  307. package/src/components/pilots/alb-ecs.pilot.ts +7 -7
  308. package/src/components/presets/ecs-fargate.ts +10 -5
  309. package/src/components/promote.test.ts +645 -0
  310. package/src/components/promote.ts +641 -0
  311. package/src/components/sandbox/driver.ts +8 -8
  312. package/src/components/sandbox/run.ts +4 -1
  313. package/src/components/verbs/build-archive.ts +27 -21
  314. package/src/components/verbs/run-agent.ts +3 -5
  315. package/src/config-static.test.ts +136 -0
  316. package/src/config-static.ts +232 -0
  317. package/src/config.test.ts +40 -0
  318. package/src/config.ts +161 -11
  319. package/src/content-digest.test.ts +120 -0
  320. package/src/content-digest.ts +21 -0
  321. package/src/discovery/files.test.ts +127 -1
  322. package/src/discovery/files.ts +91 -59
  323. package/src/discovery/fold-import.ts +127 -9
  324. package/src/discovery/index.ts +1 -0
  325. package/src/discovery/sandbox/driver.ts +73 -35
  326. package/src/discovery/sandbox/fork-diagnostic.test.ts +136 -13
  327. package/src/discovery/sandbox/fork.ts +83 -43
  328. package/src/discovery/sandbox/path-lexicon-multifile.test.ts +285 -0
  329. package/src/discovery/sandbox/path-lexicon-parity.test.ts +162 -0
  330. package/src/discovery/walk.test.ts +263 -0
  331. package/src/discovery/walk.ts +334 -0
  332. package/src/effect-receipt.ts +2 -2
  333. package/src/graph-ir.ts +18 -1
  334. package/src/join-key.test.ts +25 -0
  335. package/src/join-key.ts +39 -0
  336. package/src/lexicon-module.test.ts +203 -0
  337. package/src/lexicon-module.ts +215 -0
  338. package/src/lexicon.ts +105 -1
  339. package/src/lifecycle/build-ledger-store.ts +13 -2
  340. package/src/lifecycle/digest.ts +9 -5
  341. package/src/lifecycle/gate-ledger.test.ts +20 -0
  342. package/src/lifecycle/gate-ledger.ts +28 -6
  343. package/src/lifecycle/git.test.ts +13 -1
  344. package/src/lifecycle/git.ts +221 -176
  345. package/src/lifecycle/lease.ts +25 -10
  346. package/src/lifecycle/legacy-digest.test.ts +206 -0
  347. package/src/lifecycle/legacy-digest.ts +103 -0
  348. package/src/lifecycle/member-ledger.test.ts +319 -0
  349. package/src/lifecycle/member-ledger.ts +145 -0
  350. package/src/lifecycle/plan-digest.ts +7 -7
  351. package/src/lifecycle/release-ledger.test.ts +20 -0
  352. package/src/lifecycle/release-ledger.ts +53 -3
  353. package/src/lifecycle/status.test.ts +151 -1
  354. package/src/lifecycle/status.ts +228 -7
  355. package/src/lint/rules/comp/comp003-mutating-no-rollback.ts +2 -3
  356. package/src/op/activities/activity-contracts.ts +37 -0
  357. package/src/op/activities/index.ts +10 -0
  358. package/src/op/activities/propose-upgrade.ts +206 -0
  359. package/src/op/activity-contract-registry.ts +18 -4
  360. package/src/op/activity-registry.ts +26 -0
  361. package/src/op/discover.test.ts +14 -4
  362. package/src/op/discover.ts +19 -23
  363. package/src/op/gate-approval.ts +3 -1
  364. package/src/op/gate-name.ts +8 -0
  365. package/src/op/gate-summary.test.ts +14 -0
  366. package/src/op/gate-summary.ts +25 -2
  367. package/src/op/gate.ts +36 -7
  368. package/src/op/generate-pipeline.test.ts +14 -5
  369. package/src/op/generate-pipeline.ts +2 -1
  370. package/src/op/runtimes/local.ts +2 -1
  371. package/src/project-root.test.ts +66 -1
  372. package/src/project-root.ts +48 -0
  373. package/src/workspace/__fixtures__/contract-repo.ts +100 -0
  374. package/src/workspace/__fixtures__/two-member-workspace.ts +35 -0
  375. package/src/workspace/behold-kinds.test.ts +162 -0
  376. package/src/workspace/check-contract.test.ts +127 -0
  377. package/src/workspace/check.schema.json +347 -0
  378. package/src/workspace/checks/generated.test.ts +287 -0
  379. package/src/workspace/checks/generated.ts +475 -0
  380. package/src/workspace/checks/ledgers.test.ts +139 -0
  381. package/src/workspace/checks/ledgers.ts +246 -0
  382. package/src/workspace/checks/links.ts +183 -0
  383. package/src/workspace/checks/pipelines.test.ts +133 -0
  384. package/src/workspace/checks/pipelines.ts +225 -0
  385. package/src/workspace/checks-repo.test.ts +71 -0
  386. package/src/workspace/checks.test.ts +450 -0
  387. package/src/workspace/checks.ts +461 -0
  388. package/src/workspace/compose-graph.test.ts +146 -0
  389. package/src/workspace/compose-graph.ts +228 -0
  390. package/src/workspace/compose-reports.test.ts +109 -0
  391. package/src/workspace/compose-reports.ts +186 -0
  392. package/src/workspace/declaration.schema.json +434 -0
  393. package/src/workspace/declaration.test.ts +347 -0
  394. package/src/workspace/declaration.ts +623 -0
  395. package/src/workspace/generated-files.test.ts +114 -0
  396. package/src/workspace/generated-files.ts +94 -0
  397. package/src/workspace/glob.ts +49 -0
  398. package/src/workspace/graph-cli.ts +220 -0
  399. package/src/workspace/graph-contract.test.ts +204 -0
  400. package/src/workspace/graph.schema.json +662 -0
  401. package/src/workspace/init.test.ts +223 -0
  402. package/src/workspace/init.ts +585 -0
  403. package/src/workspace/jsonc.test.ts +65 -0
  404. package/src/workspace/jsonc.ts +231 -0
  405. package/src/workspace/kinds.test.ts +288 -0
  406. package/src/workspace/kinds.ts +506 -0
  407. package/src/workspace/lineage-check.ts +264 -0
  408. package/src/workspace/lineage-cli.ts +114 -0
  409. package/src/workspace/lineage-init.test.ts +231 -0
  410. package/src/workspace/lineage-init.ts +365 -0
  411. package/src/workspace/lineage-lock.test.ts +224 -0
  412. package/src/workspace/lineage-lock.ts +357 -0
  413. package/src/workspace/lineage-merge.ts +44 -0
  414. package/src/workspace/lineage-migrations.test.ts +178 -0
  415. package/src/workspace/lineage-migrations.ts +343 -0
  416. package/src/workspace/lineage-update.ts +160 -0
  417. package/src/workspace/lineage-upgrade-cli.ts +151 -0
  418. package/src/workspace/lineage-upgrade.test.ts +474 -0
  419. package/src/workspace/lineage-upgrade.ts +624 -0
  420. package/src/workspace/lineage-vendor.test.ts +126 -0
  421. package/src/workspace/lineage-vendor.ts +215 -0
  422. package/src/workspace/lineage-version.ts +127 -0
  423. package/src/workspace/links.test.ts +344 -0
  424. package/src/workspace/links.ts +331 -0
  425. package/src/workspace/ls-contract.test.ts +200 -0
  426. package/src/workspace/ls.schema.json +190 -0
  427. package/src/workspace/ls.ts +254 -0
  428. package/src/workspace/member-commands.e2e.test.ts +244 -0
  429. package/src/workspace/member-commands.test.ts +217 -0
  430. package/src/workspace/member-commands.ts +540 -0
  431. package/src/workspace/member-handles.test.ts +76 -0
  432. package/src/workspace/member-handles.ts +228 -0
  433. package/src/workspace/member-pipeline.test.ts +135 -0
  434. package/src/workspace/member-pipeline.ts +317 -0
  435. package/src/workspace/member-run.ts +146 -0
  436. package/src/workspace/read-contract.test.ts +129 -0
  437. package/src/workspace/reason-codes.test.ts +113 -0
  438. package/src/workspace/reason-codes.ts +81 -0
  439. package/src/workspace/record-source.ts +117 -0
  440. package/src/workspace/records-cli.ts +198 -0
  441. package/src/workspace/records-contract.test.ts +93 -0
  442. package/src/workspace/records.schema.json +150 -0
  443. package/src/workspace/records.test.ts +243 -0
  444. package/src/workspace/records.ts +384 -0
  445. package/src/workspace/root-refusal.ts +97 -0
  446. package/src/workspace/status-contract.test.ts +308 -0
  447. package/src/workspace/status.schema.json +210 -0
  448. package/src/workspace/status.ts +412 -0
  449. package/src/workspace/template-manifest.test.ts +79 -0
  450. package/src/workspace/template-manifest.ts +221 -0
  451. package/src/workspace/tree.ts +132 -0
  452. package/src/workspace/trust/attestor.ts +93 -0
  453. package/src/workspace/trust/policy.ts +306 -0
  454. package/src/workspace/trust/provenance.ts +181 -0
  455. package/src/workspace/trust/ssh-commit.ts +138 -0
  456. package/src/workspace/trust/test-repo.ts +138 -0
  457. package/src/workspace/trust/trust.test.ts +397 -0
  458. package/src/workspace/trust/verify-cli.ts +56 -0
  459. package/src/workspace/trust/verify.ts +194 -0
  460. package/src/workspace/which-chant.test.ts +117 -0
  461. package/src/workspace/which-chant.ts +151 -0
  462. package/src/workspace/workspace-kinds.schema.json +133 -0
@@ -129,6 +129,12 @@ export interface AuditReportJson {
129
129
  findings: SerializedFinding[];
130
130
  /** Candidate files that looked like they wanted a lexicon that is not installed. */
131
131
  unclaimed?: UnclaimedFile[];
132
+ /**
133
+ * Present when the local walk stopped at its file limit with files left
134
+ * unread (#2528): the limit, and the flag that raises it. Absent for a whole
135
+ * scan and for a repository URL.
136
+ */
137
+ truncated?: { limit: number; flag: string };
132
138
  }
133
139
 
134
140
  export function metaFor(id: string, catalog: Record<string, RuleMeta> = RULE_CATALOG): RuleMeta {
@@ -298,7 +304,13 @@ export function buildReportModel(findings: AuditFinding[], opts: BuildModelOptio
298
304
  /** Build the versioned, machine-readable JSON report (stable contract). */
299
305
  export function buildReportJson(
300
306
  findings: AuditFinding[],
301
- opts: { snapshot?: AuditSnapshot; toolVersion?: string; catalog?: Record<string, RuleMeta>; unclaimed?: UnclaimedFile[] } = {},
307
+ opts: {
308
+ snapshot?: AuditSnapshot;
309
+ toolVersion?: string;
310
+ catalog?: Record<string, RuleMeta>;
311
+ unclaimed?: UnclaimedFile[];
312
+ truncated?: { limit: number; flag: string };
313
+ } = {},
302
314
  ): AuditReportJson {
303
315
  const model = buildReportModel(findings, { catalog: opts.catalog });
304
316
  const version = opts.toolVersion ?? opts.snapshot?.toolVersion ?? "0.0.0";
@@ -328,5 +340,6 @@ export function buildReportJson(
328
340
  docUrl: ruleDocUrl(f.checkId),
329
341
  })),
330
342
  unclaimed: opts.unclaimed && opts.unclaimed.length > 0 ? opts.unclaimed : undefined,
343
+ truncated: opts.truncated,
331
344
  };
332
345
  }
@@ -8,9 +8,10 @@ import {
8
8
  isTerraformStateFile,
9
9
  isTerraformStatePath,
10
10
  isTerraformWorkDir,
11
+ nestedGitignoreCovering,
11
12
  type ScannableFile,
12
13
  } from "./terraform-state";
13
- import { collectCandidates } from "./discover";
14
+ import { collectCandidates, walkCandidates } from "./discover";
14
15
  import { RULE_CATALOG, RULE_CATEGORY } from "./catalog";
15
16
 
16
17
  const file = (path: string): ScannableFile => ({ path, content: "" });
@@ -142,3 +143,82 @@ describe("discovery hands TF023 its paths, and nothing else changes", () => {
142
143
  rmSync(dir, { recursive: true, force: true });
143
144
  });
144
145
  });
146
+
147
+ describe("nestedGitignoreCovering (#2528)", () => {
148
+ const reader = (bodies: Record<string, string>) => (dir: string) => bodies[dir];
149
+
150
+ test("finds a .gitignore between the path and the root, matched relative to its own directory", () => {
151
+ expect(nestedGitignoreCovering("infra/prod/terraform.tfstate", reader({ infra: "*.tfstate\n" }))).toBe("infra");
152
+ expect(nestedGitignoreCovering("infra/.terraform", reader({ infra: ".terraform/\n" }))).toBe("infra");
153
+ });
154
+
155
+ test("prefers the nearest one, as git does", () => {
156
+ const bodies = reader({ infra: "*.tfstate\n", "infra/prod": "*.tfstate\n" });
157
+ expect(nestedGitignoreCovering("infra/prod/terraform.tfstate", bodies)).toBe("infra/prod");
158
+ });
159
+
160
+ test("never reads the root's own .gitignore, and ignores one that does not cover the path", () => {
161
+ const bodies = reader({ "": "*.tfstate\n", infra: "*.log\n", other: "*.tfstate\n" });
162
+ expect(nestedGitignoreCovering("infra/terraform.tfstate", bodies)).toBeUndefined();
163
+ expect(nestedGitignoreCovering("terraform.tfstate", bodies)).toBeUndefined();
164
+ });
165
+ });
166
+
167
+ describe("walkCandidates reports what the next release changes, and changes nothing now (#2528)", () => {
168
+ function writeFiles(dir: string, n: number): void {
169
+ mkdirSync(join(dir, "docs"), { recursive: true });
170
+ for (let i = 0; i < n; i++) writeFileSync(join(dir, "docs", `${String(i).padStart(3, "0")}.md`), "x");
171
+ }
172
+
173
+ test("a walk that reaches its limit with files left says it was truncated, and keeps the same first files", () => {
174
+ const dir = tmpRepo();
175
+ writeFiles(dir, 5);
176
+ writeFileSync(join(dir, "terraform.tfstate"), "{}");
177
+ const cut = walkCandidates(dir, { maxFiles: 5 });
178
+ expect(cut.truncated).toBe(true);
179
+ expect(cut.maxFiles).toBe(5);
180
+ // `docs/` sorts first, so the state file is the one left behind.
181
+ expect(cut.files).toEqual([]);
182
+ const whole = walkCandidates(dir);
183
+ expect(whole.truncated).toBe(false);
184
+ expect(whole.maxFiles).toBe(1000);
185
+ expect(whole.files.map((f) => f.path)).toEqual(["terraform.tfstate"]);
186
+ rmSync(dir, { recursive: true, force: true });
187
+ });
188
+
189
+ test("a tree of exactly the limit, or one whose remainder is skipped, is not truncated", () => {
190
+ const dir = tmpRepo();
191
+ writeFiles(dir, 5);
192
+ mkdirSync(join(dir, "node_modules", "x"), { recursive: true });
193
+ writeFileSync(join(dir, "node_modules", "x", "index.js"), "");
194
+ mkdirSync(join(dir, "empty"), { recursive: true });
195
+ expect(walkCandidates(dir, { maxFiles: 5 }).truncated).toBe(false);
196
+ rmSync(dir, { recursive: true, force: true });
197
+ });
198
+
199
+ test("a state file a nested .gitignore ignores is not a candidate (#2528)", () => {
200
+ const dir = tmpRepo();
201
+ mkdirSync(join(dir, "infra", ".terraform"), { recursive: true });
202
+ writeFileSync(join(dir, "infra", ".gitignore"), "*.tfstate\n.terraform/\n");
203
+ writeFileSync(join(dir, "infra", "terraform.tfstate"), "{}");
204
+ const walk = walkCandidates(dir);
205
+ expect(walk.files.map((f) => f.path)).toEqual([]);
206
+ expect(auditTerraformState(walk.files)).toHaveLength(0);
207
+ rmSync(dir, { recursive: true, force: true });
208
+ });
209
+
210
+ test("only the .gitignore files between the path and the root apply, not a sibling's", () => {
211
+ const dir = tmpRepo();
212
+ mkdirSync(join(dir, "a"), { recursive: true });
213
+ mkdirSync(join(dir, "b"), { recursive: true });
214
+ writeFileSync(join(dir, ".gitignore"), "*.tfstate.backup\n");
215
+ writeFileSync(join(dir, "a", ".gitignore"), "*.tfstate.backup\n*.log\n");
216
+ writeFileSync(join(dir, "a", "terraform.tfstate"), "{}");
217
+ writeFileSync(join(dir, "a", "terraform.tfstate.backup"), "{}");
218
+ // A sibling's .gitignore is not between `a/` and the root.
219
+ writeFileSync(join(dir, "b", ".gitignore"), "*.tfstate\n");
220
+ const walk = walkCandidates(dir);
221
+ expect(walk.files.map((f) => f.path)).toEqual(["a/terraform.tfstate"]);
222
+ rmSync(dir, { recursive: true, force: true });
223
+ });
224
+ });
@@ -22,6 +22,8 @@
22
22
  * walk that decides which paths reach here is `discover.ts`'s
23
23
  * `collectCandidates`, which is also where a locally ignored path is dropped:
24
24
  * see `isTerraformStatePath` there and `gitignoreCoversTerraformState` below.
25
+ * The root `.gitignore` and every nested one on the way to the path can drop
26
+ * it (`nestedGitignoreCovering`, #2528).
25
27
  */
26
28
 
27
29
  import type { AuditFinding } from "./core";
@@ -83,6 +85,29 @@ export function gitignoreCoversTerraformState(gitignore: string, path: string):
83
85
  return false;
84
86
  }
85
87
 
88
+ /**
89
+ * The nearest directory strictly between a TF023 path and the scan root whose
90
+ * `.gitignore` covers that path, or undefined. Each `.gitignore` is matched
91
+ * against the path relative to its own directory, the way git scopes it, with
92
+ * the same narrow matcher as the root one. `readGitignore` takes a directory
93
+ * relative to the scan root and returns its `.gitignore` body, if any.
94
+ *
95
+ * The local walk drops a TF023 path this returns a directory for, as it drops
96
+ * one the root `.gitignore` covers (#2528).
97
+ */
98
+ export function nestedGitignoreCovering(
99
+ path: string,
100
+ readGitignore: (dir: string) => string | undefined,
101
+ ): string | undefined {
102
+ const parts = path.split("/");
103
+ for (let depth = parts.length - 1; depth > 0; depth--) {
104
+ const dir = parts.slice(0, depth).join("/");
105
+ const body = readGitignore(dir);
106
+ if (body !== undefined && gitignoreCoversTerraformState(body, parts.slice(depth).join("/"))) return dir;
107
+ }
108
+ return undefined;
109
+ }
110
+
86
111
  /**
87
112
  * Report TF023 for every committed state file and `.terraform/` directory in
88
113
  * the file list. One finding per path, and one for the `.terraform` directory
@@ -81,11 +81,18 @@ export interface CommandGroup {
81
81
  * (./conflict-check.ts) treats a collision as a hard, loud failure at
82
82
  * plugin-load time rather than a silently-ignored command group. Hand
83
83
  * maintained alongside the registry; update both together.
84
+ *
85
+ * `workspace` is reserved before core has the command (#2529, #2524 D12), so
86
+ * no lexicon can claim the word first and later be shadowed by it. Only a
87
+ * command-group name is reserved: a lexicon's own config field or flag
88
+ * called `workspace` (the terraform lexicon's root config has one) is
89
+ * untouched.
84
90
  */
85
91
  export const RESERVED_COMMAND_NAMES: ReadonlySet<string> = new Set([
86
92
  "build", "lint", "list", "describe", "import", "audit", "migrate", "carve",
87
93
  "init", "update", "doctor", "dev", "run", "graph", "vendor", "lifecycle",
88
94
  "lc", "components", "emulator", "serve", "operator", "approve",
95
+ "workspace",
89
96
  ]);
90
97
 
91
98
  /**
@@ -0,0 +1,167 @@
1
+ import { afterEach, beforeAll, describe, expect, test, vi } from "vitest";
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { tmpdir } from "node:os";
5
+ import { auditCommand, printAuditResult, type AuditCommandOptions } from "./audit";
6
+ import { loadAuditPlugins } from "../../audit/discover";
7
+
8
+ /**
9
+ * #2528, one of the level-0 changes on #2525's exception list (warned in
10
+ * v0.80.0). A truncated local walk is stated in the report, with its limit and
11
+ * the flag that raises it, and TF023 honours every `.gitignore` between a path
12
+ * and the scan root.
13
+ */
14
+
15
+ const NOW = "2026-09-23T00:00:00.000Z";
16
+ const dirs: string[] = [];
17
+
18
+ function tmpRepo(): string {
19
+ const dir = mkdtempSync(join(tmpdir(), "chant-2528-"));
20
+ dirs.push(dir);
21
+ return dir;
22
+ }
23
+
24
+ afterEach(() => {
25
+ for (const dir of dirs.splice(0)) rmSync(dir, { recursive: true, force: true });
26
+ vi.restoreAllMocks();
27
+ });
28
+
29
+ let plugins: Awaited<ReturnType<typeof loadAuditPlugins>>;
30
+
31
+ // Loading every audit lexicon is the slow part; once, outside any one test's timeout.
32
+ beforeAll(async () => {
33
+ plugins = await loadAuditPlugins();
34
+ }, 120_000);
35
+
36
+ function audit(path: string, extra: Partial<AuditCommandOptions> = {}) {
37
+ return auditCommand({ path, format: "json", now: NOW, toolVersion: "0.0.0", plugins, ...extra });
38
+ }
39
+
40
+ /** Print a result the way the CLI does, and split what reached each stream. */
41
+ function printed(result: Awaited<ReturnType<typeof auditCommand>>): { stdout: string; stderr: string } {
42
+ const out: string[] = [];
43
+ const err: string[] = [];
44
+ vi.spyOn(console, "log").mockImplementation((s: string) => void out.push(s));
45
+ vi.spyOn(console, "error").mockImplementation((s: string) => void err.push(s));
46
+ printAuditResult(result);
47
+ vi.restoreAllMocks();
48
+ return { stdout: out.join("\n"), stderr: err.join("\n") };
49
+ }
50
+
51
+ describe("a truncated walk is reported (#2528)", () => {
52
+ function treeWithTail(): string {
53
+ const dir = tmpRepo();
54
+ mkdirSync(join(dir, "a"), { recursive: true });
55
+ for (let i = 0; i < 5; i++) writeFileSync(join(dir, "a", `${i}.md`), "x");
56
+ writeFileSync(join(dir, "a", "terraform.tfstate"), "{}");
57
+ // Past the limit: a state file TF023 would report if the walk reached it.
58
+ mkdirSync(join(dir, "z"), { recursive: true });
59
+ writeFileSync(join(dir, "z", "terraform.tfstate"), "{}");
60
+ return dir;
61
+ }
62
+
63
+ test("JSON carries truncated with the limit and the flag, and nothing goes to stderr", async () => {
64
+ const dir = treeWithTail();
65
+ const result = await audit(dir, { maxFiles: 6 });
66
+ expect(JSON.parse(result.output).truncated).toEqual({ limit: 6, flag: "--max-files" });
67
+ expect(result.warnings).toBeUndefined();
68
+ const { stdout, stderr } = printed(result);
69
+ expect(stdout).toBe(result.output);
70
+ expect(stderr).toBe("");
71
+ expect(result.findings.map((f) => f.file)).toEqual(["a/terraform.tfstate"]);
72
+ });
73
+
74
+ test("the text report leads with a note naming the limit and --max-files", async () => {
75
+ const dir = treeWithTail();
76
+ const result = await audit(dir, { maxFiles: 6, format: "stylish" });
77
+ const first = result.output.split("\n")[0];
78
+ expect(first).toBe(
79
+ `Note: The scan of ${dir} stopped at 6 files, so part of the tree was not audited. ` +
80
+ "The limit counts every file the walk reaches, not only the ones it audits. Raise it with --max-files <n>.",
81
+ );
82
+ expect(result.warnings).toBeUndefined();
83
+ });
84
+
85
+ test("markdown and HTML carry the note, and HTML's embedded JSON carries the field", async () => {
86
+ const dir = treeWithTail();
87
+ const md = await audit(dir, { maxFiles: 6, format: "markdown" });
88
+ expect(md.output).toContain("stopped at 6 files");
89
+ const html = await audit(dir, { maxFiles: 6, format: "html" });
90
+ expect(html.output).toContain("stopped at 6 files");
91
+ expect(html.output).toContain('"truncated":{"limit":6,"flag":"--max-files"}');
92
+ });
93
+
94
+ test("SARIF has no slot for it, so the truncation goes to stderr there", async () => {
95
+ const dir = treeWithTail();
96
+ const result = await audit(dir, { maxFiles: 6, format: "sarif" });
97
+ const { stdout, stderr } = printed(result);
98
+ expect(stdout).toBe(result.output);
99
+ expect(stderr).toContain(`The scan of ${dir} stopped at 6 files`);
100
+ expect(stderr).toContain("--max-files <n>");
101
+ });
102
+
103
+ test("a whole scan reports nothing: no field, no note", async () => {
104
+ const dir = treeWithTail();
105
+ const raised = await audit(dir, { maxFiles: 7 });
106
+ expect(JSON.parse(raised.output)).not.toHaveProperty("truncated");
107
+ expect(raised.warnings).toBeUndefined();
108
+ expect(raised.findings.map((f) => f.file).sort()).toEqual(["a/terraform.tfstate", "z/terraform.tfstate"]);
109
+ const text = await audit(dir, { format: "stylish" });
110
+ expect(text.output).not.toContain("stopped at");
111
+ });
112
+
113
+ test("the no-lexicons report states it too", async () => {
114
+ const dir = treeWithTail();
115
+ const json = await audit(dir, { maxFiles: 6, plugins: [] });
116
+ expect(JSON.parse(json.output).truncated).toEqual({ limit: 6, flag: "--max-files" });
117
+ const text = await audit(dir, { maxFiles: 6, plugins: [], format: "stylish" });
118
+ expect(text.output).toContain("stopped at 6 files");
119
+ });
120
+
121
+ test("an audit with nothing auditable still says the scan was cut short", async () => {
122
+ const dir = tmpRepo();
123
+ for (let i = 0; i < 4; i++) writeFileSync(join(dir, `${i}.md`), "x");
124
+ const result = await audit(dir, { maxFiles: 2, format: "stylish" });
125
+ expect(result.output).toContain("No auditable files found");
126
+ expect(result.output).toContain("stopped at 2 files");
127
+ });
128
+ });
129
+
130
+ describe("TF023 honours every .gitignore between a path and the scan root (#2528)", () => {
131
+ function nestedTree(nested: string | undefined): string {
132
+ const dir = tmpRepo();
133
+ mkdirSync(join(dir, "infra", "prod"), { recursive: true });
134
+ writeFileSync(join(dir, ".gitignore"), "node_modules/\n");
135
+ writeFileSync(join(dir, "infra", "main.tf"), 'resource "null_resource" "a" {}\n');
136
+ writeFileSync(join(dir, "infra", "terraform.tfstate"), "{}");
137
+ writeFileSync(join(dir, "infra", "prod", "terraform.tfstate"), "{}");
138
+ if (nested !== undefined) writeFileSync(join(dir, "infra", ".gitignore"), nested);
139
+ return dir;
140
+ }
141
+ const tf023 = (r: Awaited<ReturnType<typeof audit>>) =>
142
+ r.findings.filter((f) => f.checkId === "TF023").map((f) => f.file).sort();
143
+
144
+ test("a nested .gitignore drops the paths it covers, at any depth below it", async () => {
145
+ const result = await audit(nestedTree("*.tfstate\n"));
146
+ expect(tf023(result)).toEqual([]);
147
+ expect(result.warnings).toBeUndefined();
148
+ });
149
+
150
+ test("a nested .gitignore that does not cover the file changes nothing", async () => {
151
+ expect(tf023(await audit(nestedTree("*.log\n")))).toEqual(["infra/prod/terraform.tfstate", "infra/terraform.tfstate"]);
152
+ });
153
+
154
+ test("a .gitignore deeper than the file does not apply to it", async () => {
155
+ const dir = nestedTree(undefined);
156
+ writeFileSync(join(dir, "infra", "prod", ".gitignore"), "*.tfstate\n");
157
+ expect(tf023(await audit(dir))).toEqual(["infra/terraform.tfstate"]);
158
+ });
159
+
160
+ test("auditing from the root and from the subdirectory agree", async () => {
161
+ const dir = nestedTree(undefined);
162
+ writeFileSync(join(dir, "infra", "prod", ".gitignore"), "*.tfstate\n");
163
+ const fromRoot = tf023(await audit(dir));
164
+ const fromInfra = tf023(await audit(join(dir, "infra"))).map((p) => `infra/${p}`);
165
+ expect(fromRoot).toEqual(fromInfra);
166
+ });
167
+ });