@intentius/chant 0.41.19 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/cli/build-params-cli.d.ts +7 -4
  2. package/dist/cli/build-params-cli.d.ts.map +1 -1
  3. package/dist/cli/commands/build.d.ts.map +1 -1
  4. package/dist/cli/commands/carve-apply.d.ts +9 -0
  5. package/dist/cli/commands/carve-apply.d.ts.map +1 -1
  6. package/dist/cli/commands/carve-bridge.d.ts +7 -0
  7. package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
  8. package/dist/cli/commands/carve-emit.d.ts +7 -0
  9. package/dist/cli/commands/carve-emit.d.ts.map +1 -1
  10. package/dist/cli/commands/import.d.ts +16 -0
  11. package/dist/cli/commands/import.d.ts.map +1 -1
  12. package/dist/cli/commands/init.d.ts +2 -0
  13. package/dist/cli/commands/init.d.ts.map +1 -1
  14. package/dist/cli/handlers/carve-apply.d.ts.map +1 -1
  15. package/dist/cli/handlers/components.d.ts.map +1 -1
  16. package/dist/cli/handlers/explain.d.ts +11 -0
  17. package/dist/cli/handlers/explain.d.ts.map +1 -0
  18. package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
  19. package/dist/cli/handlers/misc.d.ts.map +1 -1
  20. package/dist/cli/main.d.ts.map +1 -1
  21. package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
  22. package/dist/cli/registry.d.ts +4 -0
  23. package/dist/cli/registry.d.ts.map +1 -1
  24. package/dist/codegen/docs-rule-scanning.d.ts +11 -0
  25. package/dist/codegen/docs-rule-scanning.d.ts.map +1 -1
  26. package/dist/codegen/okf-lexicon.d.ts +36 -0
  27. package/dist/codegen/okf-lexicon.d.ts.map +1 -0
  28. package/dist/codegen/package.d.ts +2 -1
  29. package/dist/codegen/package.d.ts.map +1 -1
  30. package/dist/components/deploy-units.d.ts.map +1 -1
  31. package/dist/components/verbs/sbom.d.ts +1 -1
  32. package/dist/components/verbs/sbom.d.ts.map +1 -1
  33. package/dist/components/verbs/vuln-gate.d.ts +15 -4
  34. package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
  35. package/dist/components/verbs/vuln-scan.d.ts +18 -6
  36. package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
  37. package/dist/config.d.ts +12 -0
  38. package/dist/config.d.ts.map +1 -1
  39. package/dist/deep-observation.d.ts +13 -0
  40. package/dist/deep-observation.d.ts.map +1 -1
  41. package/dist/governance.d.ts +37 -0
  42. package/dist/governance.d.ts.map +1 -0
  43. package/dist/lexicon.d.ts +3 -0
  44. package/dist/lexicon.d.ts.map +1 -1
  45. package/dist/lifecycle/observe.d.ts.map +1 -1
  46. package/dist/lifecycle/snapshot.d.ts.map +1 -1
  47. package/dist/okf.d.ts +57 -0
  48. package/dist/okf.d.ts.map +1 -0
  49. package/dist/reconcile.d.ts +15 -0
  50. package/dist/reconcile.d.ts.map +1 -1
  51. package/dist/terraform/__fixtures__/build-graph.d.ts +13 -0
  52. package/dist/terraform/__fixtures__/build-graph.d.ts.map +1 -0
  53. package/dist/terraform/adopt-state.d.ts +33 -1
  54. package/dist/terraform/adopt-state.d.ts.map +1 -1
  55. package/dist/terraform/bridge.d.ts +7 -1
  56. package/dist/terraform/bridge.d.ts.map +1 -1
  57. package/dist/terraform/carve.d.ts +12 -0
  58. package/dist/terraform/carve.d.ts.map +1 -1
  59. package/dist/terraform/excise.d.ts +31 -0
  60. package/dist/terraform/excise.d.ts.map +1 -0
  61. package/dist/terraform/graduate.d.ts +12 -0
  62. package/dist/terraform/graduate.d.ts.map +1 -1
  63. package/dist/terraform/graph.d.ts +35 -5
  64. package/dist/terraform/graph.d.ts.map +1 -1
  65. package/dist/terraform/manifest.d.ts +89 -0
  66. package/dist/terraform/manifest.d.ts.map +1 -0
  67. package/dist/terraform/parse.d.ts +9 -4
  68. package/dist/terraform/parse.d.ts.map +1 -1
  69. package/dist/terraform/types.d.ts +7 -0
  70. package/dist/terraform/types.d.ts.map +1 -1
  71. package/dist/terraform/unified-diff.d.ts +11 -0
  72. package/dist/terraform/unified-diff.d.ts.map +1 -0
  73. package/package.json +1 -1
  74. package/src/__snapshots__/okf.test.ts.snap +381 -0
  75. package/src/cli/build-params-cli.test.ts +47 -3
  76. package/src/cli/build-params-cli.ts +22 -5
  77. package/src/cli/commands/build.test.ts +44 -0
  78. package/src/cli/commands/build.ts +15 -2
  79. package/src/cli/commands/carve-apply.test.ts +94 -2
  80. package/src/cli/commands/carve-apply.ts +62 -11
  81. package/src/cli/commands/carve-bridge.test.ts +82 -4
  82. package/src/cli/commands/carve-bridge.ts +79 -11
  83. package/src/cli/commands/carve-emit-state.test.ts +110 -1
  84. package/src/cli/commands/carve-emit.ts +184 -8
  85. package/src/cli/commands/import.ts +53 -5
  86. package/src/cli/commands/init.ts +1 -1
  87. package/src/cli/handlers/build.test.ts +3 -1
  88. package/src/cli/handlers/carve-apply.ts +1 -0
  89. package/src/cli/handlers/components.ts +4 -2
  90. package/src/cli/handlers/explain.test.ts +93 -0
  91. package/src/cli/handlers/explain.ts +60 -0
  92. package/src/cli/handlers/lifecycle.ts +9 -7
  93. package/src/cli/handlers/misc.ts +40 -1
  94. package/src/cli/handlers/run.test.ts +3 -1
  95. package/src/cli/main.ts +25 -5
  96. package/src/cli/mcp/server.test.ts +17 -0
  97. package/src/cli/mcp/tools/explain.ts +15 -3
  98. package/src/cli/registry.ts +4 -0
  99. package/src/codegen/__snapshots__/okf-lexicon.test.ts.snap +170 -0
  100. package/src/codegen/docs-rule-scanning.ts +35 -14
  101. package/src/codegen/okf-lexicon.test.ts +248 -0
  102. package/src/codegen/okf-lexicon.ts +303 -0
  103. package/src/codegen/package.ts +29 -4
  104. package/src/codegen/publish-order.test.ts +1 -1
  105. package/src/codegen/release-wiring.test.ts +7 -3
  106. package/src/components/config-defaults.test.ts +30 -0
  107. package/src/components/deploy-units.ts +3 -0
  108. package/src/components/verbs/__fixtures__/grype-with-kev-epss.json +1 -0
  109. package/src/components/verbs/__fixtures__/trivy-with-kev-epss.json +631 -0
  110. package/src/components/verbs/exploitability-roundtrip.test.ts +190 -0
  111. package/src/components/verbs/sbom.ts +1 -1
  112. package/src/components/verbs/vuln-gate.test.ts +144 -1
  113. package/src/components/verbs/vuln-gate.ts +61 -10
  114. package/src/components/verbs/vuln-scan.test.ts +94 -0
  115. package/src/components/verbs/vuln-scan.ts +44 -9
  116. package/src/config.test.ts +21 -0
  117. package/src/config.ts +18 -0
  118. package/src/deep-observation.test.ts +19 -0
  119. package/src/deep-observation.ts +32 -13
  120. package/src/governance.test.ts +72 -0
  121. package/src/governance.ts +54 -0
  122. package/src/lexicon.ts +3 -0
  123. package/src/lifecycle/observe.test.ts +18 -0
  124. package/src/lifecycle/observe.ts +10 -3
  125. package/src/lifecycle/snapshot.ts +5 -4
  126. package/src/okf.test.ts +169 -0
  127. package/src/okf.ts +308 -0
  128. package/src/reconcile.ts +32 -1
  129. package/src/terraform/__fixtures__/build-graph.ts +25 -0
  130. package/src/terraform/adopt-state.test.ts +34 -1
  131. package/src/terraform/adopt-state.ts +69 -2
  132. package/src/terraform/bridge.test.ts +38 -14
  133. package/src/terraform/bridge.ts +48 -14
  134. package/src/terraform/carve.test.ts +9 -7
  135. package/src/terraform/carve.ts +0 -0
  136. package/src/terraform/excise.test.ts +92 -0
  137. package/src/terraform/excise.ts +139 -0
  138. package/src/terraform/graduate.test.ts +73 -6
  139. package/src/terraform/graduate.ts +49 -0
  140. package/src/terraform/graph.test.ts +56 -10
  141. package/src/terraform/graph.ts +112 -45
  142. package/src/terraform/manifest.test.ts +105 -0
  143. package/src/terraform/manifest.ts +162 -0
  144. package/src/terraform/parse.test.ts +39 -1
  145. package/src/terraform/parse.ts +36 -9
  146. package/src/terraform/score.test.ts +8 -8
  147. package/src/terraform/state.test.ts +4 -4
  148. package/src/terraform/types.ts +7 -0
  149. package/src/terraform/unified-diff.test.ts +77 -0
  150. package/src/terraform/unified-diff.ts +146 -0
