@intentius/chant 0.57.0 → 0.59.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.
- package/dist/audit/catalog.d.ts +51 -1
- package/dist/audit/catalog.d.ts.map +1 -1
- package/dist/audit/core.d.ts +36 -1
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts +26 -9
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/lineage.d.ts +10 -0
- package/dist/audit/lineage.d.ts.map +1 -0
- package/dist/audit/prior-art.d.ts +385 -0
- package/dist/audit/prior-art.d.ts.map +1 -0
- package/dist/audit/proof.d.ts +16 -0
- package/dist/audit/proof.d.ts.map +1 -1
- package/dist/audit/report-html.d.ts.map +1 -1
- package/dist/audit/report-model.d.ts +8 -1
- package/dist/audit/report-model.d.ts.map +1 -1
- package/dist/audit/report.d.ts.map +1 -1
- package/dist/audit/rules-doc.d.ts +3 -0
- package/dist/audit/rules-doc.d.ts.map +1 -1
- package/dist/audit/secrets.d.ts +15 -0
- package/dist/audit/secrets.d.ts.map +1 -1
- package/dist/audit/terraform-state.d.ts +46 -0
- package/dist/audit/terraform-state.d.ts.map +1 -0
- package/dist/build.d.ts +17 -1
- package/dist/build.d.ts.map +1 -1
- package/dist/claimed-fields.d.ts +161 -0
- package/dist/claimed-fields.d.ts.map +1 -0
- package/dist/cli/build-params-cli.d.ts +2 -2
- package/dist/cli/command-group.d.ts +14 -0
- package/dist/cli/command-group.d.ts.map +1 -1
- package/dist/cli/commands/audit.d.ts +17 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-bridge.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-docs.d.ts +1 -1
- package/dist/cli/commands/check-lexicon-examples.d.ts +16 -6
- package/dist/cli/commands/check-lexicon-examples.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts +1 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon/templates/project.d.ts +7 -0
- package/dist/cli/commands/init-lexicon/templates/project.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/lint.d.ts +13 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +2 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +82 -16
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/run.d.ts +49 -42
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/main.d.ts +12 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts +16 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/resource-handlers.d.ts.map +1 -1
- package/dist/cli/mcp/resources/context.d.ts.map +1 -1
- package/dist/cli/plugins.d.ts +22 -0
- package/dist/cli/plugins.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +40 -9
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/generate-post-synth-barrel.d.ts +1 -1
- package/dist/components/auto-release.d.ts +10 -20
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability.d.ts +4 -4
- package/dist/components/cli-support.d.ts +24 -22
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +21 -6
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/driver-output.d.ts.map +1 -1
- package/dist/components/driver.d.ts +73 -37
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/index.d.ts +1 -2
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/manifest-persistence.d.ts +1 -9
- package/dist/components/manifest-persistence.d.ts.map +1 -1
- package/dist/components/run-progress.d.ts +6 -6
- package/dist/components/run-progress.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts +10 -22
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts +2 -2
- package/dist/deep-observation.d.ts +17 -0
- package/dist/deep-observation.d.ts.map +1 -1
- package/dist/detectLexicon.d.ts +13 -0
- package/dist/detectLexicon.d.ts.map +1 -1
- package/dist/discovery/files.d.ts +4 -4
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +33 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/bundle.d.ts.map +1 -1
- package/dist/discovery/sandbox/config-wire.d.ts +2 -2
- package/dist/fold/foldable-helpers.d.ts +5 -1
- package/dist/fold/foldable-helpers.d.ts.map +1 -1
- package/dist/fold-provenance.d.ts +236 -0
- package/dist/fold-provenance.d.ts.map +1 -0
- package/dist/graph-ops.d.ts +1 -1
- package/dist/held-elsewhere.d.ts +85 -0
- package/dist/held-elsewhere.d.ts.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts +3 -3
- package/dist/lexicon-config.d.ts +4 -4
- package/dist/lexicon-plugin-helpers.d.ts +1 -1
- package/dist/lexicon.d.ts +273 -16
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/change-set.d.ts +13 -0
- package/dist/lifecycle/change-set.d.ts.map +1 -1
- package/dist/lifecycle/deep-diff.d.ts +133 -6
- package/dist/lifecycle/deep-diff.d.ts.map +1 -1
- package/dist/lifecycle/deep-observe.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +79 -3
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/index.d.ts +1 -0
- package/dist/lifecycle/index.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts +2 -2
- package/dist/lifecycle/run-ledger.d.ts +53 -0
- package/dist/lifecycle/run-ledger.d.ts.map +1 -0
- package/dist/lifecycle/symptoms.d.ts +3 -3
- package/dist/lifecycle/symptoms.d.ts.map +1 -1
- package/dist/lint/config.d.ts +81 -2
- package/dist/lint/config.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +55 -2
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.d.ts.map +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts +1 -1
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.d.ts.map +1 -1
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts +44 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.d.ts.map +1 -0
- package/dist/lint/rules/comp/index.d.ts +1 -1
- package/dist/lint/rules/comp/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.d.ts +16 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts +27 -0
- package/dist/lint/rules/op/ops012-activity-contract.d.ts.map +1 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts +61 -0
- package/dist/lint/rules/op/ops013-step-output-ref.d.ts.map +1 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts +55 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.d.ts.map +1 -0
- package/dist/lint/rules/op/support.d.ts +12 -0
- package/dist/lint/rules/op/support.d.ts.map +1 -0
- package/dist/lint/suppressions.d.ts +108 -0
- package/dist/lint/suppressions.d.ts.map +1 -0
- package/dist/live-endpoint.d.ts +1 -1
- package/dist/op/activities/activity-contracts.d.ts +54 -0
- package/dist/op/activities/activity-contracts.d.ts.map +1 -0
- package/dist/op/activities/apply.d.ts +262 -0
- package/dist/op/activities/apply.d.ts.map +1 -0
- package/dist/op/activities/build.d.ts +13 -0
- package/dist/op/activities/build.d.ts.map +1 -0
- package/dist/op/activities/converge.d.ts +110 -0
- package/dist/op/activities/converge.d.ts.map +1 -0
- package/dist/op/activities/env-teardown.d.ts +76 -0
- package/dist/op/activities/env-teardown.d.ts.map +1 -0
- package/dist/op/activities/guard-validate.d.ts +64 -0
- package/dist/op/activities/guard-validate.d.ts.map +1 -0
- package/dist/op/activities/http-check.d.ts +34 -0
- package/dist/op/activities/http-check.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +31 -0
- package/dist/op/activities/index.d.ts.map +1 -0
- package/dist/op/activities/lexicon-upgrade.d.ts +182 -0
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -0
- package/dist/op/activities/lifecycle.d.ts +42 -0
- package/dist/op/activities/lifecycle.d.ts.map +1 -0
- package/dist/op/activities/pipeline-audit.d.ts +84 -0
- package/dist/op/activities/pipeline-audit.d.ts.map +1 -0
- package/dist/op/activities/policy.d.ts +17 -0
- package/dist/op/activities/policy.d.ts.map +1 -0
- package/dist/op/activities/reconcile.d.ts +149 -0
- package/dist/op/activities/reconcile.d.ts.map +1 -0
- package/dist/op/activities/shell.d.ts +13 -0
- package/dist/op/activities/shell.d.ts.map +1 -0
- package/dist/op/activities/teardown.d.ts +10 -0
- package/dist/op/activities/teardown.d.ts.map +1 -0
- package/dist/op/activities/util.d.ts +7 -0
- package/dist/op/activities/util.d.ts.map +1 -0
- package/dist/op/activities/wait.d.ts +28 -0
- package/dist/op/activities/wait.d.ts.map +1 -0
- package/dist/op/activities/workflow-audit.d.ts +92 -0
- package/dist/op/activities/workflow-audit.d.ts.map +1 -0
- package/dist/op/activity-contract-registry.d.ts +76 -0
- package/dist/op/activity-contract-registry.d.ts.map +1 -0
- package/dist/op/activity-contract.d.ts +25 -18
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts +28 -0
- package/dist/op/activity-failure.d.ts.map +1 -0
- package/dist/op/activity-profiles.d.ts +118 -0
- package/dist/op/activity-profiles.d.ts.map +1 -0
- package/dist/op/activity-registry.d.ts +22 -38
- package/dist/op/activity-registry.d.ts.map +1 -1
- package/dist/op/activity-runtime.d.ts +3 -14
- package/dist/op/activity-runtime.d.ts.map +1 -1
- package/dist/op/builders.d.ts +85 -30
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/change-signal.d.ts +91 -0
- package/dist/op/change-signal.d.ts.map +1 -0
- package/dist/op/composites/apply-op.d.ts +118 -0
- package/dist/op/composites/apply-op.d.ts.map +1 -0
- package/dist/op/composites/converge-op.d.ts +120 -0
- package/dist/op/composites/converge-op.d.ts.map +1 -0
- package/dist/op/composites/index.d.ts +26 -0
- package/dist/op/composites/index.d.ts.map +1 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts +78 -0
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -0
- package/dist/op/composites/pipeline-audit-op.d.ts +50 -0
- package/dist/op/composites/pipeline-audit-op.d.ts.map +1 -0
- package/dist/op/composites/reconcile-op.d.ts +57 -0
- package/dist/op/composites/reconcile-op.d.ts.map +1 -0
- package/dist/op/composites/watch-op.d.ts +60 -0
- package/dist/op/composites/watch-op.d.ts.map +1 -0
- package/dist/op/composites/workflow-audit-op.d.ts +57 -0
- package/dist/op/composites/workflow-audit-op.d.ts.map +1 -0
- package/dist/op/converge-rule.d.ts +12 -10
- package/dist/op/converge-rule.d.ts.map +1 -1
- package/dist/op/cron.d.ts +51 -0
- package/dist/op/cron.d.ts.map +1 -0
- package/dist/op/discover.d.ts +9 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/duration.d.ts +11 -0
- package/dist/op/duration.d.ts.map +1 -0
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/gate-name.d.ts +40 -0
- package/dist/op/gate-name.d.ts.map +1 -0
- package/dist/op/gate-summary.d.ts +43 -0
- package/dist/op/gate-summary.d.ts.map +1 -0
- package/dist/op/gate.d.ts +90 -0
- package/dist/op/gate.d.ts.map +1 -0
- package/dist/op/generate-pipeline.d.ts +9 -0
- package/dist/op/generate-pipeline.d.ts.map +1 -1
- package/dist/op/index.d.ts +29 -9
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +114 -28
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-output.d.ts +11 -1
- package/dist/op/local-output.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +185 -0
- package/dist/op/op-ir.d.ts.map +1 -0
- package/dist/op/op-verb-class.d.ts +10 -2
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts +93 -5
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/receipt-store.d.ts +1 -1
- package/dist/op/receipt-store.d.ts.map +1 -1
- package/dist/op/resource.d.ts +15 -1
- package/dist/op/resource.d.ts.map +1 -1
- package/dist/op/runtime.d.ts +200 -0
- package/dist/op/runtime.d.ts.map +1 -0
- package/dist/op/runtimes/local.d.ts +29 -0
- package/dist/op/runtimes/local.d.ts.map +1 -0
- package/dist/op/step-output-ref.d.ts +15 -13
- package/dist/op/step-output-ref.d.ts.map +1 -1
- package/dist/op/types.d.ts +96 -29
- package/dist/op/types.d.ts.map +1 -1
- package/dist/ownership.d.ts +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/serializer-walker.d.ts.map +1 -1
- package/dist/terraform/bridge.d.ts +26 -7
- package/dist/terraform/bridge.d.ts.map +1 -1
- package/dist/terraform/carve-provider.d.ts +28 -2
- package/dist/terraform/carve-provider.d.ts.map +1 -1
- package/dist/terraform/data-source-shape.d.ts +77 -0
- package/dist/terraform/data-source-shape.d.ts.map +1 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/providers/kubernetes.d.ts +5 -0
- package/dist/terraform/providers/kubernetes.d.ts.map +1 -1
- package/dist/terraform/tier-map.d.ts +16 -4
- package/dist/terraform/tier-map.d.ts.map +1 -1
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/package.json +6 -1
- package/src/audit/catalog.test.ts +79 -3
- package/src/audit/catalog.ts +111 -13
- package/src/audit/core.test.ts +26 -0
- package/src/audit/core.ts +84 -18
- package/src/audit/discover.test.ts +39 -0
- package/src/audit/discover.ts +202 -18
- package/src/audit/lineage.ts +100 -0
- package/src/audit/prior-art.ts +153 -0
- package/src/audit/proof.test.ts +67 -0
- package/src/audit/proof.ts +70 -0
- package/src/audit/report-html.ts +9 -4
- package/src/audit/report-model.ts +16 -2
- package/src/audit/report.test.ts +33 -0
- package/src/audit/report.ts +5 -3
- package/src/audit/rules-doc.test.ts +34 -2
- package/src/audit/rules-doc.ts +82 -9
- package/src/audit/secrets.ts +15 -3
- package/src/audit/terraform-state.test.ts +144 -0
- package/src/audit/terraform-state.ts +131 -0
- package/src/build.ts +31 -1
- package/src/claimed-fields.test.ts +145 -0
- package/src/claimed-fields.ts +208 -0
- package/src/cli/build-params-cli.ts +2 -2
- package/src/cli/command-group.ts +14 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/.terraform/providers/lock.txt +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/modules/foo/main.tf +1 -0
- package/src/cli/commands/__fixtures__/audit-terraform/infra/variables.tf +3 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +13 -4
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/docs-cli.ts +4 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/codegen/package.ts +1 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/src/package-cli.ts +21 -0
- package/src/cli/commands/__snapshots__/init-lexicon.test.ts.snap +1 -0
- package/src/cli/commands/audit.test.ts +191 -11
- package/src/cli/commands/audit.ts +78 -28
- package/src/cli/commands/build.test.ts +330 -9
- package/src/cli/commands/build.ts +170 -24
- package/src/cli/commands/carve-bridge.test.ts +237 -14
- package/src/cli/commands/carve-bridge.ts +21 -17
- package/src/cli/commands/carve-emit-k8s.test.ts +17 -10
- package/src/cli/commands/check-lexicon-docs.ts +1 -1
- package/src/cli/commands/check-lexicon-examples.test.ts +29 -1
- package/src/cli/commands/check-lexicon-examples.ts +42 -10
- package/src/cli/commands/init-lexicon/templates/codegen.ts +9 -0
- package/src/cli/commands/init-lexicon/templates/project.ts +44 -4
- package/src/cli/commands/init-lexicon.test.ts +97 -2
- package/src/cli/commands/init-lexicon.ts +4 -2
- package/src/cli/commands/init.test.ts +35 -1
- package/src/cli/commands/init.ts +14 -3
- package/src/cli/commands/lint.test.ts +194 -1
- package/src/cli/commands/lint.ts +205 -7
- package/src/cli/commands/onboard.test.ts +75 -0
- package/src/cli/commands/onboard.ts +54 -23
- package/src/cli/handlers/build.test.ts +81 -1
- package/src/cli/handlers/build.ts +15 -1
- package/src/cli/handlers/graph.test.ts +3 -3
- package/src/cli/handlers/lifecycle.test.ts +195 -12
- package/src/cli/handlers/lifecycle.ts +123 -6
- package/src/cli/handlers/misc.ts +1 -1
- package/src/cli/handlers/operator.test.ts +183 -11
- package/src/cli/handlers/operator.ts +341 -55
- package/src/cli/handlers/run.test.ts +568 -1295
- package/src/cli/handlers/run.ts +446 -912
- package/src/cli/main.test.ts +22 -16
- package/src/cli/main.ts +66 -33
- package/src/cli/mcp/op-tools.ts +147 -88
- package/src/cli/mcp/resource-handlers.ts +10 -37
- package/src/cli/mcp/resources/context.ts +11 -12
- package/src/cli/mcp/server.test.ts +25 -27
- package/src/cli/mcp/server.ts +2 -2
- package/src/cli/plugins.test.ts +68 -2
- package/src/cli/plugins.ts +39 -0
- package/src/cli/registry.ts +40 -9
- package/src/codegen/docs.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.test.ts +1 -1
- package/src/codegen/generate-post-synth-barrel.ts +1 -1
- package/src/components/README.md +4 -3
- package/src/components/__fixtures__/neo4j-fanout.json +1 -1
- package/src/components/auto-release.test.ts +4 -20
- package/src/components/auto-release.ts +17 -42
- package/src/components/capability.ts +4 -4
- package/src/components/cli-support.test.ts +28 -12
- package/src/components/cli-support.ts +60 -47
- package/src/components/component-schema.test.ts +18 -2
- package/src/components/component.schema.json +18 -5
- package/src/components/component.test.ts +2 -2
- package/src/components/component.ts +27 -7
- package/src/components/config-defaults.test.ts +2 -2
- package/src/components/driver-output.ts +14 -2
- package/src/components/driver.test.ts +109 -20
- package/src/components/driver.ts +201 -84
- package/src/components/index.ts +1 -6
- package/src/components/manifest-persistence.test.ts +2 -20
- package/src/components/manifest-persistence.ts +4 -24
- package/src/components/pilots/neo4j-fanout.pilot.ts +3 -3
- package/src/components/pilots/pilots-lint-clean.test.ts +11 -10
- package/src/components/run-progress.ts +6 -6
- package/src/components/verbs/run-agent.test.ts +19 -0
- package/src/components/verbs/run-agent.ts +12 -24
- package/src/components/verbs/verify.ts +2 -2
- package/src/deep-observation.test.ts +75 -0
- package/src/deep-observation.ts +48 -0
- package/src/detectLexicon.ts +18 -1
- package/src/discovery/collect.test.ts +3 -3
- package/src/discovery/files.ts +4 -4
- package/src/discovery/fold-import.test.ts +1 -1
- package/src/discovery/fold-import.ts +105 -2
- package/src/discovery/param-deps.test.ts +112 -1
- package/src/discovery/param-deps.ts +193 -0
- package/src/discovery/sandbox/bundle.ts +15 -1
- package/src/discovery/sandbox/config-wire.test.ts +2 -2
- package/src/discovery/sandbox/config-wire.ts +2 -2
- package/src/fold/fold.test.ts +56 -0
- package/src/fold/foldable-helpers.ts +82 -2
- package/src/fold-provenance-exclusion.test.ts +186 -0
- package/src/fold-provenance.test.ts +495 -0
- package/src/fold-provenance.ts +441 -0
- package/src/graph-ops.test.ts +3 -3
- package/src/graph-ops.ts +1 -1
- package/src/held-elsewhere.test.ts +102 -0
- package/src/held-elsewhere.ts +114 -0
- package/src/index.ts +3 -0
- package/src/kubectl-context.ts +3 -3
- package/src/lexicon-config.test.ts +5 -5
- package/src/lexicon-config.ts +4 -4
- package/src/lexicon-plugin-helpers.ts +1 -1
- package/src/lexicon.ts +296 -16
- package/src/lifecycle/change-set.test.ts +49 -0
- package/src/lifecycle/change-set.ts +67 -0
- package/src/lifecycle/converge-ledger.ts +1 -1
- package/src/lifecycle/deep-diff.test.ts +267 -14
- package/src/lifecycle/deep-diff.ts +217 -14
- package/src/lifecycle/deep-observe.test.ts +3 -1
- package/src/lifecycle/deep-observe.ts +16 -6
- package/src/lifecycle/gate-ledger.test.ts +74 -2
- package/src/lifecycle/gate-ledger.ts +154 -36
- package/src/lifecycle/index.ts +1 -0
- package/src/lifecycle/release-ledger.ts +2 -2
- package/src/lifecycle/run-ledger.test.ts +268 -0
- package/src/lifecycle/run-ledger.ts +201 -0
- package/src/lifecycle/symptoms.ts +3 -3
- package/src/lint/config.test.ts +82 -1
- package/src/lint/config.ts +112 -3
- package/src/lint/pipeline-change-gate.test.ts +2 -2
- package/src/lint/policy.test.ts +1 -1
- package/src/lint/post-synth.test.ts +31 -0
- package/src/lint/post-synth.ts +54 -1
- package/src/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.ts +2 -2
- package/src/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.ts +1 -1
- package/src/lint/rules/comp/comp.test.ts +27 -1
- package/src/lint/rules/comp/comp004-gate-needs-durable-runtime.ts +76 -0
- package/src/lint/rules/comp/index.ts +3 -3
- package/src/lint/rules/op/index.ts +23 -0
- package/src/lint/rules/op/ops012-activity-contract.test.ts +161 -0
- package/src/lint/rules/op/ops012-activity-contract.ts +64 -0
- package/src/lint/rules/op/ops013-step-output-ref.test.ts +237 -0
- package/src/lint/rules/op/ops013-step-output-ref.ts +98 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.test.ts +263 -0
- package/src/lint/rules/op/ops014-converge-rule-refusals.ts +179 -0
- package/src/lint/rules/op/support.ts +11 -0
- package/src/lint/suppressions.test.ts +163 -0
- package/src/lint/suppressions.ts +204 -0
- package/src/live-endpoint.ts +1 -1
- package/src/op/activities/activity-contracts.ts +66 -0
- package/src/op/activities/apply.test.ts +567 -0
- package/src/op/activities/apply.ts +662 -0
- package/src/op/activities/build.ts +26 -0
- package/src/op/activities/converge.test.ts +330 -0
- package/src/op/activities/converge.ts +449 -0
- package/src/op/activities/env-teardown.test.ts +187 -0
- package/src/op/activities/env-teardown.ts +171 -0
- package/src/op/activities/guard-validate.test.ts +139 -0
- package/src/op/activities/guard-validate.ts +223 -0
- package/src/op/activities/http-check.test.ts +48 -0
- package/src/op/activities/http-check.ts +55 -0
- package/src/op/activities/index.ts +119 -0
- package/src/op/activities/lexicon-upgrade.test.ts +492 -0
- package/src/op/activities/lexicon-upgrade.ts +673 -0
- package/src/op/activities/lifecycle.ts +85 -0
- package/src/op/activities/pipeline-audit.test.ts +67 -0
- package/src/op/activities/pipeline-audit.ts +201 -0
- package/src/op/activities/policy.test.ts +19 -0
- package/src/op/activities/policy.ts +37 -0
- package/src/op/activities/reconcile.test.ts +161 -0
- package/src/op/activities/reconcile.ts +354 -0
- package/src/op/activities/shell.ts +26 -0
- package/src/op/activities/teardown.ts +22 -0
- package/src/op/activities/util.ts +6 -0
- package/src/op/activities/wait.ts +69 -0
- package/src/op/activities/workflow-audit.test.ts +90 -0
- package/src/op/activities/workflow-audit.ts +203 -0
- package/src/op/activity-contract-registry.test.ts +98 -0
- package/src/op/activity-contract-registry.ts +114 -0
- package/src/op/activity-contract.test.ts +1 -1
- package/src/op/activity-contract.ts +37 -33
- package/src/op/activity-failure.ts +34 -0
- package/src/op/activity-profiles.test.ts +56 -0
- package/src/op/activity-profiles.ts +116 -0
- package/src/op/activity-registry.test.ts +37 -28
- package/src/op/activity-registry.ts +27 -56
- package/src/op/activity-runtime.ts +3 -47
- package/src/op/builders-exports.test.ts +0 -49
- package/src/op/builders-typed.test.ts +164 -0
- package/src/op/builders.ts +125 -41
- package/src/op/change-signal.test.ts +117 -0
- package/src/op/change-signal.ts +169 -0
- package/src/op/composites/apply-op.ts +218 -0
- package/src/op/composites/composites.test.ts +379 -0
- package/src/op/composites/converge-op.test.ts +168 -0
- package/src/op/composites/converge-op.ts +214 -0
- package/src/op/composites/index.ts +26 -0
- package/src/op/composites/lexicon-upgrade-op.test.ts +68 -0
- package/src/op/composites/lexicon-upgrade-op.ts +134 -0
- package/src/op/composites/pipeline-audit-op.test.ts +25 -0
- package/src/op/composites/pipeline-audit-op.ts +78 -0
- package/src/op/composites/reconcile-op.test.ts +51 -0
- package/src/op/composites/reconcile-op.ts +110 -0
- package/src/op/composites/watch-op.ts +108 -0
- package/src/op/composites/workflow-audit-op.test.ts +25 -0
- package/src/op/composites/workflow-audit-op.ts +88 -0
- package/src/op/converge-rule.ts +12 -10
- package/src/op/cron.test.ts +128 -0
- package/src/op/cron.ts +149 -0
- package/src/op/discover-root.test.ts +105 -1
- package/src/op/discover.test.ts +6 -2
- package/src/op/discover.ts +84 -16
- package/src/op/duration.ts +21 -0
- package/src/op/effect-step.test.ts +29 -14
- package/src/op/emulator-lifecycle.ts +1 -2
- package/src/op/gate-name.test.ts +65 -0
- package/src/op/gate-name.ts +60 -0
- package/src/op/gate-summary.ts +84 -0
- package/src/op/gate.ts +155 -0
- package/src/op/generate-pipeline.test.ts +65 -3
- package/src/op/generate-pipeline.ts +19 -2
- package/src/op/index.ts +48 -8
- package/src/op/local-executor.test.ts +178 -34
- package/src/op/local-executor.ts +371 -102
- package/src/op/local-output.test.ts +95 -11
- package/src/op/local-output.ts +33 -4
- package/src/op/op-ir.test.ts +292 -0
- package/src/op/op-ir.ts +419 -0
- package/src/op/op-verb-class.test.ts +2 -2
- package/src/op/op-verb-class.ts +19 -5
- package/src/op/op.test.ts +28 -7
- package/src/op/operator.test.ts +543 -6
- package/src/op/operator.ts +203 -20
- package/src/op/receipt-store.ts +1 -1
- package/src/op/resource.ts +20 -2
- package/src/op/runtime.ts +203 -0
- package/src/op/runtimes/local.test.ts +181 -0
- package/src/op/runtimes/local.ts +212 -0
- package/src/op/step-output-ref.ts +15 -13
- package/src/op/types.ts +106 -26
- package/src/ownership.ts +1 -1
- package/src/provenance.test.ts +6 -0
- package/src/provenance.ts +21 -1
- package/src/serializer-walker.test.ts +42 -0
- package/src/serializer-walker.ts +21 -2
- package/src/terraform/aws-resources.test.ts +13 -4
- package/src/terraform/bridge.test.ts +22 -9
- package/src/terraform/bridge.ts +89 -28
- package/src/terraform/carve-provider.ts +38 -2
- package/src/terraform/data-source-shape.ts +95 -0
- package/src/terraform/graph.ts +35 -7
- package/src/terraform/providers/kubernetes.ts +48 -2
- package/src/terraform/tier-map.ts +21 -6
- package/src/terraform/types.ts +8 -0
- package/dist/cli/handlers/op-progress.d.ts +0 -90
- package/dist/cli/handlers/op-progress.d.ts.map +0 -1
- package/dist/cli/handlers/run-client.d.ts +0 -127
- package/dist/cli/handlers/run-client.d.ts.map +0 -1
- package/dist/cli/handlers/run-report.d.ts +0 -5
- package/dist/cli/handlers/run-report.d.ts.map +0 -1
- package/dist/components/temporal-codegen-loader.d.ts +0 -27
- package/dist/components/temporal-codegen-loader.d.ts.map +0 -1
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts +0 -37
- package/dist/lint/rules/comp/comp004-gate-needs-temporal.d.ts.map +0 -1
- package/src/cli/handlers/op-progress.test.ts +0 -268
- package/src/cli/handlers/op-progress.ts +0 -248
- package/src/cli/handlers/run-client.test.ts +0 -82
- package/src/cli/handlers/run-client.ts +0 -219
- package/src/cli/handlers/run-report.test.ts +0 -62
- package/src/cli/handlers/run-report.ts +0 -122
- package/src/components/temporal-codegen-loader.ts +0 -41
- package/src/lint/rules/comp/comp004-gate-needs-temporal.ts +0 -66
|
@@ -5,6 +5,7 @@ import { tmpdir } from "os";
|
|
|
5
5
|
import { join } from "path";
|
|
6
6
|
import { carveBridge, formatCarveBridge } from "./carve-bridge";
|
|
7
7
|
import { loadHcl2json } from "../../terraform/parse";
|
|
8
|
+
import { registerCarveProvider } from "../../terraform/carve-provider";
|
|
8
9
|
import { readCarveManifest, writeCarveManifest, type CarveManifest } from "../../terraform/manifest";
|
|
9
10
|
|
|
10
11
|
let parserAvailable = false;
|
|
@@ -195,36 +196,258 @@ describe("carveBridge", () => {
|
|
|
195
196
|
}
|
|
196
197
|
});
|
|
197
198
|
|
|
198
|
-
test("refuses a
|
|
199
|
+
test("refuses a dotted-identity type no provider declares a shape for (#2015, #2034)", async () => {
|
|
199
200
|
if (!parserAvailable) return;
|
|
200
|
-
|
|
201
|
+
// A dotted identity attribute is a path into nested values, and a data body
|
|
202
|
+
// is flat `attr = value` — `spec.metadata.name = "x"` is not valid HCL. The
|
|
203
|
+
// guard now turns on the missing shape, not on the dot, so the message says
|
|
204
|
+
// what would lift it.
|
|
205
|
+
const unregister = registerCarveProvider({
|
|
206
|
+
name: "carve-bridge-test-nested",
|
|
207
|
+
tfTypePrefixes: ["nested_"],
|
|
208
|
+
lexicon: "aws",
|
|
209
|
+
tiers: { nested_widget: { tier: 1, mapsTo: "Test::Widget" } },
|
|
210
|
+
identityAttrs: { nested_widget: "spec.metadata.name" },
|
|
211
|
+
});
|
|
212
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-bridge-nested-"));
|
|
201
213
|
try {
|
|
202
|
-
// `kubernetes_manifest` identifies itself by `manifest.metadata.name`.
|
|
203
|
-
// Rendering that into a data body produced `manifest.metadata.name = "x"`,
|
|
204
|
-
// which is not valid HCL — and the provider has no manifest data source.
|
|
205
214
|
writeFileSync(
|
|
206
215
|
join(dir, "main.tf"),
|
|
207
|
-
`resource "
|
|
208
|
-
` manifest = {\n` +
|
|
209
|
-
` apiVersion = "v1"\n` +
|
|
210
|
-
` kind = "ConfigMap"\n` +
|
|
211
|
-
` metadata = { name = "demo-config" }\n` +
|
|
212
|
-
` }\n` +
|
|
213
|
-
`}\n`,
|
|
216
|
+
`resource "nested_widget" "demo" {\n spec {\n metadata {\n name = "demo"\n }\n }\n}\n`,
|
|
214
217
|
);
|
|
215
218
|
const out = join(dir, "carveout");
|
|
216
|
-
const res = await carveBridge({ from: dir, select: "
|
|
219
|
+
const res = await carveBridge({ from: dir, select: "nested_widget.demo", output: out });
|
|
217
220
|
|
|
218
221
|
expect(res.ok).toBe(false);
|
|
219
222
|
expect(res.error).toContain("cannot be bridged");
|
|
220
|
-
expect(res.error).toContain("
|
|
223
|
+
expect(res.error).toContain("spec.metadata.name");
|
|
224
|
+
expect(res.error).toContain("no carve provider declares a data-source shape for it");
|
|
225
|
+
expect(res.error).toContain("dataSourceShapes");
|
|
221
226
|
expect(res.plan).toBeUndefined();
|
|
222
227
|
expect(existsSync(out)).toBe(false);
|
|
228
|
+
} finally {
|
|
229
|
+
unregister();
|
|
230
|
+
rmSync(dir, { recursive: true, force: true });
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* `kubernetes_manifest` reads back through a different type (#2034). The
|
|
238
|
+
* kubernetes provider ships no `kubernetes_manifest` data source — verified
|
|
239
|
+
* against hashicorp/kubernetes v3.2.1 — so the bridge renders
|
|
240
|
+
* `data "kubernetes_resource"` from the manifest's own apiVersion, kind and
|
|
241
|
+
* metadata, and repoints survivors at that data source's attribute path.
|
|
242
|
+
*/
|
|
243
|
+
describe("carveBridge — kubernetes_manifest (#2034)", () => {
|
|
244
|
+
const MANIFEST_TF = `resource "kubernetes_manifest" "app_config" {
|
|
245
|
+
manifest = {
|
|
246
|
+
apiVersion = "v1"
|
|
247
|
+
kind = "ConfigMap"
|
|
248
|
+
metadata = {
|
|
249
|
+
name = "app-config"
|
|
250
|
+
namespace = "apps"
|
|
251
|
+
}
|
|
252
|
+
data = {
|
|
253
|
+
LOG_LEVEL = "info"
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
`;
|
|
258
|
+
// Three shapes of inbound reference: the issue's own example, one deeper into
|
|
259
|
+
// `object`, and one through `manifest` — the attribute the data source does
|
|
260
|
+
// NOT have, which is why the rewrite maps it rather than only swapping heads.
|
|
261
|
+
const SURVIVOR_TF = `resource "kubernetes_config_map" "mirror" {
|
|
262
|
+
metadata {
|
|
263
|
+
name = kubernetes_manifest.app_config.object.metadata.name
|
|
264
|
+
namespace = "apps"
|
|
265
|
+
}
|
|
266
|
+
data = {
|
|
267
|
+
LOG_LEVEL = kubernetes_manifest.app_config.manifest.data.LOG_LEVEL
|
|
268
|
+
UPSTREAM = kubernetes_manifest.app_config.object.data.LOG_LEVEL
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
`;
|
|
272
|
+
const OUTPUTS_TF = `output "app_config_name" {
|
|
273
|
+
value = kubernetes_manifest.app_config.object.metadata.name
|
|
274
|
+
}
|
|
275
|
+
`;
|
|
276
|
+
|
|
277
|
+
async function withManifestEstate<T>(fn: (dir: string) => Promise<T>): Promise<T> {
|
|
278
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-bridge-manifest-"));
|
|
279
|
+
try {
|
|
280
|
+
writeFileSync(join(dir, "manifest.tf"), MANIFEST_TF);
|
|
281
|
+
writeFileSync(join(dir, "survivor.tf"), SURVIVOR_TF);
|
|
282
|
+
writeFileSync(join(dir, "outputs.tf"), OUTPUTS_TF);
|
|
283
|
+
return await fn(dir);
|
|
284
|
+
} finally {
|
|
285
|
+
rmSync(dir, { recursive: true, force: true });
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
test("bridges to a data \"kubernetes_resource\" block built from the manifest body", async () => {
|
|
290
|
+
if (!parserAvailable) return;
|
|
291
|
+
await withManifestEstate(async (dir) => {
|
|
292
|
+
const out = join(dir, "carveout");
|
|
293
|
+
const res = await carveBridge({ from: dir, select: "kubernetes_manifest.app_config", output: out });
|
|
294
|
+
expect(res.ok).toBe(true);
|
|
295
|
+
|
|
296
|
+
// The data source is the provider's generic read, not the carved type.
|
|
297
|
+
expect(res.plan!.dataSources).toHaveLength(1);
|
|
298
|
+
expect(res.plan!.dataSources[0]).toMatchObject({
|
|
299
|
+
address: "kubernetes_manifest.app_config",
|
|
300
|
+
type: "kubernetes_resource",
|
|
301
|
+
name: "app_config",
|
|
302
|
+
});
|
|
303
|
+
expect(res.plan!.dataSources[0].hcl).toBe(
|
|
304
|
+
`data "kubernetes_resource" "app_config" {\n` +
|
|
305
|
+
` api_version = "v1"\n` +
|
|
306
|
+
` kind = "ConfigMap"\n` +
|
|
307
|
+
`\n` +
|
|
308
|
+
` metadata {\n` +
|
|
309
|
+
` name = "app-config"\n` +
|
|
310
|
+
` namespace = "apps"\n` +
|
|
311
|
+
` }\n` +
|
|
312
|
+
`}`,
|
|
313
|
+
);
|
|
314
|
+
expect(formatCarveBridge(res)).toContain(
|
|
315
|
+
"data.kubernetes_resource.app_config (was kubernetes_manifest.app_config)",
|
|
316
|
+
);
|
|
317
|
+
});
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
test("the emitted data source parses as HCL and is terraform-fmt clean", async () => {
|
|
321
|
+
if (!parserAvailable) return;
|
|
322
|
+
await withManifestEstate(async (dir) => {
|
|
323
|
+
const out = join(dir, "carveout");
|
|
324
|
+
await carveBridge({ from: dir, select: "kubernetes_manifest.app_config", output: out });
|
|
325
|
+
const dsPath = join(out, "kubernetes_manifest-app_config-datasources.tf");
|
|
326
|
+
const hcl = readFileSync(dsPath, "utf-8");
|
|
327
|
+
|
|
328
|
+
// The repo's own parser: `metadata` has to come out as a block, since the
|
|
329
|
+
// provider declares it Block List (Min 1, Max 1), not an attribute.
|
|
330
|
+
const parsed = await (await loadHcl2json()).parse("datasources.tf", hcl);
|
|
331
|
+
const ds = (parsed.data as Record<string, Record<string, unknown[]>>).kubernetes_resource.app_config[0] as Record<
|
|
332
|
+
string,
|
|
333
|
+
unknown
|
|
334
|
+
>;
|
|
335
|
+
expect(ds.api_version).toBe("v1");
|
|
336
|
+
expect(ds.kind).toBe("ConfigMap");
|
|
337
|
+
expect(ds.metadata).toEqual([{ name: "app-config", namespace: "apps" }]);
|
|
338
|
+
|
|
339
|
+
// And Terraform's own formatter accepts it byte for byte.
|
|
340
|
+
try {
|
|
341
|
+
execFileSync("terraform", ["fmt", "-check", "-diff", dsPath], { stdio: "pipe" });
|
|
342
|
+
} catch (err) {
|
|
343
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") return; // no terraform on this machine
|
|
344
|
+
throw err;
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
test("survivor references follow the data source's own attribute path", async () => {
|
|
350
|
+
if (!parserAvailable) return;
|
|
351
|
+
await withManifestEstate(async (dir) => {
|
|
352
|
+
const out = join(dir, "carveout");
|
|
353
|
+
const res = await carveBridge({ from: dir, select: "kubernetes_manifest.app_config", output: out });
|
|
354
|
+
expect(res.ok).toBe(true);
|
|
355
|
+
|
|
356
|
+
const survivor = readFileSync(join(out, "survivor.tf"), "utf-8");
|
|
357
|
+
// The issue's example, and a reference that goes deeper into `object`.
|
|
358
|
+
expect(survivor).toContain("name = data.kubernetes_resource.app_config.object.metadata.name");
|
|
359
|
+
expect(survivor).toContain("UPSTREAM = data.kubernetes_resource.app_config.object.data.LOG_LEVEL");
|
|
360
|
+
// `manifest` is an attribute of the resource that the data source does not
|
|
361
|
+
// have; left alone it would be an "Unsupported attribute" at validate.
|
|
362
|
+
expect(survivor).toContain("LOG_LEVEL = data.kubernetes_resource.app_config.object.data.LOG_LEVEL");
|
|
363
|
+
expect(survivor).not.toContain(".manifest.");
|
|
364
|
+
expect(survivor).not.toMatch(/(?<!data\.)\bkubernetes_manifest\.app_config\b/);
|
|
365
|
+
|
|
366
|
+
// An output reading the manifest is repointed the same way (#1638).
|
|
367
|
+
expect(res.plan!.outputRewrites).toEqual(["output.app_config_name"]);
|
|
368
|
+
expect(readFileSync(join(out, "outputs.tf"), "utf-8")).toContain(
|
|
369
|
+
"value = data.kubernetes_resource.app_config.object.metadata.name",
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
// The carved block leaves the survivor source, as for any other type.
|
|
373
|
+
expect(res.plan!.excised).toEqual(["kubernetes_manifest.app_config"]);
|
|
374
|
+
expect(readFileSync(join(out, "manifest.tf"), "utf-8").trim()).toBe("");
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
test("a namespace-less manifest omits the optional argument", async () => {
|
|
379
|
+
if (!parserAvailable) return;
|
|
380
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-bridge-clusterwide-"));
|
|
381
|
+
try {
|
|
382
|
+
// A cluster-scoped kind has no namespace, and `metadata.namespace` is
|
|
383
|
+
// optional on the data source — so it is left out, not emitted empty.
|
|
384
|
+
writeFileSync(
|
|
385
|
+
join(dir, "main.tf"),
|
|
386
|
+
`resource "kubernetes_manifest" "reader" {\n` +
|
|
387
|
+
` manifest = {\n` +
|
|
388
|
+
` apiVersion = "rbac.authorization.k8s.io/v1"\n` +
|
|
389
|
+
` kind = "ClusterRole"\n` +
|
|
390
|
+
` metadata = {\n` +
|
|
391
|
+
` name = "reader"\n` +
|
|
392
|
+
` }\n` +
|
|
393
|
+
` }\n` +
|
|
394
|
+
`}\n`,
|
|
395
|
+
);
|
|
396
|
+
writeFileSync(
|
|
397
|
+
join(dir, "outputs.tf"),
|
|
398
|
+
`output "reader" {\n value = kubernetes_manifest.reader.object.metadata.name\n}\n`,
|
|
399
|
+
);
|
|
400
|
+
const out = join(dir, "carveout");
|
|
401
|
+
const res = await carveBridge({ from: dir, select: "kubernetes_manifest.reader", output: out });
|
|
402
|
+
expect(res.ok).toBe(true);
|
|
403
|
+
const hcl = res.plan!.dataSources[0].hcl;
|
|
404
|
+
expect(hcl).toContain('api_version = "rbac.authorization.k8s.io/v1"');
|
|
405
|
+
expect(hcl).toContain('name = "reader"');
|
|
406
|
+
expect(hcl).not.toContain("namespace");
|
|
407
|
+
} finally {
|
|
408
|
+
rmSync(dir, { recursive: true, force: true });
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("an interpolated manifest name falls back to the TODO body, never a half-written block", async () => {
|
|
413
|
+
if (!parserAvailable) return;
|
|
414
|
+
const dir = mkdtempSync(join(tmpdir(), "chant-bridge-interp-"));
|
|
415
|
+
try {
|
|
416
|
+
writeFileSync(
|
|
417
|
+
join(dir, "main.tf"),
|
|
418
|
+
`variable "suffix" {\n type = string\n}\n\n` +
|
|
419
|
+
`resource "kubernetes_manifest" "app_config" {\n` +
|
|
420
|
+
` manifest = {\n` +
|
|
421
|
+
` apiVersion = "v1"\n` +
|
|
422
|
+
` kind = "ConfigMap"\n` +
|
|
423
|
+
` metadata = {\n` +
|
|
424
|
+
` name = "app-\${var.suffix}"\n` +
|
|
425
|
+
` }\n` +
|
|
426
|
+
` }\n` +
|
|
427
|
+
`}\n`,
|
|
428
|
+
);
|
|
429
|
+
writeFileSync(
|
|
430
|
+
join(dir, "outputs.tf"),
|
|
431
|
+
`output "name" {\n value = kubernetes_manifest.app_config.object.metadata.name\n}\n`,
|
|
432
|
+
);
|
|
433
|
+
const out = join(dir, "carveout");
|
|
434
|
+
const res = await carveBridge({ from: dir, select: "kubernetes_manifest.app_config", output: out });
|
|
435
|
+
expect(res.ok).toBe(true);
|
|
436
|
+
// `metadata.name` is required on the data source; guessing it would be
|
|
437
|
+
// worse than saying so.
|
|
438
|
+
expect(res.plan!.dataSources[0].hcl).toContain("# TODO: identify the resource");
|
|
439
|
+
expect(res.plan!.dataSources[0].hcl).not.toContain("api_version");
|
|
440
|
+
// The reference is still repointed, so the survivor plan is one edit away.
|
|
441
|
+
expect(readFileSync(join(out, "outputs.tf"), "utf-8")).toContain(
|
|
442
|
+
"value = data.kubernetes_resource.app_config.object.metadata.name",
|
|
443
|
+
);
|
|
223
444
|
} finally {
|
|
224
445
|
rmSync(dir, { recursive: true, force: true });
|
|
225
446
|
}
|
|
226
447
|
});
|
|
448
|
+
});
|
|
227
449
|
|
|
450
|
+
describe("carveBridge — formatting", () => {
|
|
228
451
|
test("formatCarveBridge summarizes data sources, rewires, and safety", async () => {
|
|
229
452
|
if (!parserAvailable) return;
|
|
230
453
|
await withEstate(async (dir) => {
|
|
@@ -14,8 +14,8 @@ import { join, basename, relative, resolve } from "path";
|
|
|
14
14
|
import { cdkNotSupported, isCloudAssembly } from "../../cdk/assembly";
|
|
15
15
|
import { parseTerraformDir, Hcl2JsonNotInstalled } from "../../terraform/parse";
|
|
16
16
|
import { boundaryReport, type CarveReport } from "../../terraform/carve";
|
|
17
|
-
import { generateBridge, type BridgePlan, type
|
|
18
|
-
import { identityAttrOf, canBridge } from "../../terraform/tier-map";
|
|
17
|
+
import { generateBridge, type BridgePlan, type CarvedDataSource } from "../../terraform/bridge";
|
|
18
|
+
import { identityAttrOf, canBridge, dataSourceShapeOf } from "../../terraform/tier-map";
|
|
19
19
|
import { resolveCarveManifest, writeCarveManifest, type CarveManifest } from "../../terraform/manifest";
|
|
20
20
|
import { newFileDiff, unifiedDiff } from "../../terraform/unified-diff";
|
|
21
21
|
|
|
@@ -76,13 +76,13 @@ export async function carveBridge(opts: CarveBridgeOptions): Promise<CarveBridge
|
|
|
76
76
|
if (!found) return { ok: false, error: `${select} not found in ${opts.from}` };
|
|
77
77
|
report = found;
|
|
78
78
|
|
|
79
|
-
// Refuse a carve set
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
//
|
|
79
|
+
// Refuse a carve set no provider says how to read back. A dotted identity
|
|
80
|
+
// attribute is a path into nested values and a data body is flat
|
|
81
|
+
// `attr = value`, so such a type bridges only once its provider declares a
|
|
82
|
+
// data-source shape — the data type, its arguments and where each comes
|
|
83
|
+
// from in the carved body (#2034). `kubernetes_manifest` declares one now:
|
|
84
|
+
// `data "kubernetes_resource"`, built from the manifest's apiVersion,
|
|
85
|
+
// kind and metadata.
|
|
86
86
|
const carvedTypes = report.carveSet.map((m) => m.type).filter((t): t is string => t !== undefined);
|
|
87
87
|
const unbridgeable = [...new Set(carvedTypes.filter((t) => !canBridge(t)))];
|
|
88
88
|
if (unbridgeable.length) {
|
|
@@ -91,21 +91,25 @@ export async function carveBridge(opts: CarveBridgeOptions): Promise<CarveBridge
|
|
|
91
91
|
error:
|
|
92
92
|
`${select} cannot be bridged: ${unbridgeable
|
|
93
93
|
.map((t) => `${t} identifies itself by \`${identityAttrOf(t)}\``)
|
|
94
|
-
.join(", ")}, a path into nested
|
|
95
|
-
`
|
|
94
|
+
.join(", ")}, a path into nested values that a flat Terraform data source body cannot express, ` +
|
|
95
|
+
`and no carve provider declares a data-source shape for it. A provider contributes one through ` +
|
|
96
|
+
`\`dataSourceShapes\` (see \`kubernetes_manifest\` reading back as \`data "kubernetes_resource"\`, chant issue #2034).`,
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
99
|
|
|
99
|
-
//
|
|
100
|
-
|
|
100
|
+
// How each carved resource is read back, and the literals to render the
|
|
101
|
+
// data-source body from. The shape comes from the provider, the values from
|
|
102
|
+
// the parsed block (`dataSourceValues`, a superset of the old identity).
|
|
103
|
+
const readBacks = new Map<string, CarvedDataSource>();
|
|
101
104
|
for (const node of graph.nodes) {
|
|
102
|
-
if (node.type
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
if (!node.type) continue;
|
|
106
|
+
const shape = dataSourceShapeOf(node.type);
|
|
107
|
+
if (!shape) continue;
|
|
108
|
+
readBacks.set(node.address, { shape, values: node.dataSourceValues ?? {} });
|
|
105
109
|
}
|
|
106
110
|
|
|
107
111
|
const files = listTfFiles(opts.from).map((path) => ({ path, content: readFileSync(path, "utf-8") }));
|
|
108
|
-
plan = generateBridge(report, files,
|
|
112
|
+
plan = generateBridge(report, files, readBacks);
|
|
109
113
|
} catch (err) {
|
|
110
114
|
if (err instanceof Hcl2JsonNotInstalled) return { ok: false, error: err.message };
|
|
111
115
|
return { ok: false, error: `Failed to build the bridge: ${err instanceof Error ? err.message : String(err)}` };
|
|
@@ -239,24 +239,31 @@ describe("carve emit — kubernetes_manifest (#999)", () => {
|
|
|
239
239
|
});
|
|
240
240
|
});
|
|
241
241
|
|
|
242
|
-
test("bridge
|
|
242
|
+
test("emit then bridge compose on the same manifest (#2034)", async () => {
|
|
243
243
|
if (!parserAvailable) return;
|
|
244
244
|
await withEstate(async (dir) => {
|
|
245
245
|
const out = join(dir, "carveout");
|
|
246
246
|
const emitted = await carveEmit(
|
|
247
|
-
{ from: dir, select: "kubernetes_manifest.
|
|
247
|
+
{ from: dir, select: "kubernetes_manifest.web_cert", statePath: join(dir, "terraform.tfstate"), output: out },
|
|
248
248
|
{ plugins: [], liveImport: fakeImport() },
|
|
249
249
|
);
|
|
250
250
|
expect(emitted.ok).toBe(true);
|
|
251
251
|
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
expect(bridged.
|
|
258
|
-
expect(bridged.
|
|
259
|
-
expect(existsSync(join(out, "kubernetes_manifest-
|
|
252
|
+
// Bridge used to refuse here: `manifest.metadata.name` is a path into the
|
|
253
|
+
// body, and a data-source body is flat `attr = value`. It now reads the
|
|
254
|
+
// manifest back through the shape the kubernetes provider declares, so
|
|
255
|
+
// the target the emit manifest recorded bridges without --select.
|
|
256
|
+
const bridged = await carveBridge({ from: dir, output: out });
|
|
257
|
+
expect(bridged.ok).toBe(true);
|
|
258
|
+
expect(bridged.plan!.target).toBe("kubernetes_manifest.web_cert");
|
|
259
|
+
expect(existsSync(join(out, "kubernetes_manifest-web_cert-runbook.md"))).toBe(true);
|
|
260
|
+
|
|
261
|
+
// Nothing reads the Certificate, so there is no data source to write —
|
|
262
|
+
// but its own block still has to leave the survivor source, or the next
|
|
263
|
+
// apply re-creates what `terraform state rm` released.
|
|
264
|
+
expect(bridged.plan!.dataSources).toEqual([]);
|
|
265
|
+
expect(bridged.plan!.excised).toEqual(["kubernetes_manifest.web_cert"]);
|
|
266
|
+
expect(readFileSync(join(out, "main.tf"), "utf-8")).not.toContain('resource "kubernetes_manifest" "web_cert"');
|
|
260
267
|
});
|
|
261
268
|
});
|
|
262
269
|
});
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The contract used to check documentation by counting files — "at least 1
|
|
5
5
|
* .mdx page" at tier 1, "at least 8" at tier 2 — and never opened one. That
|
|
6
6
|
* counts a page nothing links to exactly the same as a page a reader can
|
|
7
|
-
* actually find, so azure,
|
|
7
|
+
* actually find, so azure, helm and github each accumulated
|
|
8
8
|
* hand-added pages that appear in no sidebar and are reachable only by typing
|
|
9
9
|
* their URL. Azure's getting-started, resource reference and composites pages
|
|
10
10
|
* were all invisible while its ≥8-page check passed comfortably — the count
|
|
@@ -119,7 +119,7 @@ export const plainBucket = new Bucket({
|
|
|
119
119
|
const results = await checkExamplesBuild(dir);
|
|
120
120
|
const insecure = results.find((r) => r.example === "insecure");
|
|
121
121
|
expect(insecure?.ok).toBe(false);
|
|
122
|
-
expect(insecure?.detail).toMatch(/post-synth error\(s\)
|
|
122
|
+
expect(insecure?.detail).toMatch(/post-synth error\(s\)/);
|
|
123
123
|
expect(insecure?.detail).toMatch(/WAW042: \[plainBucket\]/);
|
|
124
124
|
});
|
|
125
125
|
|
|
@@ -141,6 +141,34 @@ export const plainBucket = new Bucket({
|
|
|
141
141
|
expect(results.find((r) => r.example === "suppressed")).toMatchObject({ ok: true });
|
|
142
142
|
});
|
|
143
143
|
|
|
144
|
+
// #2101 — the third axis: core's own Op-model checks run over the example's
|
|
145
|
+
// result too, so an example carrying an Op has it validated here rather
|
|
146
|
+
// than only when a user builds the example themselves. The Op below
|
|
147
|
+
// references a step whose activity has no registered contract anywhere,
|
|
148
|
+
// which is exactly what OPS013 exists to refuse.
|
|
149
|
+
test("an example whose Op fails core's own OPS checks fails (#2101)", async () => {
|
|
150
|
+
writeLexiconDirWithExample(dir, "bad-op", {
|
|
151
|
+
"bucket.ts": cleanBucketSource,
|
|
152
|
+
"broken.op.ts": `import { Op, phase, activity, stepOutput } from "@intentius/chant/op";
|
|
153
|
+
|
|
154
|
+
export const brokenOp = Op({
|
|
155
|
+
name: "broken",
|
|
156
|
+
overview: "references a step nothing declares",
|
|
157
|
+
phases: [
|
|
158
|
+
phase("Run", [
|
|
159
|
+
activity("shellCmd", { cmd: stepOutput("nope", "value") }),
|
|
160
|
+
]),
|
|
161
|
+
],
|
|
162
|
+
});
|
|
163
|
+
`,
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const results = await checkExamplesBuild(dir);
|
|
167
|
+
const badOp = results.find((r) => r.example === "bad-op");
|
|
168
|
+
expect(badOp?.ok).toBe(false);
|
|
169
|
+
expect(badOp?.detail).toMatch(/OPS013/);
|
|
170
|
+
});
|
|
171
|
+
|
|
144
172
|
test("an empty src/ directory is skipped, not reported as a failure", async () => {
|
|
145
173
|
writeLexiconDirWithExample(dir, "empty", {});
|
|
146
174
|
const results = await checkExamplesBuild(dir);
|
|
@@ -23,6 +23,14 @@
|
|
|
23
23
|
* diagnostic left at `error` severity fails the example. Warnings do not.
|
|
24
24
|
* An example is what a user copies wholesale; it must not teach a pattern
|
|
25
25
|
* the lexicon it demonstrates flags as an error.
|
|
26
|
+
*
|
|
27
|
+
* #2101 added the third axis: core's own Op-model checks (OPS012/OPS013/
|
|
28
|
+
* OPS014, `../../lint/rules/op/`) run over the same result, as `chant build`
|
|
29
|
+
* runs them, so an example carrying an Op has that Op validated here rather
|
|
30
|
+
* than only when a user builds the example themselves. They are given the
|
|
31
|
+
* activity contracts every loaded lexicon declares, resolved the same way
|
|
32
|
+
* `chant build` resolves them, so a step calling that lexicon's own activity
|
|
33
|
+
* validates against its own schemas.
|
|
26
34
|
*/
|
|
27
35
|
|
|
28
36
|
import { existsSync, readdirSync } from "fs";
|
|
@@ -31,8 +39,11 @@ import { build, type BuildResult } from "../../build";
|
|
|
31
39
|
import { findInfraFiles } from "../../discovery/files";
|
|
32
40
|
import { detectLexicons } from "../../detectLexicon";
|
|
33
41
|
import { loadChantConfig } from "../../config";
|
|
34
|
-
import { loadPlugins } from "../plugins";
|
|
42
|
+
import { loadPlugins, collectBuildRootContributors } from "../plugins";
|
|
35
43
|
import { runPostSynthChecks, type PostSynthDiagnostic } from "../../lint/post-synth";
|
|
44
|
+
import { coreOpChecks } from "../../lint/rules/op";
|
|
45
|
+
import { loadActivityContracts } from "../../op/activity-contract-registry";
|
|
46
|
+
import type { ActivityContract } from "../../op/activity-contract";
|
|
36
47
|
import { applyConfiguredSeverity } from "../../lint/config";
|
|
37
48
|
import type { LexiconPlugin } from "../../lexicon";
|
|
38
49
|
import type { SerializerResult } from "../../serializer";
|
|
@@ -44,18 +55,31 @@ export interface ExampleBuildResult {
|
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/**
|
|
47
|
-
* Run
|
|
48
|
-
*
|
|
49
|
-
* `cli/commands/build.ts` applies — and
|
|
50
|
-
* severity. Project `lint.policies` are not
|
|
51
|
-
* example author's organizational policy, not the
|
|
58
|
+
* Run core's Op-model checks over the whole result, then each plugin's own
|
|
59
|
+
* post-synth checks against that plugin's output — the same scoping and
|
|
60
|
+
* `lint.rules` severity resolution `cli/commands/build.ts` applies — and
|
|
61
|
+
* return what is left at `error` severity. Project `lint.policies` are not
|
|
62
|
+
* run here: those are the example author's organizational policy, not the
|
|
63
|
+
* lexicon's contract.
|
|
52
64
|
*/
|
|
53
65
|
export function postSynthErrors(
|
|
54
66
|
plugins: LexiconPlugin[],
|
|
55
67
|
result: BuildResult,
|
|
56
68
|
lintRules: Parameters<typeof applyConfiguredSeverity>[1],
|
|
69
|
+
activityContracts?: ReadonlyMap<string, ActivityContract>,
|
|
57
70
|
): PostSynthDiagnostic[] {
|
|
58
71
|
const errors: PostSynthDiagnostic[] = [];
|
|
72
|
+
|
|
73
|
+
// Core's Op-model checks first (#2101). An Op is recognized by entity type,
|
|
74
|
+
// not by which lexicon declared it, so these run over the FULL result the
|
|
75
|
+
// way `chant build` runs them — unscoped, and regardless of which plugins
|
|
76
|
+
// loaded. Without this an example's Op reached output unvalidated, which is
|
|
77
|
+
// why the terraform, aws and render examples kept their Ops outside `src/`.
|
|
78
|
+
const opDiags = runPostSynthChecks(coreOpChecks(), result, undefined, { activityContracts });
|
|
79
|
+
for (const diag of applyConfiguredSeverity(opDiags, lintRules).diagnostics) {
|
|
80
|
+
if (diag.severity === "error") errors.push(diag);
|
|
81
|
+
}
|
|
82
|
+
|
|
59
83
|
for (const plugin of plugins) {
|
|
60
84
|
if (!plugin.postSynthChecks) continue;
|
|
61
85
|
const checks = plugin.postSynthChecks();
|
|
@@ -66,7 +90,7 @@ export function postSynthErrors(
|
|
|
66
90
|
const pluginOutput = result.outputs.get(outputKey);
|
|
67
91
|
if (pluginOutput !== undefined) scopedOutputs.set(outputKey, pluginOutput);
|
|
68
92
|
|
|
69
|
-
const diags = runPostSynthChecks(checks, { ...result, outputs: scopedOutputs });
|
|
93
|
+
const diags = runPostSynthChecks(checks, { ...result, outputs: scopedOutputs }, undefined, { activityContracts });
|
|
70
94
|
const { diagnostics } = applyConfiguredSeverity(diags, lintRules);
|
|
71
95
|
for (const diag of diagnostics) {
|
|
72
96
|
if (diag.severity === "error") errors.push(diag);
|
|
@@ -129,7 +153,15 @@ export async function checkExamplesBuild(lexiconDir: string): Promise<ExampleBui
|
|
|
129
153
|
}
|
|
130
154
|
|
|
131
155
|
const plugins = await loadPlugins(lexiconNames);
|
|
132
|
-
|
|
156
|
+
// Bind each plugin's `buildRoots()` hook exactly as `chant build` does
|
|
157
|
+
// (#2083): a lexicon whose entities come from config-declared roots
|
|
158
|
+
// rather than typed source (k8s kustomize roots, terraform roots) has
|
|
159
|
+
// nothing to serialize otherwise, and its example would read as
|
|
160
|
+
// "produced no output" for a reason that is this harness's, not the
|
|
161
|
+
// example's.
|
|
162
|
+
const exampleDir = join(examplesDir, entry.name);
|
|
163
|
+
const buildRoots = collectBuildRootContributors(plugins, exampleConfig as Record<string, unknown>, exampleDir);
|
|
164
|
+
const result = await build(srcDir, plugins.map((p) => p.serializer), undefined, { buildRoots });
|
|
133
165
|
|
|
134
166
|
const structuralErrors = result.errors.map((e) => e.message);
|
|
135
167
|
const producedOutput = result.outputs.size > 0;
|
|
@@ -139,7 +171,7 @@ export async function checkExamplesBuild(lexiconDir: string): Promise<ExampleBui
|
|
|
139
171
|
// already explains the failure, and partial output is not the output
|
|
140
172
|
// the checks are meant to see.
|
|
141
173
|
const postSynth = structurallyOk
|
|
142
|
-
? postSynthErrors(plugins, result, exampleConfig.lint?.rules)
|
|
174
|
+
? postSynthErrors(plugins, result, exampleConfig.lint?.rules, await loadActivityContracts(plugins))
|
|
143
175
|
: [];
|
|
144
176
|
const ok = structurallyOk && postSynth.length === 0;
|
|
145
177
|
|
|
@@ -152,7 +184,7 @@ export async function checkExamplesBuild(lexiconDir: string): Promise<ExampleBui
|
|
|
152
184
|
? structuralErrors.join("; ")
|
|
153
185
|
: !producedOutput
|
|
154
186
|
? "discovered source but produced no output"
|
|
155
|
-
: `post-synth error(s)
|
|
187
|
+
: `post-synth error(s): ${postSynth.map(formatPostSynthError).join("; ")}`,
|
|
156
188
|
});
|
|
157
189
|
} catch (err) {
|
|
158
190
|
results.push({
|
|
@@ -150,6 +150,7 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
|
|
|
150
150
|
buildManifest: (genResult) => ({
|
|
151
151
|
name: "${name}",
|
|
152
152
|
version: "0.0.1",
|
|
153
|
+
chantVersion: ">=0.1.0",
|
|
153
154
|
}),
|
|
154
155
|
srcDir,
|
|
155
156
|
collectSkills: () => new Map(),
|
|
@@ -161,6 +162,14 @@ export async function packageLexicon(options?: { verbose?: boolean; force?: bool
|
|
|
161
162
|
`;
|
|
162
163
|
}
|
|
163
164
|
|
|
165
|
+
export function generateCodegenDocsCliTs(): string {
|
|
166
|
+
return `#!/usr/bin/env tsx
|
|
167
|
+
import { generateDocs } from "./docs";
|
|
168
|
+
|
|
169
|
+
await generateDocs({ verbose: true });
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
|
|
164
173
|
export function generateCodegenDocsTs(name: string): string {
|
|
165
174
|
return `import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
|
|
166
175
|
|
|
@@ -10,8 +10,16 @@ export function generatePackageJson(name: string, names: { packageName: string }
|
|
|
10
10
|
private: true,
|
|
11
11
|
files: ["src/", "dist/"],
|
|
12
12
|
exports: {
|
|
13
|
-
".":
|
|
14
|
-
|
|
13
|
+
".": {
|
|
14
|
+
development: "./src/index.ts",
|
|
15
|
+
types: "./dist/index.d.ts",
|
|
16
|
+
default: "./src/index.ts",
|
|
17
|
+
},
|
|
18
|
+
"./*": {
|
|
19
|
+
development: "./src/*.ts",
|
|
20
|
+
types: "./dist/*.d.ts",
|
|
21
|
+
default: "./src/*.ts",
|
|
22
|
+
},
|
|
15
23
|
"./manifest": "./dist/manifest.json",
|
|
16
24
|
"./meta": "./dist/meta.json",
|
|
17
25
|
"./types": "./dist/types/index.d.ts",
|
|
@@ -20,8 +28,9 @@ export function generatePackageJson(name: string, names: { packageName: string }
|
|
|
20
28
|
generate: "npx tsx src/codegen/generate-cli.ts",
|
|
21
29
|
validate: "npx tsx src/validate-cli.ts",
|
|
22
30
|
docs: "npx tsx src/codegen/docs-cli.ts",
|
|
23
|
-
build:
|
|
24
|
-
prepack: "npm run generate && npm run validate && npm run build",
|
|
31
|
+
build: 'tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name "*.js" -o -name "*.js.map" \\) -delete',
|
|
32
|
+
prepack: "npm run generate && npm run bundle && npm run validate && npm run build",
|
|
33
|
+
bundle: "tsx src/package-cli.ts",
|
|
25
34
|
},
|
|
26
35
|
devDependencies: {
|
|
27
36
|
// `*` (not `workspace:*`) so a fresh lexicon `npm install`s under plain npm
|
|
@@ -211,3 +220,34 @@ import { validate } from "./validate";
|
|
|
211
220
|
await validate();
|
|
212
221
|
`;
|
|
213
222
|
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Thin entry point for `npm run bundle`, called from `prepack`. Writes
|
|
226
|
+
* `src/generated/` (via the generate pipeline) and `dist/` (via the package
|
|
227
|
+
* pipeline plus `writeBundleSpec`), so `dist/manifest.json` exists before
|
|
228
|
+
* `npm run validate` and `npm run build` run.
|
|
229
|
+
*/
|
|
230
|
+
export function generatePackageCliTs(): string {
|
|
231
|
+
return `#!/usr/bin/env tsx
|
|
232
|
+
import { generate, writeGeneratedFiles } from "./codegen/generate";
|
|
233
|
+
import { packageLexicon } from "./codegen/package";
|
|
234
|
+
import { writeBundleSpec } from "@intentius/chant/codegen/package";
|
|
235
|
+
import { join, dirname } from "path";
|
|
236
|
+
import { fileURLToPath } from "url";
|
|
237
|
+
|
|
238
|
+
const srcDir = dirname(fileURLToPath(import.meta.url));
|
|
239
|
+
|
|
240
|
+
// 1. Generate src/generated/ files (writeGeneratedFiles resolves its own target)
|
|
241
|
+
const genResult = await generate({ verbose: true });
|
|
242
|
+
writeGeneratedFiles(genResult);
|
|
243
|
+
|
|
244
|
+
// 2. Run package pipeline and write dist/
|
|
245
|
+
const { spec, stats } = await packageLexicon({ verbose: true });
|
|
246
|
+
|
|
247
|
+
const distDir = join(dirname(srcDir), "dist");
|
|
248
|
+
writeBundleSpec(spec, distDir);
|
|
249
|
+
|
|
250
|
+
console.error(\`Packaged \${stats.resources} resources, \${stats.ruleCount} rules, \${stats.skillCount} skills\`);
|
|
251
|
+
console.error(\`dist/ written to \${distDir}\`);
|
|
252
|
+
`;
|
|
253
|
+
}
|