@@ -0,0 +1,89 @@
1
+ /**
2
+ * The carve state manifest (#998) — what makes emit → bridge → apply compose.
3
+ *
4
+ * `carve emit` persists the boundary report and adoption selector next to the
5
+ * emitted source as `<target>.carve.json`. The later steps read it back from
6
+ * their output dir, so `carve bridge` and `carve apply` no longer need the
7
+ * target re-specified by hand, and each step records what it did for the next.
8
+ * Plain JSON on disk — reviewable, diffable, nothing proprietary.
9
+ */
10
+ import type { CarveReport } from "./carve.js";
11
+ import type { OwnershipMarker } from "../ownership.js";
12
+ export declare const CARVE_MANIFEST_SUFFIX = ".carve.json";
13
+ export interface CarveManifest {
14
+ version: 1;
15
+ /** Terraform address of the carved resource, e.g. `aws_s3_bucket.assets`. */
16
+ target: string;
17
+ /** Terraform resource type, when known. */
18
+ tfType?: string;
19
+ /** Absolute path of the Terraform estate the carve came from. */
20
+ from: string;
21
+ /** Absolute path of the tfstate used for adoption (offline path). */
22
+ statePath?: string;
23
+ /** Boundary classification persisted when the manifest was written. */
24
+ boundary: CarveReport;
25
+ /** Recorded by `carve emit`. */
26
+ emit?: {
27
+ source: "tfstate" | "live";
28
+ /** Emitted chant source file path(s). */
29
+ files: string[];
30
+ /**
31
+ * Deferred outbound inputs declared as build parameters in the emitted
32
+ * project (#998), keyed by parameter name.
33
+ */
34
+ params?: Record<string, {
35
+ /** The carved resource's own Terraform attribute the value enters through. */
36
+ tfAttr: string;
37
+ /** The survivor the Terraform source read, e.g. `aws_vpc.main`. */
38
+ survivor: string;
39
+ /** Survivor attribute(s) read. */
40
+ attrs: string[];
41
+ /** State-resolved default, when scalar. */
42
+ default?: string | number | boolean;
43
+ }>;
44
+ at: string;
45
+ };
46
+ /** Recorded by `carve bridge`. */
47
+ bridge?: {
48
+ written: string[];
49
+ appliedInPlace: boolean;
50
+ /** The git-applyable `.patch` carrying the whole survivor edit. */
51
+ patch?: string;
52
+ /** Carved addresses whose own `.tf` block the rewrites remove (#998). */
53
+ excised?: string[];
54
+ at: string;
55
+ };
56
+ /** Recorded by `carve apply`. */
57
+ apply?: {
58
+ marker: OwnershipMarker;
59
+ ownershipTags: Record<string, string>;
60
+ /** Emitted files the marker was stamped into (`--write-source`). */
61
+ stampedFiles?: string[];
62
+ at: string;
63
+ };
64
+ }
65
+ /** Filesystem-safe slug for a Terraform address (shared file-naming convention). */
66
+ export declare function carveSlug(target: string): string;
67
+ /** Where the manifest for `target` lives inside an output dir. */
68
+ export declare function carveManifestPath(outDir: string, target: string): string;
69
+ /** Write (or overwrite) a manifest into the output dir. Returns the path. */
70
+ export declare function writeCarveManifest(outDir: string, manifest: CarveManifest): string;
71
+ /** Read a manifest, or null when absent/unreadable/not a v1 manifest. */
72
+ export declare function readCarveManifest(path: string): CarveManifest | null;
73
+ /** All carve manifest paths in an output dir. */
74
+ export declare function listCarveManifests(outDir: string): string[];
75
+ export interface ResolvedManifest {
76
+ manifest?: CarveManifest;
77
+ path?: string;
78
+ error?: string;
79
+ }
80
+ /**
81
+ * Resolve the manifest a later carve step composes with. With a selected
82
+ * target, that target's manifest (absent is fine — the step just runs
83
+ * standalone). Without one, the single manifest in the output dir; none or
84
+ * several is an error naming what is (or is not) there.
85
+ */
86
+ export declare function resolveCarveManifest(outDir: string, select?: string): ResolvedManifest;
87
+ /** Read-modify-write a section of an existing manifest. No-op when absent. */
88
+ export declare function updateCarveManifest(outDir: string, target: string, patch: Partial<Pick<CarveManifest, "boundary" | "emit" | "bridge" | "apply">>): string | undefined;
89
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../src/terraform/manifest.ts"],"names":[],"mappings":"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"}
@@ -8,8 +8,14 @@
8
8
  * advisor fails with a one-line install hint.
9
9
  */
10
10
  import type { Hcl2JsonTree, TfGraph } from "./types.js";
11
- /** Minimal shape of the parser export we depend on. */
12
- type Hcl2JsonParse = (filename: string, hcl: string) => Promise<Hcl2JsonTree>;
11
+ /** Minimal shape of the parser exports we depend on. */
12
+ export interface Hcl2Json {
13
+ parse: (filename: string, hcl: string) => Promise<Hcl2JsonTree>;
14
+ /** Expression-AST reference extraction (#998) — one traversal accessor per reference. */
15
+ getReferencesInExpression: (filename: string, expression: string) => Promise<Array<{
16
+ value: string;
17
+ }>>;
18
+ }
13
19
  export declare class Hcl2JsonNotInstalled extends Error {
14
20
  constructor(cause: unknown);
15
21
  }
@@ -17,7 +23,7 @@ export declare class Hcl2JsonNotInstalled extends Error {
17
23
  * Lazy-load the optional HCL parser. Throws `Hcl2JsonNotInstalled` with an
18
24
  * install hint when the package is missing, rather than a raw MODULE_NOT_FOUND.
19
25
  */
20
- export declare function loadHcl2json(): Promise<Hcl2JsonParse>;
26
+ export declare function loadHcl2json(): Promise<Hcl2Json>;
21
27
  export interface ParseTerraformOptions {
22
28
  /** Opt-in `.tfstate` path (#214 T2): overlays state-expanded instance counts. */
23
29
  statePath?: string;
@@ -29,5 +35,4 @@ export interface ParseTerraformOptions {
29
35
  * instance counts become accurate (see `state.ts`).
30
36
  */
31
37
  export declare function parseTerraformDir(dir: string, opts?: ParseTerraformOptions): Promise<TfGraph>;
32
- export {};
33
38
  //# sourceMappingURL=parse.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/terraform/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAErD,uDAAuD;AACvD,KAAK,aAAa,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAE9E,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,KAAK,EAAE,OAAO;CAQ3B;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAO3D;AAuBD,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAWvG"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/terraform/parse.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAErD,wDAAwD;AACxD,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAChE,yFAAyF;IACzF,yBAAyB,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC,CAAC;CACxG;AAED,qBAAa,oBAAqB,SAAQ,KAAK;gBACjC,KAAK,EAAE,OAAO;CAQ3B;AAED;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,QAAQ,CAAC,CAMtD;AA+CD,MAAM,WAAW,qBAAqB;IACpC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,GAAE,qBAA0B,GAAG,OAAO,CAAC,OAAO,CAAC,CAWvG"}
@@ -46,6 +46,13 @@ export interface TfEdge {
46
46
  to: string;
47
47
  /** The attribute path(s) referenced, e.g. `["id", "arn"]`. */
48
48
  attrs: string[];
49
+ /**
50
+ * The referring block's own top-level attribute(s) the reference sits in,
51
+ * e.g. `["vpc_id"]` for a subnet reading its VPC (#998). This is what a
52
+ * deferred outbound input is named after when emit turns it into a build
53
+ * parameter. Empty when the reference came from a non-object block shape.
54
+ */
55
+ via: string[];
49
56
  }
50
57
  export interface TfGraph {
51
58
  nodes: TfNode[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/terraform/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/terraform/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,+EAA+E;AAC/E,MAAM,WAAW,MAAM;IACrB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,UAAU,GAAG,QAAQ,CAAC;IAC5B,8DAA8D;IAC9D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,EAAE,OAAO,CAAC;IACpB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;;;;;OAKG;IACH,GAAG,EAAE,MAAM,EAAE,CAAC;CACf;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Minimal unified-diff generator for the carve bridge patch (#998). Emits
3
+ * git-applyable hunks (`git apply`, or plain `patch -p1`) so the whole survivor
4
+ * edit — data sources plus rewired references — lands in one reviewable file.
5
+ * LCS-based; bridge inputs are hand-sized `.tf` files, so O(n·m) is fine.
6
+ */
7
+ /** One file's diff, `a/<path>` → `b/<path>`, with git headers. Empty when unchanged. */
8
+ export declare function unifiedDiff(path: string, oldText: string, newText: string, context?: number): string;
9
+ /** A new-file diff (`/dev/null` → `b/<path>`), git-applyable. */
10
+ export declare function newFileDiff(path: string, text: string): string;
11
+ //# sourceMappingURL=unified-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unified-diff.d.ts","sourceRoot":"","sources":["../../src/terraform/unified-diff.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,wFAAwF;AACxF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,SAAI,GAAG,MAAM,CA0B/F;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAa9D"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant",
3
- "version": "0.41.19",
3
+ "version": "0.42.1",
4
4
  "description": "Declarative infrastructure-as-code toolkit — TypeScript on Node.js",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -0,0 +1,381 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`buildOkfBundle over shipped examples > aws lambda-s3 emits a conformant, snapshot-stable bundle 1`] = `
4
+ [
5
+ {
6
+ "content": "---
7
+ type: AWS::S3::Bucket
8
+ title: appBucket
9
+ description: aws resource of type AWS::S3::Bucket
10
+ name: appBucket
11
+ lexicon: aws
12
+ kind: resource
13
+ source: main.ts
14
+ composite: LambdaS3
15
+ composite_instance: app
16
+ ---
17
+ Declared in \`main.ts\`.
18
+
19
+ ## Referenced by
20
+
21
+ - [appFunc](/aws/appFunc.md)
22
+ - [appRole](/aws/appRole.md)
23
+ ",
24
+ "path": "aws/appBucket.md",
25
+ },
26
+ {
27
+ "content": "---
28
+ type: AWS::Lambda::Function
29
+ title: appFunc
30
+ description: aws resource of type AWS::Lambda::Function
31
+ name: appFunc
32
+ lexicon: aws
33
+ kind: resource
34
+ source: main.ts
35
+ composite: LambdaS3
36
+ composite_instance: app
37
+ ---
38
+ Declared in \`main.ts\`.
39
+
40
+ ## Depends on
41
+
42
+ - [appBucket](/aws/appBucket.md)
43
+ - [appRole](/aws/appRole.md)
44
+ ",
45
+ "path": "aws/appFunc.md",
46
+ },
47
+ {
48
+ "content": "---
49
+ type: AWS::IAM::Role
50
+ title: appRole
51
+ description: aws resource of type AWS::IAM::Role
52
+ name: appRole
53
+ lexicon: aws
54
+ kind: resource
55
+ source: main.ts
56
+ composite: LambdaS3
57
+ composite_instance: app
58
+ ---
59
+ Declared in \`main.ts\`.
60
+
61
+ ## Depends on
62
+
63
+ - [appBucket](/aws/appBucket.md)
64
+
65
+ ## Referenced by
66
+
67
+ - [appFunc](/aws/appFunc.md)
68
+ ",
69
+ "path": "aws/appRole.md",
70
+ },
71
+ {
72
+ "content": "---
73
+ type: Output
74
+ title: bucketArn
75
+ description: aws output of type Output
76
+ name: bucketArn
77
+ lexicon: aws
78
+ kind: output
79
+ source: outputs.ts
80
+ ---
81
+ Declared in \`outputs.ts\`.
82
+ ",
83
+ "path": "aws/bucketArn.md",
84
+ },
85
+ {
86
+ "content": "---
87
+ type: AWS::CloudFormation::Parameter
88
+ title: environment
89
+ description: aws resource of type AWS::CloudFormation::Parameter
90
+ name: environment
91
+ lexicon: aws
92
+ kind: resource
93
+ source: params.ts
94
+ ---
95
+ Declared in \`params.ts\`.
96
+ ",
97
+ "path": "aws/environment.md",
98
+ },
99
+ {
100
+ "content": "---
101
+ type: chant:aws:defaultTags
102
+ title: tags
103
+ description: aws resource of type chant:aws:defaultTags
104
+ name: tags
105
+ lexicon: aws
106
+ kind: resource
107
+ source: tags.ts
108
+ ---
109
+ Declared in \`tags.ts\`.
110
+ ",
111
+ "path": "aws/tags.md",
112
+ },
113
+ {
114
+ "content": "---
115
+ okf_version: '0.2'
116
+ ---
117
+
118
+ # Lexicon: aws
119
+
120
+ * [appBucket](/aws/appBucket.md) - aws resource of type AWS::S3::Bucket
121
+ * [appFunc](/aws/appFunc.md) - aws resource of type AWS::Lambda::Function
122
+ * [appRole](/aws/appRole.md) - aws resource of type AWS::IAM::Role
123
+ * [bucketArn](/aws/bucketArn.md) - aws output of type Output
124
+ * [environment](/aws/environment.md) - aws resource of type AWS::CloudFormation::Parameter
125
+ * [tags](/aws/tags.md) - aws resource of type chant:aws:defaultTags
126
+ ",
127
+ "path": "index.md",
128
+ },
129
+ ]
130
+ `;
131
+
132
+ exports[`buildOkfBundle over shipped examples > gitlab node-pipeline emits a conformant, snapshot-stable bundle 1`] = `
133
+ [
134
+ {
135
+ "content": "---
136
+ type: GitLab::CI::Job
137
+ title: appBuild
138
+ description: gitlab resource of type GitLab::CI::Job
139
+ name: appBuild
140
+ lexicon: gitlab
141
+ kind: resource
142
+ source: pipeline.ts
143
+ composite: NodePipeline
144
+ composite_instance: app
145
+ ---
146
+ Declared in \`pipeline.ts\`.
147
+ ",
148
+ "path": "gitlab/appBuild.md",
149
+ },
150
+ {
151
+ "content": "---
152
+ type: GitLab::CI::Default
153
+ title: appDefaults
154
+ description: gitlab resource of type GitLab::CI::Default
155
+ name: appDefaults
156
+ lexicon: gitlab
157
+ kind: resource
158
+ source: pipeline.ts
159
+ composite: NodePipeline
160
+ composite_instance: app
161
+ ---
162
+ Declared in \`pipeline.ts\`.
163
+ ",
164
+ "path": "gitlab/appDefaults.md",
165
+ },
166
+ {
167
+ "content": "---
168
+ type: GitLab::CI::Job
169
+ title: appTest
170
+ description: gitlab resource of type GitLab::CI::Job
171
+ name: appTest
172
+ lexicon: gitlab
173
+ kind: resource
174
+ source: pipeline.ts
175
+ composite: NodePipeline
176
+ composite_instance: app
177
+ ---
178
+ Declared in \`pipeline.ts\`.
179
+ ",
180
+ "path": "gitlab/appTest.md",
181
+ },
182
+ {
183
+ "content": "---
184
+ okf_version: '0.2'
185
+ ---
186
+
187
+ # Lexicon: gitlab
188
+
189
+ * [appBuild](/gitlab/appBuild.md) - gitlab resource of type GitLab::CI::Job
190
+ * [appDefaults](/gitlab/appDefaults.md) - gitlab resource of type GitLab::CI::Default
191
+ * [appTest](/gitlab/appTest.md) - gitlab resource of type GitLab::CI::Job
192
+ ",
193
+ "path": "index.md",
194
+ },
195
+ ]
196
+ `;
197
+
198
+ exports[`buildOkfBundle over shipped examples > k8s layered-config emits a conformant, snapshot-stable bundle 1`] = `
199
+ [
200
+ {
201
+ "content": "---
202
+ okf_version: '0.2'
203
+ ---
204
+
205
+ # Lexicon: k8s
206
+
207
+ * [devAppDeployment](/k8s/devAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
208
+ * [devAppService](/k8s/devAppService.md) - k8s resource of type K8s::Core::Service
209
+ * [prodAppDeployment](/k8s/prodAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
210
+ * [prodAppIngress](/k8s/prodAppIngress.md) - k8s resource of type K8s::Networking::Ingress
211
+ * [prodAppPdb](/k8s/prodAppPdb.md) - k8s resource of type K8s::Policy::PodDisruptionBudget
212
+ * [prodAppService](/k8s/prodAppService.md) - k8s resource of type K8s::Core::Service
213
+ * [stagingAppDeployment](/k8s/stagingAppDeployment.md) - k8s resource of type K8s::Apps::Deployment
214
+ * [stagingAppIngress](/k8s/stagingAppIngress.md) - k8s resource of type K8s::Networking::Ingress
215
+ * [stagingAppPdb](/k8s/stagingAppPdb.md) - k8s resource of type K8s::Policy::PodDisruptionBudget
216
+ * [stagingAppService](/k8s/stagingAppService.md) - k8s resource of type K8s::Core::Service
217
+ ",
218
+ "path": "index.md",
219
+ },
220
+ {
221
+ "content": "---
222
+ type: K8s::Apps::Deployment
223
+ title: devAppDeployment
224
+ description: k8s resource of type K8s::Apps::Deployment
225
+ name: devAppDeployment
226
+ lexicon: k8s
227
+ kind: resource
228
+ source: web.ts
229
+ composite: WebApp
230
+ composite_instance: devApp
231
+ ---
232
+ Declared in \`web.ts\`.
233
+ ",
234
+ "path": "k8s/devAppDeployment.md",
235
+ },
236
+ {
237
+ "content": "---
238
+ type: K8s::Core::Service
239
+ title: devAppService
240
+ description: k8s resource of type K8s::Core::Service
241
+ name: devAppService
242
+ lexicon: k8s
243
+ kind: resource
244
+ source: web.ts
245
+ composite: WebApp
246
+ composite_instance: devApp
247
+ ---
248
+ Declared in \`web.ts\`.
249
+ ",
250
+ "path": "k8s/devAppService.md",
251
+ },
252
+ {
253
+ "content": "---
254
+ type: K8s::Apps::Deployment
255
+ title: prodAppDeployment
256
+ description: k8s resource of type K8s::Apps::Deployment
257
+ name: prodAppDeployment
258
+ lexicon: k8s
259
+ kind: resource
260
+ source: web.ts
261
+ composite: WebApp
262
+ composite_instance: prodApp
263
+ ---
264
+ Declared in \`web.ts\`.
265
+ ",
266
+ "path": "k8s/prodAppDeployment.md",
267
+ },
268
+ {
269
+ "content": "---
270
+ type: K8s::Networking::Ingress
271
+ title: prodAppIngress
272
+ description: k8s resource of type K8s::Networking::Ingress
273
+ name: prodAppIngress
274
+ lexicon: k8s
275
+ kind: resource
276
+ source: web.ts
277
+ composite: WebApp
278
+ composite_instance: prodApp
279
+ ---
280
+ Declared in \`web.ts\`.
281
+ ",
282
+ "path": "k8s/prodAppIngress.md",
283
+ },
284
+ {
285
+ "content": "---
286
+ type: K8s::Policy::PodDisruptionBudget
287
+ title: prodAppPdb
288
+ description: k8s resource of type K8s::Policy::PodDisruptionBudget
289
+ name: prodAppPdb
290
+ lexicon: k8s
291
+ kind: resource
292
+ source: web.ts
293
+ composite: WebApp
294
+ composite_instance: prodApp
295
+ ---
296
+ Declared in \`web.ts\`.
297
+ ",
298
+ "path": "k8s/prodAppPdb.md",
299
+ },
300
+ {
301
+ "content": "---
302
+ type: K8s::Core::Service
303
+ title: prodAppService
304
+ description: k8s resource of type K8s::Core::Service
305
+ name: prodAppService
306
+ lexicon: k8s
307
+ kind: resource
308
+ source: web.ts
309
+ composite: WebApp
310
+ composite_instance: prodApp
311
+ ---
312
+ Declared in \`web.ts\`.
313
+ ",
314
+ "path": "k8s/prodAppService.md",
315
+ },
316
+ {
317
+ "content": "---
318
+ type: K8s::Apps::Deployment
319
+ title: stagingAppDeployment
320
+ description: k8s resource of type K8s::Apps::Deployment
321
+ name: stagingAppDeployment
322
+ lexicon: k8s
323
+ kind: resource
324
+ source: web.ts
325
+ composite: WebApp
326
+ composite_instance: stagingApp
327
+ ---
328
+ Declared in \`web.ts\`.
329
+ ",
330
+ "path": "k8s/stagingAppDeployment.md",
331
+ },
332
+ {
333
+ "content": "---
334
+ type: K8s::Networking::Ingress
335
+ title: stagingAppIngress
336
+ description: k8s resource of type K8s::Networking::Ingress
337
+ name: stagingAppIngress
338
+ lexicon: k8s
339
+ kind: resource
340
+ source: web.ts
341
+ composite: WebApp
342
+ composite_instance: stagingApp
343
+ ---
344
+ Declared in \`web.ts\`.
345
+ ",
346
+ "path": "k8s/stagingAppIngress.md",
347
+ },
348
+ {
349
+ "content": "---
350
+ type: K8s::Policy::PodDisruptionBudget
351
+ title: stagingAppPdb
352
+ description: k8s resource of type K8s::Policy::PodDisruptionBudget
353
+ name: stagingAppPdb
354
+ lexicon: k8s
355
+ kind: resource
356
+ source: web.ts
357
+ composite: WebApp
358
+ composite_instance: stagingApp
359
+ ---
360
+ Declared in \`web.ts\`.
361
+ ",
362
+ "path": "k8s/stagingAppPdb.md",
363
+ },
364
+ {
365
+ "content": "---
366
+ type: K8s::Core::Service
367
+ title: stagingAppService
368
+ description: k8s resource of type K8s::Core::Service
369
+ name: stagingAppService
370
+ lexicon: k8s
371
+ kind: resource
372
+ source: web.ts
373
+ composite: WebApp
374
+ composite_instance: stagingApp
375
+ ---
376
+ Declared in \`web.ts\`.
377
+ ",
378
+ "path": "k8s/stagingAppService.md",
379
+ },
380
+ ]
381
+ `;
@@ -56,18 +56,62 @@ describe("resolveCliBuildParams", () => {
56
56
  }
57
57
  });
58
58
 
59
- test("logs every resolved parameter as '[param] name = value (source)'", () => {
59
+ test("a build with no overrides collapses to a single defaults count", () => {
60
+ // The provenance still records every value; the echo just stops naming
61
+ // what nobody set. One line, so silence still never means "no parameters
62
+ // reached us".
60
63
  const defs: BuildParamsConfig = { tier: { type: "string", default: "light" } };
61
64
  const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
62
65
  try {
63
- resolveCliBuildParams(defs, {});
66
+ const result = resolveCliBuildParams(defs, {});
64
67
  const logged = errorSpy.mock.calls.map((call) => String(call[0]));
65
- expect(logged.some((line) => line.includes("[param] tier") && line.includes("light") && line.includes("default"))).toBe(true);
68
+ expect(logged.some((line) => line.includes("1 parameters at their defaults"))).toBe(true);
69
+ expect(logged.some((line) => line.includes("[param] tier"))).toBe(false);
70
+ expect(result.provenance).toEqual([{ name: "tier", value: "light", source: "default" }]);
66
71
  } finally {
67
72
  errorSpy.mockRestore();
68
73
  }
69
74
  });
70
75
 
76
+ test("names the overrides and collapses the defaults into a count", () => {
77
+ const defs: BuildParamsConfig = {
78
+ tier: { type: "string", default: "light" },
79
+ target: { type: "string", default: "k3d" },
80
+ host: { type: "string", default: "localhost:4000" },
81
+ };
82
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
83
+ try {
84
+ resolveCliBuildParams(defs, { cli: { tier: "ha" } });
85
+ const logged = errorSpy.mock.calls.map((call) => String(call[0]));
86
+ expect(logged.some((line) => line.includes("[param] tier") && line.includes("ha") && line.includes("cli"))).toBe(true);
87
+ expect(logged.some((line) => line.includes("2 more at their defaults"))).toBe(true);
88
+ expect(logged.some((line) => line.includes("[param] target"))).toBe(false);
89
+ } finally {
90
+ errorSpy.mockRestore();
91
+ }
92
+ });
93
+
94
+ test("CHANT_PARAM_ECHO=all restores the full listing", () => {
95
+ const defs: BuildParamsConfig = {
96
+ tier: { type: "string", default: "light" },
97
+ target: { type: "string", default: "k3d" },
98
+ };
99
+ const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
100
+ const prev = process.env.CHANT_PARAM_ECHO;
101
+ process.env.CHANT_PARAM_ECHO = "all";
102
+ try {
103
+ resolveCliBuildParams(defs, { cli: { tier: "ha" } });
104
+ const logged = errorSpy.mock.calls.map((call) => String(call[0]));
105
+ expect(logged.some((line) => line.includes("[param] tier") && line.includes("ha"))).toBe(true);
106
+ expect(logged.some((line) => line.includes("[param] target") && line.includes("k3d") && line.includes("default"))).toBe(true);
107
+ expect(logged.some((line) => line.includes("more at their defaults"))).toBe(false);
108
+ } finally {
109
+ if (prev === undefined) delete process.env.CHANT_PARAM_ECHO;
110
+ else process.env.CHANT_PARAM_ECHO = prev;
111
+ errorSpy.mockRestore();
112
+ }
113
+ });
114
+
71
115
  test("no declared params → success with empty provenance and no logging", () => {
72
116
  const errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
73
117
  try {
@@ -62,10 +62,13 @@ export interface CliBuildParamsResolution {
62
62
  * chant #1064's acceptance criterion that this never surfaces as a thrown
63
63
  * error from inside user source.
64
64
  *
65
- * On success, every resolved parameter is logged via `console.error` as
66
- * `[param] <name> = <value> (<source>)` unconditional, not gated on
67
- * `--verbose`, so a build's environment-varying inputs are always visible,
68
- * the same way #1022's fold decisions are.
65
+ * On success, every explicitly-set parameter is logged via `console.error` as
66
+ * `[param] <name> = <value> (<source>)`, and the ones still at their declared
67
+ * defaults collapse to a single count line (`CHANT_PARAM_ECHO=all` lists them
68
+ * individually). Overrides stay unconditionally visible not gated on
69
+ * `--verbose` — so a build's environment-varying inputs are always in the log,
70
+ * the same way #1022's fold decisions are; the defaults are the part that
71
+ * never varies, which is exactly why they can be a count.
69
72
  */
70
73
  export function resolveCliBuildParams(
71
74
  buildParamsConfig: BuildParamsConfig | undefined,
@@ -99,9 +102,23 @@ export function resolveCliBuildParams(
99
102
  return { success: false, provenance: [], errors };
100
103
  }
101
104
 
102
- for (const p of resolution.provenance) {
105
+ // Echo what the operator SET, one line each; collapse what they did not.
106
+ // A project with two dozen declared parameters printed two dozen grey lines
107
+ // on every build, and the ones that matter — the overrides — drowned in the
108
+ // ones that never vary. Defaults still get named on request
109
+ // (CHANT_PARAM_ECHO=all), and a build with no overrides still says how many
110
+ // parameters resolved, so silence never means "no parameters reached us"
111
+ // (the failure mode warnIfParamsCannotReachProject exists for).
112
+ const explicit = resolution.provenance.filter((p) => p.source !== "default");
113
+ const defaulted = resolution.provenance.length - explicit.length;
114
+ const echoAll = process.env.CHANT_PARAM_ECHO === "all";
115
+ for (const p of echoAll ? resolution.provenance : explicit) {
103
116
  console.error(formatInfo(`[param] ${p.name} = ${JSON.stringify(p.value)} (${p.source})`));
104
117
  }
118
+ if (!echoAll && defaulted > 0) {
119
+ const more = explicit.length > 0 ? `${defaulted} more` : `${defaulted} parameters`;
120
+ console.error(formatInfo(`[param] ${more} at their defaults (CHANT_PARAM_ECHO=all lists them)`));
121
+ }
105
122
 
106
123
  return { success: true, provenance: resolution.provenance, errors: [] };
107
124
  }