@intentius/chant 0.124.13 → 0.124.14
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/bin/chant +11 -0
- package/dist/agents/checks.js +326 -0
- package/dist/agents/discover.js +885 -0
- package/dist/agents/importer.js +17 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/types.js +19 -0
- package/dist/apply.js +151 -0
- package/dist/attrref.js +70 -0
- package/dist/audit/catalog.js +350 -0
- package/dist/audit/core.js +252 -0
- package/dist/audit/discover.js +633 -0
- package/dist/audit/fetch.js +666 -0
- package/dist/audit/lineage.js +91 -0
- package/dist/audit/nginx.js +366 -0
- package/dist/audit/prior-art.js +132 -0
- package/dist/audit/proof.js +321 -0
- package/dist/audit/report-html.js +194 -0
- package/dist/audit/report-model.js +198 -0
- package/dist/audit/report.js +102 -0
- package/dist/audit/rules-doc.js +144 -0
- package/dist/audit/secrets.js +405 -0
- package/dist/audit/terraform-state.js +140 -0
- package/dist/audit/wrangler.js +262 -0
- package/dist/behaviour-delta.js +401 -0
- package/dist/behaviour-engine.js +357 -0
- package/dist/behaviour-graph.js +83 -0
- package/dist/behaviour-http.js +188 -0
- package/dist/behaviour-kinds.js +172 -0
- package/dist/behaviour-overlay.js +50 -0
- package/dist/behaviour-predict.js +188 -0
- package/dist/behaviour-request.js +194 -0
- package/dist/behaviour.js +1325 -0
- package/dist/build-params.js +108 -0
- package/dist/build.js +668 -0
- package/dist/builder.js +44 -0
- package/dist/cdk/advise.js +30 -0
- package/dist/cdk/assembly.js +122 -0
- package/dist/cdk/graph.js +444 -0
- package/dist/cdk/tier-map.js +64 -0
- package/dist/cdk/types.js +24 -0
- package/dist/change-set.js +312 -0
- package/dist/child-project.js +21 -0
- package/dist/claimed-fields.js +135 -0
- package/dist/cli/build-options.js +70 -0
- package/dist/cli/build-params-cli.js +139 -0
- package/dist/cli/command-group.js +123 -0
- package/dist/cli/commands/audit-agents.js +326 -0
- package/dist/cli/commands/audit.js +571 -0
- package/dist/cli/commands/build.js +920 -0
- package/dist/cli/commands/carve-apply.js +153 -0
- package/dist/cli/commands/carve-bridge.js +201 -0
- package/dist/cli/commands/carve-emit.js +332 -0
- package/dist/cli/commands/carve-status.js +119 -0
- package/dist/cli/commands/carve.js +204 -0
- package/dist/cli/commands/check-lexicon-docs.js +79 -0
- package/dist/cli/commands/check-lexicon-examples.js +177 -0
- package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
- package/dist/cli/commands/check-lexicon-mcp.js +82 -0
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +104 -0
- package/dist/cli/commands/check-lexicon.js +766 -0
- package/dist/cli/commands/describe.js +85 -0
- package/dist/cli/commands/diff.js +175 -0
- package/dist/cli/commands/doctor.js +350 -0
- package/dist/cli/commands/import-agents.js +155 -0
- package/dist/cli/commands/import.js +670 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
- package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
- package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
- package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
- package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
- package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
- package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
- package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
- package/dist/cli/commands/init-lexicon.js +172 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
- package/dist/cli/commands/lexicon-surface-diff.js +145 -0
- package/dist/cli/commands/licenses.js +125 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +948 -0
- package/dist/cli/commands/list.js +63 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +423 -0
- package/dist/cli/commands/onboard.js +403 -0
- package/dist/cli/commands/pinned-upgrade.js +191 -0
- package/dist/cli/commands/update.js +194 -0
- package/dist/cli/commands/vendor.js +217 -0
- package/dist/cli/conflict-check.js +104 -0
- package/dist/cli/debug.js +8 -0
- package/dist/cli/format.js +104 -0
- package/dist/cli/handlers/build.js +267 -0
- package/dist/cli/handlers/carve-apply.js +30 -0
- package/dist/cli/handlers/carve-bridge.js +28 -0
- package/dist/cli/handlers/carve-emit.js +50 -0
- package/dist/cli/handlers/carve-status.js +26 -0
- package/dist/cli/handlers/carve.js +40 -0
- package/dist/cli/handlers/change-set.js +46 -0
- package/dist/cli/handlers/components.js +730 -0
- package/dist/cli/handlers/dev.js +113 -0
- package/dist/cli/handlers/emulator.js +233 -0
- package/dist/cli/handlers/explain.js +54 -0
- package/dist/cli/handlers/fan-out.js +422 -0
- package/dist/cli/handlers/gate-resume.js +275 -0
- package/dist/cli/handlers/generate.js +84 -0
- package/dist/cli/handlers/graph.js +969 -0
- package/dist/cli/handlers/init.js +102 -0
- package/dist/cli/handlers/lifecycle.js +1727 -0
- package/dist/cli/handlers/lint.js +62 -0
- package/dist/cli/handlers/migrate.js +48 -0
- package/dist/cli/handlers/misc.js +391 -0
- package/dist/cli/handlers/operator.js +1162 -0
- package/dist/cli/handlers/override-approve.js +102 -0
- package/dist/cli/handlers/pr.js +503 -0
- package/dist/cli/handlers/promote.js +342 -0
- package/dist/cli/handlers/run-generate.js +206 -0
- package/dist/cli/handlers/run-wave.js +66 -0
- package/dist/cli/handlers/run.js +1191 -0
- package/dist/cli/handlers/scenario.js +325 -0
- package/dist/cli/handlers/search.js +924 -0
- package/dist/cli/handlers/serve.js +32 -0
- package/dist/cli/handlers/vendor.js +154 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/is-entry-point.js +23 -0
- package/dist/cli/lsp/capabilities.js +28 -0
- package/dist/cli/lsp/diagnostics.js +34 -0
- package/dist/cli/lsp/server.js +329 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +2540 -0
- package/dist/cli/mcp/lifecycle-tools.js +80 -0
- package/dist/cli/mcp/op-tools.js +306 -0
- package/dist/cli/mcp/resource-handlers.js +258 -0
- package/dist/cli/mcp/resources/context.js +85 -0
- package/dist/cli/mcp/server.js +353 -0
- package/dist/cli/mcp/tools/build.js +111 -0
- package/dist/cli/mcp/tools/composites.js +95 -0
- package/dist/cli/mcp/tools/explain.js +166 -0
- package/dist/cli/mcp/tools/import.js +49 -0
- package/dist/cli/mcp/tools/lint.js +41 -0
- package/dist/cli/mcp/tools/scaffold.js +111 -0
- package/dist/cli/mcp/tools/search.js +112 -0
- package/dist/cli/mcp/types.js +1 -0
- package/dist/cli/mcp/workspace-plugins.js +91 -0
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.js +564 -0
- package/dist/cli/mcp-config.js +70 -0
- package/dist/cli/plugins.js +313 -0
- package/dist/cli/registry.js +23 -0
- package/dist/cli/reporters/stylish.js +329 -0
- package/dist/cli/version.js +15 -0
- package/dist/cli/watch.js +79 -0
- package/dist/codegen/bound-property-types.js +82 -0
- package/dist/codegen/coverage.js +119 -0
- package/dist/codegen/docs-file-markers.js +60 -0
- package/dist/codegen/docs-pages.js +115 -0
- package/dist/codegen/docs-rule-scanning.js +164 -0
- package/dist/codegen/docs-rules.js +76 -0
- package/dist/codegen/docs-sections.js +117 -0
- package/dist/codegen/docs-sidebar.js +65 -0
- package/dist/codegen/docs-types.js +4 -0
- package/dist/codegen/docs.js +356 -0
- package/dist/codegen/fetch.js +340 -0
- package/dist/codegen/generate-post-synth-barrel.js +63 -0
- package/dist/codegen/generate-registry.js +71 -0
- package/dist/codegen/generate-runtime-index.js +56 -0
- package/dist/codegen/generate-typescript.js +119 -0
- package/dist/codegen/generate.js +115 -0
- package/dist/codegen/json-patch.js +141 -0
- package/dist/codegen/json-schema-to-ts.js +344 -0
- package/dist/codegen/json-schema.js +246 -0
- package/dist/codegen/lexicon-regen.js +412 -0
- package/dist/codegen/naming.js +217 -0
- package/dist/codegen/okf-lexicon.js +245 -0
- package/dist/codegen/package.js +150 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.js +494 -0
- package/dist/codegen/registry.js +60 -0
- package/dist/codegen/rehype-base-url.mjs +68 -0
- package/dist/codegen/rolling-upgrade.js +217 -0
- package/dist/codegen/surface-snapshot.js +537 -0
- package/dist/codegen/testdata/postgres-tags.json +242 -0
- package/dist/codegen/topo-sort.js +36 -0
- package/dist/codegen/typecheck.js +115 -0
- package/dist/codegen/validate.js +200 -0
- package/dist/codegen/version-bump.js +35 -0
- package/dist/components/auto-release.js +143 -0
- package/dist/components/builders.js +47 -0
- package/dist/components/capability-plugin-loader.js +175 -0
- package/dist/components/capability-plugin-schema.js +46 -0
- package/dist/components/capability-plugin.js +99 -0
- package/dist/components/capability.js +60 -0
- package/dist/components/changed-files.js +72 -0
- package/dist/components/cli-support.js +427 -0
- package/dist/components/component.js +120 -0
- package/dist/components/component.schema.json +271 -0
- package/dist/components/config-defaults.js +130 -0
- package/dist/components/deploy-units.js +60 -0
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/discover.js +189 -0
- package/dist/components/driver-output.js +86 -0
- package/dist/components/driver.js +728 -0
- package/dist/components/fan-out-output.js +165 -0
- package/dist/components/fan-out-record.js +94 -0
- package/dist/components/fan-out-run.js +373 -0
- package/dist/components/fan-out-support.js +60 -0
- package/dist/components/fan-out.js +273 -0
- package/dist/components/gate-plan.js +41 -0
- package/dist/components/gated-wave-pipeline.js +46 -0
- package/dist/components/index.js +24 -0
- package/dist/components/layers.js +28 -0
- package/dist/components/manifest-persistence.js +108 -0
- package/dist/components/pilots/alb-ecs.pilot.js +59 -0
- package/dist/components/pilots/dynamodb.pilot.js +51 -0
- package/dist/components/pilots/jar-emr.pilot.js +65 -0
- package/dist/components/pilots/lambda.pilot.js +52 -0
- package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
- package/dist/components/pilots/project.js +12 -0
- package/dist/components/pr-pipeline.js +134 -0
- package/dist/components/pr-run.js +363 -0
- package/dist/components/presets/ecs-fargate.js +72 -0
- package/dist/components/presets/index.js +28 -0
- package/dist/components/presets/lambda.js +34 -0
- package/dist/components/presets/single-host-compose.js +41 -0
- package/dist/components/promote.js +549 -0
- package/dist/components/registry.js +34 -0
- package/dist/components/run-progress.js +33 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/driver.js +93 -0
- package/dist/components/sandbox/run.js +115 -0
- package/dist/components/starter-plugin.js +104 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
- package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
- package/dist/components/verbs/bom-writer.js +287 -0
- package/dist/components/verbs/build-archive.js +188 -0
- package/dist/components/verbs/build.js +142 -0
- package/dist/components/verbs/cloud-executor.js +110 -0
- package/dist/components/verbs/component-bom.js +125 -0
- package/dist/components/verbs/ensure-secret.js +50 -0
- package/dist/components/verbs/index.js +61 -0
- package/dist/components/verbs/license-policy.js +75 -0
- package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
- package/dist/components/verbs/process-runner.js +78 -0
- package/dist/components/verbs/r2-sync.js +93 -0
- package/dist/components/verbs/reproducibility.js +62 -0
- package/dist/components/verbs/run-agent.js +577 -0
- package/dist/components/verbs/sbom-generator.js +119 -0
- package/dist/components/verbs/sbom.js +97 -0
- package/dist/components/verbs/shell.js +32 -0
- package/dist/components/verbs/sign.js +221 -0
- package/dist/components/verbs/stub.js +28 -0
- package/dist/components/verbs/tool-sbom-generator.js +154 -0
- package/dist/components/verbs/verify.js +112 -0
- package/dist/components/verbs/vex.js +131 -0
- package/dist/components/verbs/vuln-gate.js +152 -0
- package/dist/components/verbs/vuln-scan.js +288 -0
- package/dist/components/verbs/wait-verify.js +106 -0
- package/dist/components/verbs/wrangler.js +179 -0
- package/dist/components/wave-plan.js +102 -0
- package/dist/composite.js +305 -0
- package/dist/config-import.d.ts.map +1 -1
- package/dist/config-import.js +22 -0
- package/dist/config-sandbox.js +122 -0
- package/dist/config-static.js +206 -0
- package/dist/config.js +605 -0
- package/dist/content-digest.js +23 -0
- package/dist/declarable.js +114 -0
- package/dist/deep-observation.js +437 -0
- package/dist/detectLexicon.js +54 -0
- package/dist/discovery/cache.js +70 -0
- package/dist/discovery/collect.js +208 -0
- package/dist/discovery/cycles.js +95 -0
- package/dist/discovery/entity-wire-codec.js +391 -0
- package/dist/discovery/entity-wire.js +42 -0
- package/dist/discovery/files.js +121 -0
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +4178 -0
- package/dist/discovery/fold-rank.js +292 -0
- package/dist/discovery/graph.js +115 -0
- package/dist/discovery/import.d.ts.map +1 -1
- package/dist/discovery/import.js +65 -0
- package/dist/discovery/index.js +333 -0
- package/dist/discovery/param-deps.js +487 -0
- package/dist/discovery/resolve.js +39 -0
- package/dist/discovery/sandbox/bundle.js +214 -0
- package/dist/discovery/sandbox/child-errors.js +26 -0
- package/dist/discovery/sandbox/config-run.js +100 -0
- package/dist/discovery/sandbox/config-wire.js +183 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.js +333 -0
- package/dist/discovery/sandbox/fork.js +229 -0
- package/dist/discovery/sandbox/policy-run.js +142 -0
- package/dist/discovery/sandbox/policy-wire.js +152 -0
- package/dist/discovery/sandbox/run.js +77 -0
- package/dist/discovery/specifier-resolve.js +320 -0
- package/dist/discovery/walk.js +284 -0
- package/dist/effect-receipt.js +340 -0
- package/dist/env.js +55 -0
- package/dist/errors.js +62 -0
- package/dist/fold/fold.js +1434 -0
- package/dist/fold/foldable-helpers.js +229 -0
- package/dist/fold/subset.js +696 -0
- package/dist/fold-provenance.js +414 -0
- package/dist/gate-decision.js +260 -0
- package/dist/gate-resume-run.js +154 -0
- package/dist/gated-waves.js +165 -0
- package/dist/governance.js +43 -0
- package/dist/graph-declared.js +45 -0
- package/dist/graph-detail.js +207 -0
- package/dist/graph-dot.js +54 -0
- package/dist/graph-effective.js +107 -0
- package/dist/graph-ir.js +623 -0
- package/dist/graph-layout.js +184 -0
- package/dist/graph-lens.js +105 -0
- package/dist/graph-mermaid.js +83 -0
- package/dist/graph-ops.js +39 -0
- package/dist/graph-refs.js +156 -0
- package/dist/held-elsewhere.js +87 -0
- package/dist/identity.js +251 -0
- package/dist/import/base-parser.js +34 -0
- package/dist/import/embedded.js +255 -0
- package/dist/import/generator.js +1 -0
- package/dist/import/ir-utils.js +85 -0
- package/dist/import/parser-options.js +45 -0
- package/dist/import/parser.js +1 -0
- package/dist/index.js +118 -0
- package/dist/intrinsic-interpolation.js +73 -0
- package/dist/intrinsic.js +31 -0
- package/dist/join-key.js +35 -0
- package/dist/kubectl-context.js +150 -0
- package/dist/lexicon-config.js +58 -0
- package/dist/lexicon-integrity.js +47 -0
- package/dist/lexicon-manifest.js +70 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +241 -0
- package/dist/lexicon-output.js +218 -0
- package/dist/lexicon-plugin-helpers.js +104 -0
- package/dist/lexicon-schema.js +136 -0
- package/dist/lexicon.js +130 -0
- package/dist/lifecycle/affected.js +224 -0
- package/dist/lifecycle/assert-live.js +110 -0
- package/dist/lifecycle/build-ledger-store.js +160 -0
- package/dist/lifecycle/build-ledger.js +155 -0
- package/dist/lifecycle/change-set.js +356 -0
- package/dist/lifecycle/converge-ledger.js +161 -0
- package/dist/lifecycle/deep-diff.js +233 -0
- package/dist/lifecycle/deep-observe.js +147 -0
- package/dist/lifecycle/digest.js +143 -0
- package/dist/lifecycle/disruption.js +135 -0
- package/dist/lifecycle/gate-applied.js +113 -0
- package/dist/lifecycle/gate-audit.js +341 -0
- package/dist/lifecycle/gate-ledger-select.js +89 -0
- package/dist/lifecycle/gate-ledger.js +193 -0
- package/dist/lifecycle/gate-origin.js +117 -0
- package/dist/lifecycle/gate-pending.js +58 -0
- package/dist/lifecycle/git.js +1182 -0
- package/dist/lifecycle/identity.js +58 -0
- package/dist/lifecycle/index.js +26 -0
- package/dist/lifecycle/lease.js +283 -0
- package/dist/lifecycle/ledger-port.js +1 -0
- package/dist/lifecycle/legacy-digest.js +91 -0
- package/dist/lifecycle/live-diff.js +274 -0
- package/dist/lifecycle/local-note.js +15 -0
- package/dist/lifecycle/member-ledger.js +122 -0
- package/dist/lifecycle/observation-baseline.js +155 -0
- package/dist/lifecycle/observe.js +375 -0
- package/dist/lifecycle/oras-referrer-lookup.js +82 -0
- package/dist/lifecycle/override-ledger.js +54 -0
- package/dist/lifecycle/plan-digest.js +110 -0
- package/dist/lifecycle/plan-ledger.js +129 -0
- package/dist/lifecycle/receipt-plan.js +192 -0
- package/dist/lifecycle/release-ledger.js +155 -0
- package/dist/lifecycle/release-read.js +64 -0
- package/dist/lifecycle/replay.js +193 -0
- package/dist/lifecycle/rollback.js +102 -0
- package/dist/lifecycle/run-ledger.js +183 -0
- package/dist/lifecycle/scenario-eval.js +204 -0
- package/dist/lifecycle/scenario.js +214 -0
- package/dist/lifecycle/snapshot.js +239 -0
- package/dist/lifecycle/status.js +447 -0
- package/dist/lifecycle/symptoms.js +117 -0
- package/dist/lifecycle/teardown.js +255 -0
- package/dist/lifecycle/types.js +1 -0
- package/dist/lifecycle/unobserved-gate.js +33 -0
- package/dist/lifecycle/wave-plans.js +68 -0
- package/dist/lifecycle/work-item-id.js +36 -0
- package/dist/lifecycle/work-lease.js +393 -0
- package/dist/lint/component-checks.js +87 -0
- package/dist/lint/config.js +483 -0
- package/dist/lint/declarative.js +122 -0
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +138 -0
- package/dist/lint/engine.js +246 -0
- package/dist/lint/knowledge-checks.js +64 -0
- package/dist/lint/named-checks.js +22 -0
- package/dist/lint/output-checks.js +87 -0
- package/dist/lint/output-docs.js +163 -0
- package/dist/lint/parser.js +33 -0
- package/dist/lint/pipeline-change-gate.js +70 -0
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/policy-import.d.ts.map +1 -1
- package/dist/lint/policy-import.js +62 -0
- package/dist/lint/policy-sandbox.js +86 -0
- package/dist/lint/policy.js +122 -0
- package/dist/lint/post-synth.js +87 -0
- package/dist/lint/presets/relaxed.json +26 -0
- package/dist/lint/presets/strict.json +24 -24
- package/dist/lint/receipt-checks.js +83 -0
- package/dist/lint/rule-loader.d.ts.map +1 -1
- package/dist/lint/rule-loader.js +89 -0
- package/dist/lint/rule-registry.js +86 -0
- package/dist/lint/rule.js +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
- package/dist/lint/rules/comp/index.js +33 -0
- package/dist/lint/rules/comp/support.js +129 -0
- package/dist/lint/rules/composite-scope.js +51 -0
- package/dist/lint/rules/cor017-composite-name-match.js +93 -0
- package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
- package/dist/lint/rules/cor021-env-literal-name.js +100 -0
- package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
- package/dist/lint/rules/declarable-naming-convention.js +62 -0
- package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
- package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
- package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
- package/dist/lint/rules/evl004-spread-non-const.js +94 -0
- package/dist/lint/rules/evl005-resource-block-body.js +41 -0
- package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
- package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
- package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
- package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
- package/dist/lint/rules/export-required.js +115 -0
- package/dist/lint/rules/file-declarable-limit.js +88 -0
- package/dist/lint/rules/flat-declarations.js +62 -0
- package/dist/lint/rules/index.js +90 -0
- package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
- package/dist/lint/rules/no-redundant-type-import.js +76 -0
- package/dist/lint/rules/no-redundant-value-cast.js +41 -0
- package/dist/lint/rules/no-string-ref.js +59 -0
- package/dist/lint/rules/no-unused-declarable-import.js +75 -0
- package/dist/lint/rules/no-unused-declarable.js +142 -0
- package/dist/lint/rules/op/index.js +28 -0
- package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
- package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
- package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
- package/dist/lint/rules/op/support.js +11 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
- package/dist/lint/rules/property-kind.js +56 -0
- package/dist/lint/rules/single-concern-file.js +71 -0
- package/dist/lint/rules/sys001-no-literal-key.js +60 -0
- package/dist/lint/selectors.js +168 -0
- package/dist/lint/suppressions.js +129 -0
- package/dist/lint/typescript.js +17 -0
- package/dist/live-endpoint.js +113 -0
- package/dist/live-read-session.js +76 -0
- package/dist/lsp/lexicon-providers.js +163 -0
- package/dist/lsp/types.js +5 -0
- package/dist/managed-fields.js +293 -0
- package/dist/mcp/types.js +4 -0
- package/dist/notify-verify.js +0 -1
- package/dist/notify.js +0 -1
- package/dist/notify.schema.json +72 -0
- package/dist/observation.js +266 -0
- package/dist/okf-read.js +134 -0
- package/dist/okf.js +275 -0
- package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
- package/dist/op/activities/activity-contracts.js +313 -0
- package/dist/op/activities/apply.js +582 -0
- package/dist/op/activities/build.js +18 -0
- package/dist/op/activities/change-coverage.js +40 -0
- package/dist/op/activities/change-set.js +64 -0
- package/dist/op/activities/converge.js +492 -0
- package/dist/op/activities/decide.js +211 -0
- package/dist/op/activities/env-teardown.js +110 -0
- package/dist/op/activities/factory.js +591 -0
- package/dist/op/activities/forge-pull-request.js +82 -0
- package/dist/op/activities/gh-host.js +78 -0
- package/dist/op/activities/guard-validate.js +165 -0
- package/dist/op/activities/http-check.js +40 -0
- package/dist/op/activities/index.js +59 -0
- package/dist/op/activities/lexicon-upgrade.js +629 -0
- package/dist/op/activities/lifecycle.js +109 -0
- package/dist/op/activities/pipeline-audit.js +147 -0
- package/dist/op/activities/policy.js +26 -0
- package/dist/op/activities/predict-behaviour.js +341 -0
- package/dist/op/activities/propose-upgrade.js +165 -0
- package/dist/op/activities/reconcile.js +997 -0
- package/dist/op/activities/shell.js +118 -0
- package/dist/op/activities/source-release.js +97 -0
- package/dist/op/activities/source-rollback.js +165 -0
- package/dist/op/activities/teardown.js +17 -0
- package/dist/op/activities/util.js +6 -0
- package/dist/op/activities/wait.js +51 -0
- package/dist/op/activities/work-evidence.js +35 -0
- package/dist/op/activities/workflow-audit.js +133 -0
- package/dist/op/activity-contract-registry.js +106 -0
- package/dist/op/activity-contract.js +232 -0
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/activity-profiles.js +129 -0
- package/dist/op/activity-registry.js +105 -0
- package/dist/op/activity-runtime.js +28 -0
- package/dist/op/builders.js +801 -0
- package/dist/op/change-signal.js +118 -0
- package/dist/op/composites/apply-op.js +151 -0
- package/dist/op/composites/behaviour-op.js +65 -0
- package/dist/op/composites/converge-op.js +141 -0
- package/dist/op/composites/index.js +19 -0
- package/dist/op/composites/lexicon-upgrade-op.js +107 -0
- package/dist/op/composites/pipeline-audit-op.js +50 -0
- package/dist/op/composites/reconcile-op.js +84 -0
- package/dist/op/composites/watch-op.js +69 -0
- package/dist/op/composites/workflow-audit-op.js +57 -0
- package/dist/op/converge-rule.js +205 -0
- package/dist/op/cron.js +146 -0
- package/dist/op/decide-backend.js +181 -0
- package/dist/op/decide-config.js +68 -0
- package/dist/op/decide-read-inputs.js +141 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +213 -0
- package/dist/op/duration.js +21 -0
- package/dist/op/emulator-freshness.js +80 -0
- package/dist/op/emulator-lifecycle.js +269 -0
- package/dist/op/factory.js +83 -0
- package/dist/op/gate-approval.js +172 -0
- package/dist/op/gate-name.js +86 -0
- package/dist/op/gate-plan-context.js +167 -0
- package/dist/op/gate-point-run.js +67 -0
- package/dist/op/gate-point.js +111 -0
- package/dist/op/gate-resume-plan.js +155 -0
- package/dist/op/gate-resume.js +31 -0
- package/dist/op/gate-review.js +290 -0
- package/dist/op/gate-run-locator.js +85 -0
- package/dist/op/gate-summary.js +100 -0
- package/dist/op/gate-wait.js +56 -0
- package/dist/op/gate.js +449 -0
- package/dist/op/generate-pipeline.js +124 -0
- package/dist/op/index.js +51 -0
- package/dist/op/lifecycle-receipt-store.js +45 -0
- package/dist/op/local-executor.js +1164 -0
- package/dist/op/local-output.js +140 -0
- package/dist/op/op-ir.js +317 -0
- package/dist/op/op-verb-class.js +131 -0
- package/dist/op/op-waves-notify.js +136 -0
- package/dist/op/op-waves-run.js +1657 -0
- package/dist/op/op-waves.js +409 -0
- package/dist/op/operator.js +743 -0
- package/dist/op/receipt-store.js +94 -0
- package/dist/op/resource.js +23 -0
- package/dist/op/run-context.js +28 -0
- package/dist/op/run-live.js +256 -0
- package/dist/op/runtime.js +21 -0
- package/dist/op/runtimes/local.js +195 -0
- package/dist/op/source-archive.js +131 -0
- package/dist/op/step-output-ref.js +397 -0
- package/dist/op/steward-beside.js +169 -0
- package/dist/op/steward-points.js +138 -0
- package/dist/op/steward-turn.js +59 -0
- package/dist/op/steward.js +317 -0
- package/dist/op/types.js +25 -0
- package/dist/op/work-lease-decl.js +81 -0
- package/dist/op/work-lease-run.js +393 -0
- package/dist/override-gate.js +284 -0
- package/dist/owner-chain.js +74 -0
- package/dist/ownership.js +92 -0
- package/dist/params.js +61 -0
- package/dist/plan-summary.js +711 -0
- package/dist/point-decision.js +211 -0
- package/dist/pr-forge.js +810 -0
- package/dist/pr-loop.js +203 -0
- package/dist/project-codegen.js +191 -0
- package/dist/project-root.js +74 -0
- package/dist/project-validation.js +50 -0
- package/dist/provenance.js +157 -0
- package/dist/pseudo-parameter.js +40 -0
- package/dist/reconcile.js +450 -0
- package/dist/resource-attributes.js +33 -0
- package/dist/runtime-adapter.js +77 -0
- package/dist/runtime.js +66 -0
- package/dist/secret-materialization.js +153 -0
- package/dist/secret-provenance.js +250 -0
- package/dist/serializer-walker.js +112 -0
- package/dist/serializer.js +1 -0
- package/dist/sort.js +45 -0
- package/dist/stack-output.js +115 -0
- package/dist/telemetry-attribution.js +149 -0
- package/dist/terraform/__fixtures__/build-graph.js +63 -0
- package/dist/terraform/adopt-state.js +40 -0
- package/dist/terraform/aws-resources.js +384 -0
- package/dist/terraform/bridge.js +204 -0
- package/dist/terraform/carve-provider.js +155 -0
- package/dist/terraform/carve.js +138 -0
- package/dist/terraform/data-source-shape.js +57 -0
- package/dist/terraform/emit-source.js +36 -0
- package/dist/terraform/excise.js +123 -0
- package/dist/terraform/graduate.js +128 -0
- package/dist/terraform/graph.js +435 -0
- package/dist/terraform/hcl2json.js +60 -0
- package/dist/terraform/manifest.js +149 -0
- package/dist/terraform/parse.js +81 -0
- package/dist/terraform/providers/aws.js +146 -0
- package/dist/terraform/providers/gcp.js +294 -0
- package/dist/terraform/providers/index.js +17 -0
- package/dist/terraform/providers/kubernetes.js +253 -0
- package/dist/terraform/score.js +151 -0
- package/dist/terraform/state.js +67 -0
- package/dist/terraform/tier-map.js +74 -0
- package/dist/terraform/types.js +13 -0
- package/dist/terraform/unified-diff.js +132 -0
- package/dist/testing.js +295 -0
- package/dist/toml-emit.js +153 -0
- package/dist/toml-parse.js +355 -0
- package/dist/toml-utils.js +60 -0
- package/dist/toml.js +428 -0
- package/dist/ts-loader.d.ts +46 -0
- package/dist/ts-loader.d.ts.map +1 -0
- package/dist/ts-loader.js +103 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +61 -0
- package/dist/validation.js +20 -0
- package/dist/vendor/js-yaml-load.js +1662 -0
- package/dist/workspace/__fixtures__/contract-repo.js +103 -0
- package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
- package/dist/workspace/__fixtures__/sessions.js +91 -0
- package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
- package/dist/workspace/agent-cli.js +99 -0
- package/dist/workspace/agent.schema.json +390 -0
- package/dist/workspace/answers-ledger.js +89 -0
- package/dist/workspace/box-cli.js +142 -0
- package/dist/workspace/box-factory-write.js +196 -0
- package/dist/workspace/box-factory-write.schema.json +342 -0
- package/dist/workspace/box-factory.js +88 -0
- package/dist/workspace/box-intent.js +126 -0
- package/dist/workspace/box-isolation.js +169 -0
- package/dist/workspace/box-listing-write.schema.json +204 -0
- package/dist/workspace/box-listing.js +298 -0
- package/dist/workspace/box-publish.js +352 -0
- package/dist/workspace/box-publish.schema.json +498 -0
- package/dist/workspace/box-services.js +39 -0
- package/dist/workspace/broker-protocol.js +359 -0
- package/dist/workspace/broker-protocol.schema.json +228 -0
- package/dist/workspace/change-set.schema.json +460 -0
- package/dist/workspace/changes-cli.js +56 -0
- package/dist/workspace/changes.js +446 -0
- package/dist/workspace/changes.schema.json +642 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
- package/dist/workspace/chant-migrations.js +113 -0
- package/dist/workspace/check.schema.json +433 -0
- package/dist/workspace/checks/box-isolation.js +62 -0
- package/dist/workspace/checks/boxes.js +491 -0
- package/dist/workspace/checks/diagrams.js +104 -0
- package/dist/workspace/checks/generated.js +419 -0
- package/dist/workspace/checks/ledgers.js +212 -0
- package/dist/workspace/checks/links.js +191 -0
- package/dist/workspace/checks/live.js +100 -0
- package/dist/workspace/checks/pipelines.js +188 -0
- package/dist/workspace/checks/records.js +169 -0
- package/dist/workspace/checks.js +426 -0
- package/dist/workspace/ci-green-cli.js +125 -0
- package/dist/workspace/ci-green-forge.js +83 -0
- package/dist/workspace/ci-green-workflow.js +199 -0
- package/dist/workspace/ci-green.js +325 -0
- package/dist/workspace/ci-last-green.schema.json +158 -0
- package/dist/workspace/compose-graph.js +235 -0
- package/dist/workspace/compose-reports.js +146 -0
- package/dist/workspace/composites.js +264 -0
- package/dist/workspace/composites.schema.json +617 -0
- package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
- package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
- package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
- package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/dist/workspace/conformance/broker.js +736 -0
- package/dist/workspace/conformance/index.js +673 -0
- package/dist/workspace/conformance/vitest.js +108 -0
- package/dist/workspace/conformance/writer.js +1080 -0
- package/dist/workspace/decide.js +879 -0
- package/dist/workspace/decision-points.schema.json +135 -135
- package/dist/workspace/declaration-write-cli.js +74 -0
- package/dist/workspace/declaration-write.js +238 -0
- package/dist/workspace/declaration.js +938 -0
- package/dist/workspace/declaration.schema.json +1413 -1413
- package/dist/workspace/declared-kinds.js +106 -0
- package/dist/workspace/environments.js +164 -0
- package/dist/workspace/evidence.schema.json +279 -0
- package/dist/workspace/export-cli.js +185 -0
- package/dist/workspace/export.js +499 -0
- package/dist/workspace/factory-rules.js +175 -0
- package/dist/workspace/generated-files.js +92 -0
- package/dist/workspace/glob.js +45 -0
- package/dist/workspace/graph-cache.js +352 -0
- package/dist/workspace/graph-cli.js +348 -0
- package/dist/workspace/graph.schema.json +1338 -0
- package/dist/workspace/identity-gate-rule.js +75 -0
- package/dist/workspace/identity.js +126 -0
- package/dist/workspace/import.js +283 -0
- package/dist/workspace/init.js +620 -0
- package/dist/workspace/intent-cli.js +263 -0
- package/dist/workspace/intent-joins.js +201 -0
- package/dist/workspace/intent-record.js +352 -0
- package/dist/workspace/intent-record.schema.json +864 -0
- package/dist/workspace/intent.js +1582 -0
- package/dist/workspace/intent.schema.json +2420 -0
- package/dist/workspace/json-edit.js +221 -0
- package/dist/workspace/jsonc.js +235 -0
- package/dist/workspace/kind-readers.js +103 -0
- package/dist/workspace/kinds.js +587 -0
- package/dist/workspace/lexicon-symbols.js +112 -0
- package/dist/workspace/lineage-adopt-cli.js +102 -0
- package/dist/workspace/lineage-adopt.js +360 -0
- package/dist/workspace/lineage-check.js +282 -0
- package/dist/workspace/lineage-cli.js +121 -0
- package/dist/workspace/lineage-hash-index.js +284 -0
- package/dist/workspace/lineage-init.js +507 -0
- package/dist/workspace/lineage-lock.js +387 -0
- package/dist/workspace/lineage-merge.js +45 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.js +329 -0
- package/dist/workspace/lineage-provenance.js +36 -0
- package/dist/workspace/lineage-update.js +138 -0
- package/dist/workspace/lineage-upgrade-cli.js +131 -0
- package/dist/workspace/lineage-upgrade.js +889 -0
- package/dist/workspace/lineage-vendor.js +171 -0
- package/dist/workspace/lineage-version.js +128 -0
- package/dist/workspace/lineage-versions.js +275 -0
- package/dist/workspace/links.js +330 -0
- package/dist/workspace/ls-generated.js +95 -0
- package/dist/workspace/ls.js +277 -0
- package/dist/workspace/ls.schema.json +333 -0
- package/dist/workspace/member-commands.js +508 -0
- package/dist/workspace/member-handles.js +216 -0
- package/dist/workspace/member-pipeline.js +258 -0
- package/dist/workspace/member-run.js +117 -0
- package/dist/workspace/member-write.schema.json +193 -0
- package/dist/workspace/nested-graph.js +156 -0
- package/dist/workspace/nesting.js +38 -0
- package/dist/workspace/patch.js +301 -0
- package/dist/workspace/patch.schema.json +321 -0
- package/dist/workspace/pin-cli.js +55 -0
- package/dist/workspace/pin-integrity.js +100 -0
- package/dist/workspace/plan-summary.schema.json +155 -0
- package/dist/workspace/point-answer.schema.json +129 -129
- package/dist/workspace/points-cli.js +291 -0
- package/dist/workspace/points-write.schema.json +660 -0
- package/dist/workspace/points.js +521 -0
- package/dist/workspace/points.schema.json +916 -0
- package/dist/workspace/pr-report.schema.json +108 -0
- package/dist/workspace/principal-classes.js +245 -0
- package/dist/workspace/reason-codes.js +326 -0
- package/dist/workspace/record-assets.js +151 -0
- package/dist/workspace/record-decided.js +105 -0
- package/dist/workspace/record-sessions.js +96 -0
- package/dist/workspace/record-source.js +114 -0
- package/dist/workspace/records-amend.schema.json +284 -0
- package/dist/workspace/records-checkout.js +76 -0
- package/dist/workspace/records-cli.js +707 -0
- package/dist/workspace/records-close.js +116 -0
- package/dist/workspace/records-close.schema.json +278 -0
- package/dist/workspace/records-new.schema.json +202 -0
- package/dist/workspace/records-review.schema.json +367 -0
- package/dist/workspace/records-since.js +317 -0
- package/dist/workspace/records-since.schema.json +218 -0
- package/dist/workspace/records-write.js +1229 -0
- package/dist/workspace/records.js +1345 -0
- package/dist/workspace/records.schema.json +604 -0
- package/dist/workspace/reference-kinds/app/package.json +10 -0
- package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/dist/workspace/returns.js +303 -0
- package/dist/workspace/root-refusal.js +75 -0
- package/dist/workspace/run-statement.schema.json +622 -0
- package/dist/workspace/runs-cli.js +584 -0
- package/dist/workspace/runs-write.schema.json +994 -0
- package/dist/workspace/runs.js +708 -0
- package/dist/workspace/runs.schema.json +1257 -0
- package/dist/workspace/runtimes.js +76 -0
- package/dist/workspace/session-kinds.js +83 -0
- package/dist/workspace/signers.schema.json +206 -0
- package/dist/workspace/source-block.js +125 -0
- package/dist/workspace/squash.js +177 -0
- package/dist/workspace/status-gates.js +162 -0
- package/dist/workspace/status-stewards.js +330 -0
- package/dist/workspace/status.js +514 -0
- package/dist/workspace/status.schema.json +998 -0
- package/dist/workspace/steward-index.js +191 -0
- package/dist/workspace/symbols.js +188 -0
- package/dist/workspace/template-manifest.js +227 -0
- package/dist/workspace/template-pins.js +115 -0
- package/dist/workspace/trailer-joins.js +65 -0
- package/dist/workspace/trailers.js +111 -0
- package/dist/workspace/tree.js +136 -0
- package/dist/workspace/trust/attestor.js +63 -0
- package/dist/workspace/trust/dsse.js +108 -0
- package/dist/workspace/trust/evidence-cli.js +175 -0
- package/dist/workspace/trust/evidence.js +161 -0
- package/dist/workspace/trust/gate-seal.js +226 -0
- package/dist/workspace/trust/policy.js +190 -0
- package/dist/workspace/trust/provenance.js +180 -0
- package/dist/workspace/trust/rotation.js +298 -0
- package/dist/workspace/trust/run-commits.js +101 -0
- package/dist/workspace/trust/run-statement.js +182 -0
- package/dist/workspace/trust/seal.js +272 -0
- package/dist/workspace/trust/signers-cli.js +152 -0
- package/dist/workspace/trust/ssh-commit.js +178 -0
- package/dist/workspace/trust/test-repo.js +118 -0
- package/dist/workspace/trust/trust-files.js +193 -0
- package/dist/workspace/trust/verify-cli.js +63 -0
- package/dist/workspace/trust/verify.js +192 -0
- package/dist/workspace/which-chant.js +141 -0
- package/dist/workspace/wip-cli.js +95 -0
- package/dist/workspace/wip-write.schema.json +504 -0
- package/dist/workspace/wip.js +631 -0
- package/dist/workspace/wip.schema.json +334 -0
- package/dist/workspace/work-cli.js +448 -0
- package/dist/workspace/work-evidence.js +122 -0
- package/dist/workspace/work-evidence.schema.json +222 -0
- package/dist/workspace/work-history.schema.json +421 -0
- package/dist/workspace/work-lease.schema.json +246 -0
- package/dist/workspace/work-size.js +77 -0
- package/dist/workspace/work.js +283 -0
- package/dist/workspace/workspace-kinds.schema.json +259 -259
- package/dist/workspace/workspace-principals.schema.json +53 -53
- package/dist/workspace/write-lock-cli.js +105 -0
- package/dist/workspace/write-lock.js +424 -0
- package/dist/workspace/write-lock.schema.json +172 -0
- package/dist/workspace/write-scope.js +484 -0
- package/dist/yaml.js +459 -0
- package/package.json +2 -2
- package/src/cli/commands/check-lexicon-plugin.ts +2 -0
- package/src/cli/commands/lint.ts +3 -0
- package/src/cli/commands/migrate.ts +2 -0
- package/src/cli/compiled-cli.e2e.test.ts +165 -0
- package/src/cli/main.ts +121 -27
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -0
- package/src/components/discover.ts +2 -0
- package/src/components/sandbox/driver.ts +3 -1
- package/src/config-import.ts +3 -0
- package/src/discovery/fold-import.ts +23 -14
- package/src/discovery/import.ts +2 -0
- package/src/discovery/sandbox/driver.ts +3 -1
- package/src/lexicon-module.ts +3 -0
- package/src/lint/config.ts +1 -1
- package/src/lint/discover.ts +28 -8
- package/src/lint/policy-import.ts +4 -1
- package/src/lint/rule-loader.ts +2 -0
- package/src/op/discover.ts +3 -0
- package/src/ts-loader.test.ts +23 -0
- package/src/ts-loader.ts +122 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
- package/src/workspace/declaration.ts +1 -1
- package/src/workspace/kinds.ts +1 -1
- package/src/workspace/lineage-migrations.ts +2 -0
- package/src/workspace/points.ts +1 -1
- package/src/workspace/principal-classes.ts +1 -1
|
@@ -0,0 +1,889 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant workspace upgrade <scope>`: bring one lineage scope to a newer
|
|
3
|
+
* version of its template (#2550, D9, ws-005, ws-032).
|
|
4
|
+
*
|
|
5
|
+
* The upgrade is a core command, never an Op the template ships, so the
|
|
6
|
+
* template cannot change the rules that judge its own upgrade. It works in the
|
|
7
|
+
* six steps of D9:
|
|
8
|
+
*
|
|
9
|
+
* 1. Fetch the target version of the template. For a git source that is one
|
|
10
|
+
* `git fetch` of the target ref, plus the commit the scope was made from.
|
|
11
|
+
* This is the command's only network step, catalogued in
|
|
12
|
+
* `test/egress-catalogue.ts`. A local repository reaches nothing, and
|
|
13
|
+
* neither does a directory source (#2647), which reads `--to <dir>`.
|
|
14
|
+
* 2. Rebuild the merge base offline: each recorded file's content at the base
|
|
15
|
+
* commit, kept only when it has the hash the lock recorded. A file the
|
|
16
|
+
* project never edited is its own merge base. Vendor sources keep no
|
|
17
|
+
* history, so only unedited vendored files have a base.
|
|
18
|
+
* 3. Migrate in a separate git worktree, checked out at HEAD under
|
|
19
|
+
* `.chant/upgrade/`. The chain is planned from the template's
|
|
20
|
+
* `.chant/migrations/`, and a gap refuses the upgrade.
|
|
21
|
+
* 4. Merge per file (ws-005): an edited file takes the new version only when
|
|
22
|
+
* every hunk merges cleanly. Otherwise it stays as it was, with one manual
|
|
23
|
+
* step. The worktree never holds conflict markers.
|
|
24
|
+
* Then rebuild each CI workflow a chant member's package.json builds with
|
|
25
|
+
* `chant build ... -o <workflow>` (#3244), with the chant doing the
|
|
26
|
+
* upgrade, so the committed workflow follows that chant's composites.
|
|
27
|
+
* 5. Check the worktree: `chant build` and `chant lint` when the project is a
|
|
28
|
+
* chant project, and the lineage checks of `chant workspace check`.
|
|
29
|
+
* 6. Bind the gate to the digest of the resulting patch: the pending fact and
|
|
30
|
+
* the approval name it, so an approval covers exactly this patch.
|
|
31
|
+
*
|
|
32
|
+
* The project's own tree changes only once the gate is approved, when the
|
|
33
|
+
* patch is applied to it. A patch that changes governance files (Op files,
|
|
34
|
+
* `chant.config`, CI workflows, CODEOWNERS) needs human approvals, as many as
|
|
35
|
+
* the strictest gate in the Op files it changes asks for at HEAD. The
|
|
36
|
+
* upgraded Op files never decide their own gate.
|
|
37
|
+
*/
|
|
38
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
39
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
40
|
+
import { tmpdir } from "node:os";
|
|
41
|
+
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
42
|
+
import { computePlanDigest } from "../lifecycle/plan-digest.js";
|
|
43
|
+
import { checkLineage, findingKey } from "./lineage-check.js";
|
|
44
|
+
import { dirLabel, git, parseDirSpec, parseTemplateSource, portableUrl, readTemplateDir, readTemplateTree, recordedDirPath } from "./lineage-init.js";
|
|
45
|
+
import { LOCK_FILE, LockError, contentDigest, fileHash, readLock, renderLock, scopeKey, writeLock, } from "./lineage-lock.js";
|
|
46
|
+
import { mergeFile } from "./lineage-merge.js";
|
|
47
|
+
import { reportPlan, runChantMigrations } from "./chant-migrations.js";
|
|
48
|
+
import { readDeclaration, readerVersion, WorkspaceReadError } from "./declaration.js";
|
|
49
|
+
import { assertCodeAllowed, planMigrations, runMigration, splitMigrations } from "./lineage-migrations.js";
|
|
50
|
+
import { applyUpstream } from "./lineage-update.js";
|
|
51
|
+
import { pathsInsideNested } from "./nesting.js";
|
|
52
|
+
import { carryParameters, readManifest, substituteParameters } from "./template-manifest.js";
|
|
53
|
+
import { repinSubstituted } from "./template-pins.js";
|
|
54
|
+
import { workingTree } from "./tree.js";
|
|
55
|
+
import { splitCommandLine } from "./checks/generated.js";
|
|
56
|
+
/** The kind the patch digest is taken under, so it never collides with another kind of plan. */
|
|
57
|
+
export const UPGRADE_PLAN_KIND = "workspace-upgrade";
|
|
58
|
+
/** Where staging worktrees live, relative to the project root. */
|
|
59
|
+
export const UPGRADE_DIR = ".chant/upgrade";
|
|
60
|
+
export class UpgradeError extends LockError {
|
|
61
|
+
constructor() {
|
|
62
|
+
super(...arguments);
|
|
63
|
+
this.name = "UpgradeError";
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The default runner: this same chant, in a child process. The child sees the
|
|
68
|
+
* worktree's sources and resolves packages the way the project does, since the
|
|
69
|
+
* worktree sits inside the project.
|
|
70
|
+
*/
|
|
71
|
+
export const spawnChant = (command, cwd, args = []) => new Promise((resolvePromise, reject) => {
|
|
72
|
+
const entry = process.argv[1];
|
|
73
|
+
if (!entry) {
|
|
74
|
+
reject(new UpgradeError("cannot find the chant entry point to run build and lint in the worktree"));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const child = spawn(process.execPath, [...process.execArgv, entry, command, ...args], { cwd, stdio: ["ignore", "pipe", "pipe"], env: process.env });
|
|
78
|
+
const out = [];
|
|
79
|
+
child.stdout.on("data", (c) => out.push(c));
|
|
80
|
+
child.stderr.on("data", (c) => out.push(c));
|
|
81
|
+
child.on("error", reject);
|
|
82
|
+
child.on("close", (code) => resolvePromise({ exitCode: code ?? 1, output: Buffer.concat(out).toString("utf-8") }));
|
|
83
|
+
});
|
|
84
|
+
/** A CI workflow path a forge reads, relative to the repository root. The governance list's pipeline entries. */
|
|
85
|
+
const CI_WORKFLOW = [/(^|\/)\.github\/workflows\/[^/]+\.ya?ml$/, /(^|\/)\.forgejo\/workflows\/[^/]+\.ya?ml$/, /(^|\/)\.gitea\/workflows\/[^/]+\.ya?ml$/, /(^|\/)\.gitlab-ci\.ya?ml$/];
|
|
86
|
+
/**
|
|
87
|
+
* The CI workflows the chant members under `worktreeProject` build: each
|
|
88
|
+
* package.json script that is one `chant build ... -o <file>` command (no
|
|
89
|
+
* shell, no `&&`), whose output is a committed CI workflow inside the scope.
|
|
90
|
+
* The studio kit's template has `"ci:build": "chant build ci --lexicon github
|
|
91
|
+
* -o ../.github/workflows/ci.yml"` in delivery/, and its CI fails when the
|
|
92
|
+
* committed workflow differs from what ci/ci.ts builds.
|
|
93
|
+
*/
|
|
94
|
+
function workflowBuilds(worktree, worktreeProject, scopeRepoPath) {
|
|
95
|
+
const out = [];
|
|
96
|
+
for (const member of chantMemberDirs(worktreeProject)) {
|
|
97
|
+
const dir = member === "." ? worktreeProject : join(worktreeProject, member);
|
|
98
|
+
let scripts;
|
|
99
|
+
try {
|
|
100
|
+
scripts = JSON.parse(readFileSync(join(dir, "package.json"), "utf-8")).scripts ?? {};
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
for (const [script, line] of Object.entries(scripts)) {
|
|
106
|
+
if (typeof line !== "string")
|
|
107
|
+
continue;
|
|
108
|
+
const words = splitCommandLine(line);
|
|
109
|
+
if (!words || words[0] !== "chant" || words[1] !== "build")
|
|
110
|
+
continue;
|
|
111
|
+
const flag = words.findIndex((w) => w === "-o" || w === "--output");
|
|
112
|
+
const target = flag >= 0 ? words[flag + 1] : words.find((w) => w.startsWith("--output="))?.slice("--output=".length);
|
|
113
|
+
if (!target)
|
|
114
|
+
continue;
|
|
115
|
+
const abs = resolve(dir, target);
|
|
116
|
+
const path = relative(worktree, abs).split(sep).join("/");
|
|
117
|
+
if (path.startsWith("../") || !CI_WORKFLOW.some((re) => re.test(path)))
|
|
118
|
+
continue;
|
|
119
|
+
if (scopeRepoPath !== "." && !path.startsWith(`${scopeRepoPath}/`))
|
|
120
|
+
continue;
|
|
121
|
+
if (!existsSync(abs))
|
|
122
|
+
continue;
|
|
123
|
+
out.push({ member, script, command: line, args: words.slice(2), abs, path });
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return out;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Rebuild the CI workflows {@link workflowBuilds} finds (#3244), each in its
|
|
130
|
+
* member's directory of the staging worktree with that member's node_modules
|
|
131
|
+
* linked in from the project. A workflow is built from the member's sources
|
|
132
|
+
* through the lexicon's composites, so upgrading chant can change it with no
|
|
133
|
+
* change to the sources (#2621 moved Checkout and SetupNode from v4 to v7),
|
|
134
|
+
* and a committed copy then fails the project's own ci:check. Rebuilding it
|
|
135
|
+
* here puts the new workflow in the patch the gate approves. The links are
|
|
136
|
+
* removed before the patch is taken. A build that fails leaves the file as
|
|
137
|
+
* the merge left it.
|
|
138
|
+
*/
|
|
139
|
+
async function rebuildWorkflows(root, worktree, worktreeProject, scopeRepoPath, run) {
|
|
140
|
+
const builds = workflowBuilds(worktree, worktreeProject, scopeRepoPath);
|
|
141
|
+
if (builds.length === 0)
|
|
142
|
+
return [];
|
|
143
|
+
const linked = [];
|
|
144
|
+
const results = [];
|
|
145
|
+
try {
|
|
146
|
+
for (const member of new Set(builds.map((b) => b.member))) {
|
|
147
|
+
if (member === ".")
|
|
148
|
+
continue;
|
|
149
|
+
const from = join(root, member, "node_modules");
|
|
150
|
+
const to = join(worktreeProject, member, "node_modules");
|
|
151
|
+
if (existsSync(from) && !existsSync(to) && existsSync(dirname(to))) {
|
|
152
|
+
symlinkSync(from, to, "dir");
|
|
153
|
+
linked.push(to);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
for (const b of builds) {
|
|
157
|
+
const before = readFileSync(b.abs);
|
|
158
|
+
const r = await run("build", b.member === "." ? worktreeProject : join(worktreeProject, b.member), b.args);
|
|
159
|
+
const base = { member: b.member, script: b.script, path: b.path, command: b.command };
|
|
160
|
+
if (r.exitCode !== 0) {
|
|
161
|
+
writeFileSync(b.abs, before);
|
|
162
|
+
results.push({ ...base, status: "failed", detail: tail(r.output) });
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const after = existsSync(b.abs) ? readFileSync(b.abs) : null;
|
|
166
|
+
if (after === null) {
|
|
167
|
+
writeFileSync(b.abs, before);
|
|
168
|
+
results.push({ ...base, status: "failed", detail: `\`${b.command}\` exited 0 and wrote no ${b.path}` });
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
results.push({ ...base, status: after.equals(before) ? "unchanged" : "rebuilt" });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
for (const l of linked) {
|
|
176
|
+
try {
|
|
177
|
+
if (lstatSync(l).isSymbolicLink())
|
|
178
|
+
unlinkSync(l);
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
// Already gone.
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return results;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* The template's files as the project would have them (#2627): the manifest
|
|
189
|
+
* removed and the parameters substituted, with the recorded values and the
|
|
190
|
+
* defaults of parameters this version adds. Records that pin a substituted
|
|
191
|
+
* file are re-pinned as init re-pinned them (#2549), for the base and the
|
|
192
|
+
* target alike, so an unedited record compares equal to its base.
|
|
193
|
+
*/
|
|
194
|
+
function instantiate(raw, recorded, label) {
|
|
195
|
+
try {
|
|
196
|
+
const manifest = readManifest(raw);
|
|
197
|
+
const parameters = carryParameters(manifest, recorded);
|
|
198
|
+
const { files, repinned } = repinSubstituted(raw, substituteParameters(raw, manifest, parameters), manifest?.files ?? []);
|
|
199
|
+
return { files, parameters, repinned };
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
throw new UpgradeError(`${label}: ${err.message.replace(/; pass --param .*$/, "")}`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Fetch the target ref, and the commit the scope was made from, of a git
|
|
207
|
+
* source into a scratch repository, and read both trees. The base fetch may
|
|
208
|
+
* fail (a server that refuses fetches by commit); the base is then left empty,
|
|
209
|
+
* and every edited file the template changed becomes a manual step.
|
|
210
|
+
*/
|
|
211
|
+
function fetchGit(root, lineage, ref, onto) {
|
|
212
|
+
const source = lineage.source;
|
|
213
|
+
if (source.type !== "git")
|
|
214
|
+
throw new UpgradeError("not a git source");
|
|
215
|
+
const baseUrl = source.url.startsWith(".") ? resolve(root, source.url) : source.url;
|
|
216
|
+
// With --source (#2551) the target comes from the other template; the base always from the scope's own.
|
|
217
|
+
const url = onto ? onto.url : baseUrl;
|
|
218
|
+
const label = `${onto ? onto.repo : source.repo}@${ref}`;
|
|
219
|
+
const scratch = mkdtempSync(join(tmpdir(), "chant-upgrade-"));
|
|
220
|
+
try {
|
|
221
|
+
git(scratch, ["init", "-q"]);
|
|
222
|
+
try {
|
|
223
|
+
// The network step of `chant workspace upgrade`, catalogued in test/egress-catalogue.ts.
|
|
224
|
+
git(scratch, ["fetch", "-q", "--depth", "1", url, ref]);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
const stderr = err.stderr?.toString().trim();
|
|
228
|
+
throw new UpgradeError(`could not fetch ${label}${stderr ? `: ${stderr}` : ""}`);
|
|
229
|
+
}
|
|
230
|
+
const commit = git(scratch, ["rev-parse", "FETCH_HEAD^{commit}"]);
|
|
231
|
+
const target = readTemplateTree(scratch, commit, onto ? onto.path : source.path, label);
|
|
232
|
+
const raw = new Map();
|
|
233
|
+
const executable = new Set();
|
|
234
|
+
for (const [path, f] of target.files) {
|
|
235
|
+
raw.set(path, f.data);
|
|
236
|
+
if (f.executable)
|
|
237
|
+
executable.add(path);
|
|
238
|
+
}
|
|
239
|
+
// The target with the scope's parameters substituted (#2627), so an
|
|
240
|
+
// unedited file that carries a value compares equal to its base.
|
|
241
|
+
const instantiated = instantiate(raw, lineage.parameters, label);
|
|
242
|
+
let base = new Map();
|
|
243
|
+
const baseCommit = lineage.address?.commit;
|
|
244
|
+
if (baseCommit && baseCommit !== commit) {
|
|
245
|
+
try {
|
|
246
|
+
git(scratch, ["fetch", "-q", "--depth", "1", baseUrl, baseCommit]);
|
|
247
|
+
const oldLabel = `${source.repo}@${baseCommit.slice(0, 12)}`;
|
|
248
|
+
const old = readTemplateTree(scratch, baseCommit, source.path, oldLabel);
|
|
249
|
+
// The base is rebuilt the way init wrote it: the old version's
|
|
250
|
+
// manifest, with the values the lock recorded.
|
|
251
|
+
base = instantiate(new Map([...old.files].map(([path, f]) => [path, f.data])), lineage.parameters, oldLabel).files;
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
// No base from the source; the tree still supplies it for unedited files.
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (baseCommit) {
|
|
258
|
+
base = new Map(instantiated.files);
|
|
259
|
+
}
|
|
260
|
+
const split = splitMigrations(instantiated.files);
|
|
261
|
+
return {
|
|
262
|
+
files: split.files,
|
|
263
|
+
executable,
|
|
264
|
+
base,
|
|
265
|
+
migrations: split.migrations,
|
|
266
|
+
modules: split.modules,
|
|
267
|
+
commit,
|
|
268
|
+
tree: target.tree,
|
|
269
|
+
parameters: instantiated.parameters,
|
|
270
|
+
repinned: instantiated.repinned,
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
finally {
|
|
274
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Why a directory scope cannot be upgraded, with the way out. A directory
|
|
279
|
+
* has no history, so the merge base exists only while the files the scope
|
|
280
|
+
* was made from are still on disk.
|
|
281
|
+
*/
|
|
282
|
+
function dirRefusal(lineage, why) {
|
|
283
|
+
const source = lineage.source;
|
|
284
|
+
return new UpgradeError(`${why}. The scope was made from the directory ${dirLabel(source.path, source.member)}, which has no git history to rebuild a merge base from. ` +
|
|
285
|
+
`Upgrade with --to <dir> while ${source.path} still holds the files the scope was made from, or move the scope onto the git repository the directory was copied from with \`chant workspace adopt-lineage --from <repo>[#<member>]\`.`);
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* The upstream of a directory source (#2647): the new version from the
|
|
289
|
+
* directory `to` names, and the merge base from the recorded directory, used
|
|
290
|
+
* only when its files, instantiated with the recorded parameters, still have
|
|
291
|
+
* the recorded digest. Anything else is refused: a base that is not the one
|
|
292
|
+
* the scope was made from would turn the project's edits into upstream
|
|
293
|
+
* changes. Reaches no network.
|
|
294
|
+
*/
|
|
295
|
+
function readDir(root, lineage, to) {
|
|
296
|
+
const source = lineage.source;
|
|
297
|
+
if (source.type !== "dir")
|
|
298
|
+
throw new UpgradeError("not a directory source");
|
|
299
|
+
if (!to)
|
|
300
|
+
throw dirRefusal(lineage, "no --to directory");
|
|
301
|
+
let target;
|
|
302
|
+
try {
|
|
303
|
+
target = parseDirSpec(to);
|
|
304
|
+
}
|
|
305
|
+
catch {
|
|
306
|
+
target = null;
|
|
307
|
+
}
|
|
308
|
+
if (!target)
|
|
309
|
+
throw new UpgradeError(`--to ${to}: a scope made from a directory upgrades from a directory, and ${to} is not one`);
|
|
310
|
+
const member = to.includes("#") ? target.member : source.member;
|
|
311
|
+
const label = dirLabel(target.path, member);
|
|
312
|
+
const read = readTemplateDir(target.abs, member, label);
|
|
313
|
+
const raw = new Map();
|
|
314
|
+
const executable = new Set();
|
|
315
|
+
for (const [path, f] of read.files) {
|
|
316
|
+
raw.set(path, f.data);
|
|
317
|
+
if (f.executable)
|
|
318
|
+
executable.add(path);
|
|
319
|
+
}
|
|
320
|
+
const instantiated = instantiate(raw, lineage.parameters, label);
|
|
321
|
+
// The merge base: the recorded directory, only while it holds exactly what the scope was made from.
|
|
322
|
+
const original = resolve(root, source.path);
|
|
323
|
+
const originalLabel = dirLabel(source.path, source.member);
|
|
324
|
+
let base;
|
|
325
|
+
try {
|
|
326
|
+
const old = readTemplateDir(original, source.member, originalLabel);
|
|
327
|
+
base = splitMigrations(instantiate(new Map([...old.files].map(([path, f]) => [path, f.data])), lineage.parameters, originalLabel).files).files;
|
|
328
|
+
}
|
|
329
|
+
catch {
|
|
330
|
+
throw dirRefusal(lineage, `${originalLabel} is gone`);
|
|
331
|
+
}
|
|
332
|
+
if (!lineage.address || contentDigest(base) !== lineage.address.digest) {
|
|
333
|
+
throw dirRefusal(lineage, `${originalLabel} no longer holds the files the scope was made from (its digest is not ${lineage.address?.digest ?? "recorded"})`);
|
|
334
|
+
}
|
|
335
|
+
const split = splitMigrations(instantiated.files);
|
|
336
|
+
return {
|
|
337
|
+
files: split.files,
|
|
338
|
+
executable,
|
|
339
|
+
base,
|
|
340
|
+
migrations: split.migrations,
|
|
341
|
+
modules: split.modules,
|
|
342
|
+
parameters: instantiated.parameters,
|
|
343
|
+
repinned: instantiated.repinned,
|
|
344
|
+
source: { type: "dir", path: recordedDirPath(target.path, target.abs, root), ...(member ? { member } : {}) },
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
async function fetchUpstream(root, lineage, ref, onto) {
|
|
348
|
+
const source = lineage.source;
|
|
349
|
+
if (source.type === "git") {
|
|
350
|
+
if (!ref)
|
|
351
|
+
throw new UpgradeError("the scope records no ref; pass --to <ref>");
|
|
352
|
+
return fetchGit(root, lineage, ref, onto);
|
|
353
|
+
}
|
|
354
|
+
if (source.type === "local" || source.type === "archive") {
|
|
355
|
+
const { resolveVendorSource } = await import("../cli/commands/vendor.js");
|
|
356
|
+
const files = await resolveVendorSource(source, root);
|
|
357
|
+
return { files, executable: new Set(), base: new Map(), migrations: [], modules: new Map() };
|
|
358
|
+
}
|
|
359
|
+
if (source.type === "dir")
|
|
360
|
+
return readDir(root, lineage, ref);
|
|
361
|
+
throw new UpgradeError(`scope made by \`chant init --template\` (${lineage.template}) is refused: it came from a lexicon's built-in template, which has no versioned source to fetch, and the merge base would be the render of the chant version that wrote it, which chant cannot rebuild offline. Scopes made by \`chant init --from\` (a git repository or a directory) and \`chant vendor\` scopes upgrade.`);
|
|
362
|
+
}
|
|
363
|
+
/** The merge base per recorded file: from the source's old version, or from an unedited file in the tree. */
|
|
364
|
+
function rebuildBase(scopeDir, lineage, fromSource) {
|
|
365
|
+
const base = new Map();
|
|
366
|
+
for (const [path, entry] of Object.entries(lineage.files)) {
|
|
367
|
+
const old = fromSource.get(path);
|
|
368
|
+
if (old && fileHash(old) === entry.sha256) {
|
|
369
|
+
base.set(path, old);
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
const abs = join(scopeDir, path);
|
|
373
|
+
if (existsSync(abs)) {
|
|
374
|
+
const data = readFileSync(abs);
|
|
375
|
+
if (fileHash(data) === entry.sha256)
|
|
376
|
+
base.set(path, data);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
return base;
|
|
380
|
+
}
|
|
381
|
+
// ── Governance ───────────────────────────────────────────────────────────────
|
|
382
|
+
const GOVERNANCE = [
|
|
383
|
+
/(^|\/)[^/]+\.op\.[cm]?[jt]s$/,
|
|
384
|
+
/(^|\/)chant\.config\.(ts|js|mjs|cjs|json)$/,
|
|
385
|
+
/(^|\/)chant\.workspace\.jsonc?$/,
|
|
386
|
+
/(^|\/)\.github\/workflows\//,
|
|
387
|
+
/(^|\/)\.forgejo\/workflows\//,
|
|
388
|
+
/(^|\/)\.gitea\/workflows\//,
|
|
389
|
+
/(^|\/)\.gitlab-ci\.ya?ml$/,
|
|
390
|
+
/(^|\/)CODEOWNERS$/,
|
|
391
|
+
];
|
|
392
|
+
/** Whether a repository path is a governance file: one that decides gates, pipelines or review. */
|
|
393
|
+
export function isGovernancePath(path) {
|
|
394
|
+
return GOVERNANCE.some((re) => re.test(path));
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* The approval an upgrade gate asks for when the patch changes governance
|
|
398
|
+
* files. Only human approvals count, and the gate needs as many as the
|
|
399
|
+
* strictest gate declared at HEAD in any Op file the patch changes, at least
|
|
400
|
+
* one. The Op files are read from the project's tree, which the upgrade
|
|
401
|
+
* requires to match HEAD for every path the patch touches.
|
|
402
|
+
*/
|
|
403
|
+
async function rulesAtHead(root, repo, paths) {
|
|
404
|
+
const opFiles = new Set(paths.filter((p) => GOVERNANCE[0].test(p)));
|
|
405
|
+
let count = 1;
|
|
406
|
+
let roles;
|
|
407
|
+
if (opFiles.size > 0) {
|
|
408
|
+
const { discoverOps } = await import("../op/discover.js");
|
|
409
|
+
const { ops } = await discoverOps({ cwd: root });
|
|
410
|
+
for (const { config, filePath } of ops.values()) {
|
|
411
|
+
const rel = relative(repo, filePath).split(sep).join("/");
|
|
412
|
+
if (!opFiles.has(rel))
|
|
413
|
+
continue;
|
|
414
|
+
for (const approval of gateApprovals(config)) {
|
|
415
|
+
const need = approval.quorum?.count ?? 1;
|
|
416
|
+
if (need > count) {
|
|
417
|
+
count = need;
|
|
418
|
+
roles = approval.quorum?.roles;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
return { mode: "log-only", quorum: { count, ...(roles && roles.length > 0 ? { roles } : {}) } };
|
|
424
|
+
}
|
|
425
|
+
function gateApprovals(config) {
|
|
426
|
+
const out = [];
|
|
427
|
+
const visit = (step) => {
|
|
428
|
+
if (step.kind === "gate")
|
|
429
|
+
out.push(step.approval ?? {});
|
|
430
|
+
if (step.kind === "effect")
|
|
431
|
+
(step.steps ?? []).forEach(visit);
|
|
432
|
+
};
|
|
433
|
+
for (const p of [...(config.phases ?? []), ...(config.onFailure ?? [])])
|
|
434
|
+
p.steps.forEach(visit);
|
|
435
|
+
return out;
|
|
436
|
+
}
|
|
437
|
+
// ── Stage ────────────────────────────────────────────────────────────────────
|
|
438
|
+
function gitOut(cwd, args) {
|
|
439
|
+
return execFileSync("git", args, { cwd, encoding: "utf-8", stdio: ["ignore", "pipe", "pipe"], maxBuffer: 256 * 1024 * 1024 });
|
|
440
|
+
}
|
|
441
|
+
function isChantProject(dir) {
|
|
442
|
+
return ["chant.config.ts", "chant.config.json", "chant.config.js", "chant.config.mjs"].some((f) => existsSync(join(dir, f)));
|
|
443
|
+
}
|
|
444
|
+
function tail(text, lines = 30) {
|
|
445
|
+
return text.trimEnd().split("\n").slice(-lines).join("\n");
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* The `chant` members `chant.workspace.json` declares in `dir` (#2804): a
|
|
449
|
+
* template built as a workspace, such as the studio kit's, keeps its chant
|
|
450
|
+
* project in a member (`delivery`), not at the scope's root, and the root
|
|
451
|
+
* itself never has a `chant.config`. Empty when `dir` declares no workspace,
|
|
452
|
+
* or the declaration cannot be read: the caller then falls back to `dir`
|
|
453
|
+
* itself.
|
|
454
|
+
*/
|
|
455
|
+
function chantMemberDirs(dir) {
|
|
456
|
+
try {
|
|
457
|
+
return readDeclaration(workingTree(dir))
|
|
458
|
+
.members.filter((m) => m.kind === "chant")
|
|
459
|
+
.map((m) => m.dir);
|
|
460
|
+
}
|
|
461
|
+
catch (err) {
|
|
462
|
+
if (err instanceof WorkspaceReadError)
|
|
463
|
+
return [];
|
|
464
|
+
throw err;
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Resolve the scope argument against `root` (#2550). A scope the lock at
|
|
469
|
+
* `root` holds is used as it is. Otherwise a member the workspace
|
|
470
|
+
* declaration names (by name or directory) that keeps a lock of its own is
|
|
471
|
+
* upgraded from its directory, as the project it is, so its patch, gate and
|
|
472
|
+
* build stay inside it. A member without a lock was not made from a template.
|
|
473
|
+
*/
|
|
474
|
+
export function resolveUpgradeTarget(root, scopeArg) {
|
|
475
|
+
const scope = scopeKey(scopeArg ?? ".");
|
|
476
|
+
const lock = readLock(root);
|
|
477
|
+
if (lock?.scopes[scope])
|
|
478
|
+
return { root, scope };
|
|
479
|
+
if (scope !== ".") {
|
|
480
|
+
let declared = [];
|
|
481
|
+
try {
|
|
482
|
+
declared = readDeclaration(workingTree(root)).members;
|
|
483
|
+
}
|
|
484
|
+
catch (err) {
|
|
485
|
+
if (!(err instanceof WorkspaceReadError))
|
|
486
|
+
throw err;
|
|
487
|
+
}
|
|
488
|
+
const hit = declared.find((m) => m.dir !== "." && (m.name === scopeArg || scopeKey(m.dir) === scope));
|
|
489
|
+
if (hit?.kind === "workspace") {
|
|
490
|
+
// A nested workspace upgrades itself; the outer one never writes inside it (D2, #2551).
|
|
491
|
+
throw new UpgradeError(`member "${hit.name}" is a nested workspace, which upgrades itself: run chant workspace upgrade in ${hit.dir}`);
|
|
492
|
+
}
|
|
493
|
+
if (hit) {
|
|
494
|
+
const memberRoot = join(root, hit.dir);
|
|
495
|
+
if (readLock(memberRoot))
|
|
496
|
+
return { root: memberRoot, scope: ".", member: hit.name };
|
|
497
|
+
throw new UpgradeError(`member "${hit.name}" (${hit.dir}) has no ${LOCK_FILE}, so it was not made from a template and has nothing to upgrade. \`chant init --from <template> ${hit.dir}\` writes one; \`chant workspace adopt-lineage\` is for an older member.`);
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
return { root, scope };
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Stage an upgrade: steps 1 to 5 and the digest of step 6. Nothing in the
|
|
504
|
+
* project's tree changes. The caller decides the gate, then applies the patch
|
|
505
|
+
* with {@link applyStagedUpgrade} or commits it with {@link commitStagedUpgrade},
|
|
506
|
+
* and always calls `dispose()`.
|
|
507
|
+
*/
|
|
508
|
+
export async function stageUpgrade(options) {
|
|
509
|
+
const { root, scope, member } = resolveUpgradeTarget(resolve(options.root), options.scope);
|
|
510
|
+
const lock = readLock(root);
|
|
511
|
+
if (!lock)
|
|
512
|
+
throw new UpgradeError(`no ${LOCK_FILE} in ${root}`);
|
|
513
|
+
const lineage = lock.scopes[scope];
|
|
514
|
+
if (!lineage) {
|
|
515
|
+
throw new UpgradeError(`${LOCK_FILE} has no scope "${scope}" (scopes: ${Object.keys(lock.scopes).join(", ") || "none"})`);
|
|
516
|
+
}
|
|
517
|
+
if (lineage.manualSteps.length > 0) {
|
|
518
|
+
throw new UpgradeError(`scope "${scope}" has ${lineage.manualSteps.length} open manual step(s) from its last update (${lineage.manualSteps.map((s) => s.path).join(", ")}). Merge them and run \`chant workspace lineage resolve <path>\` first.`);
|
|
519
|
+
}
|
|
520
|
+
let repo;
|
|
521
|
+
let head;
|
|
522
|
+
try {
|
|
523
|
+
repo = gitOut(root, ["rev-parse", "--show-toplevel"]).trim();
|
|
524
|
+
head = gitOut(root, ["rev-parse", "HEAD"]).trim();
|
|
525
|
+
}
|
|
526
|
+
catch {
|
|
527
|
+
throw new UpgradeError("chant workspace upgrade stages its change in a git worktree, so the project must be in a git repository with at least one commit");
|
|
528
|
+
}
|
|
529
|
+
const projectRel = relative(repo, root).split(sep).join("/");
|
|
530
|
+
const scopeRepoPath = [projectRel, scope === "." ? "" : scope].filter(Boolean).join("/") || ".";
|
|
531
|
+
const lockRepoPath = [projectRel, LOCK_FILE].filter(Boolean).join("/");
|
|
532
|
+
let lockTracked = true;
|
|
533
|
+
try {
|
|
534
|
+
gitOut(repo, ["ls-files", "--error-unmatch", "--", lockRepoPath]);
|
|
535
|
+
}
|
|
536
|
+
catch {
|
|
537
|
+
lockTracked = false;
|
|
538
|
+
}
|
|
539
|
+
const dirty = gitOut(repo, ["status", "--porcelain", "--untracked-files=all", "--", scopeRepoPath, lockRepoPath])
|
|
540
|
+
.split("\n")
|
|
541
|
+
.filter(Boolean)
|
|
542
|
+
.filter((line) => !line.slice(3).startsWith(`${[projectRel, UPGRADE_DIR].filter(Boolean).join("/")}/`));
|
|
543
|
+
if (dirty.length > 0) {
|
|
544
|
+
throw new UpgradeError(`the scope has uncommitted changes (${dirty.slice(0, 5).map((l) => l.slice(3)).join(", ")}${dirty.length > 5 ? ", …" : ""}). Commit or stash them: the upgrade stages from HEAD and applies its patch to the tree.`);
|
|
545
|
+
}
|
|
546
|
+
// A move to another template (#2551): a git scope only, and to a named ref.
|
|
547
|
+
let onto;
|
|
548
|
+
if (options.source !== undefined) {
|
|
549
|
+
const spec = parseTemplateSource(options.source, root, "--source");
|
|
550
|
+
if (spec.ref !== undefined)
|
|
551
|
+
throw new UpgradeError(`--source ${options.source}: name the version with --to, not "@${spec.ref}"`);
|
|
552
|
+
if (options.to === undefined)
|
|
553
|
+
throw new UpgradeError("--source moves the scope to another template, so it needs --to <ref>: a version of that template");
|
|
554
|
+
if (lineage.source.type !== "git") {
|
|
555
|
+
throw new UpgradeError(`scope "${scope}" has a ${lineage.source.type} source; only a git scope moves to another template. A directory scope moves onto git with chant workspace adopt-lineage first.`);
|
|
556
|
+
}
|
|
557
|
+
onto = { url: spec.url, repo: spec.repo, ...(spec.member ? { path: spec.member } : {}), id: spec.id };
|
|
558
|
+
}
|
|
559
|
+
const switching = onto !== undefined && onto.id !== lineage.template;
|
|
560
|
+
// 1. Fetch. A directory source has no ref: `--to` names the directory.
|
|
561
|
+
const fromDir = lineage.source.type === "dir";
|
|
562
|
+
const ref = fromDir ? undefined : options.to ?? lineage.ref;
|
|
563
|
+
const upstream = await fetchUpstream(root, lineage, fromDir ? options.to : ref, onto);
|
|
564
|
+
// 2. The merge base, offline from here on.
|
|
565
|
+
const base = rebuildBase(join(root, scope), lineage, upstream.base);
|
|
566
|
+
// Plan the chain before anything is staged, so a gap refuses early.
|
|
567
|
+
const plan = lineage.kind === "template" ? planMigrations(lineage, ref, upstream.migrations, onto?.id) : { chain: [] };
|
|
568
|
+
assertCodeAllowed(plan.chain, !!options.allowCode);
|
|
569
|
+
// 3. The worktree, inside the project so the project's packages resolve.
|
|
570
|
+
const holder = join(root, UPGRADE_DIR);
|
|
571
|
+
mkdirSync(holder, { recursive: true });
|
|
572
|
+
const worktree = mkdtempSync(join(holder, `${scope === "." ? "root" : basename(scope)}-`));
|
|
573
|
+
let disposed = false;
|
|
574
|
+
const dispose = () => {
|
|
575
|
+
if (disposed)
|
|
576
|
+
return;
|
|
577
|
+
disposed = true;
|
|
578
|
+
try {
|
|
579
|
+
gitOut(repo, ["worktree", "remove", "--force", worktree]);
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
// Fall through to the directory removal and a prune.
|
|
583
|
+
}
|
|
584
|
+
rmSync(worktree, { recursive: true, force: true });
|
|
585
|
+
try {
|
|
586
|
+
gitOut(repo, ["worktree", "prune"]);
|
|
587
|
+
}
|
|
588
|
+
catch {
|
|
589
|
+
// Nothing to prune.
|
|
590
|
+
}
|
|
591
|
+
if (existsSync(holder) && readdirSync(holder).length === 0)
|
|
592
|
+
rmSync(holder, { recursive: true, force: true });
|
|
593
|
+
};
|
|
594
|
+
try {
|
|
595
|
+
gitOut(repo, ["worktree", "add", "-q", "--detach", worktree, head]);
|
|
596
|
+
const worktreeProject = projectRel ? join(worktree, projectRel) : worktree;
|
|
597
|
+
const scopeDir = join(worktreeProject, scope);
|
|
598
|
+
const next = structuredClone(lock);
|
|
599
|
+
const staged = next.scopes[scope];
|
|
600
|
+
const scratch = mkdtempSync(join(tmpdir(), "chant-upgrade-code-"));
|
|
601
|
+
try {
|
|
602
|
+
for (const m of plan.chain) {
|
|
603
|
+
await runMigration(m, {
|
|
604
|
+
dir: scopeDir,
|
|
605
|
+
lineage: staged,
|
|
606
|
+
modules: upstream.modules,
|
|
607
|
+
allowCode: !!options.allowCode,
|
|
608
|
+
scratch,
|
|
609
|
+
onMove: (from, to) => {
|
|
610
|
+
const data = base.get(from);
|
|
611
|
+
base.delete(from);
|
|
612
|
+
if (data)
|
|
613
|
+
base.set(to, data);
|
|
614
|
+
},
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
finally {
|
|
619
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
620
|
+
}
|
|
621
|
+
// chant's own migrations (#2737): planned from what the scope holds, and
|
|
622
|
+
// applied only when the plan has no conflict. A conflict fails the checks.
|
|
623
|
+
// Each is planned from the tree the ones before it left.
|
|
624
|
+
const chantRuns = lineage.kind === "template" ? runChantMigrations({ dir: scopeDir, lineage: staged, chantVersion: readerVersion() }) : [];
|
|
625
|
+
const chantMigrations = chantRuns.map((r) => reportPlan(r.plan, r.applied));
|
|
626
|
+
// 4. Merge per file.
|
|
627
|
+
const result = applyUpstream(scopeDir, staged, upstream.files, { base, merge: mergeFile });
|
|
628
|
+
for (const path of result.written)
|
|
629
|
+
if (upstream.executable.has(path))
|
|
630
|
+
chmodSync(join(scopeDir, path), 0o755);
|
|
631
|
+
if (ref !== undefined)
|
|
632
|
+
staged.ref = ref;
|
|
633
|
+
if (upstream.parameters)
|
|
634
|
+
staged.parameters = upstream.parameters;
|
|
635
|
+
if (upstream.repinned) {
|
|
636
|
+
// The records this version re-pins, among the files the scope keeps (#2549).
|
|
637
|
+
const kept = upstream.repinned.filter((r) => staged.files[r.record] !== undefined || existsSync(join(scopeDir, r.record)));
|
|
638
|
+
if (kept.length > 0)
|
|
639
|
+
staged.repinned = kept;
|
|
640
|
+
else
|
|
641
|
+
delete staged.repinned;
|
|
642
|
+
}
|
|
643
|
+
if (upstream.commit)
|
|
644
|
+
staged.address = { ...staged.address, commit: upstream.commit, tree: upstream.tree };
|
|
645
|
+
if (upstream.source)
|
|
646
|
+
staged.source = upstream.source;
|
|
647
|
+
if (onto) {
|
|
648
|
+
staged.template = onto.id;
|
|
649
|
+
staged.source = { type: "git", repo: onto.repo, url: portableUrl(onto.url, root), ...(onto.path ? { path: onto.path } : {}) };
|
|
650
|
+
}
|
|
651
|
+
writeLock(worktreeProject, next);
|
|
652
|
+
const lockText = renderLock(next);
|
|
653
|
+
// The CI workflows a chant member builds, rebuilt with this chant (#3244),
|
|
654
|
+
// before the patch is taken so the gate approves them with the rest.
|
|
655
|
+
const workflows = lineage.kind === "template" ? await rebuildWorkflows(root, worktree, worktreeProject, scopeRepoPath, options.runChant ?? spawnChant) : [];
|
|
656
|
+
// The patch, taken before anything else runs in the worktree.
|
|
657
|
+
gitOut(worktree, ["add", "-A"]);
|
|
658
|
+
if (!lockTracked)
|
|
659
|
+
gitOut(worktree, ["rm", "--cached", "-q", "--ignore-unmatch", "--", lockRepoPath]);
|
|
660
|
+
const patch = gitOut(worktree, ["diff", "--cached", "--binary", "--full-index", "--no-color", "--no-ext-diff", head]);
|
|
661
|
+
const changedPaths = gitOut(worktree, ["diff", "--cached", "--name-only", "-z", head]).split("\0").filter(Boolean).sort();
|
|
662
|
+
// An upgrade writes inside its scope and the lock that records it, and nowhere else.
|
|
663
|
+
const outside = changedPaths.filter((p) => scopeRepoPath !== "." && p !== lockRepoPath && p !== scopeRepoPath && !p.startsWith(`${scopeRepoPath}/`));
|
|
664
|
+
if (outside.length > 0) {
|
|
665
|
+
throw new UpgradeError(`the upgrade would change ${outside.slice(0, 5).join(", ")}${outside.length > 5 ? ", ..." : ""}, outside the scope "${scopeRepoPath}". An upgrade writes only inside its own scope.`);
|
|
666
|
+
}
|
|
667
|
+
const lockChanged = !lockTracked && lockText !== readFileSync(join(root, LOCK_FILE), "utf-8");
|
|
668
|
+
const changed = patch.length > 0 || lockChanged;
|
|
669
|
+
const digest = computePlanDigest(UPGRADE_PLAN_KIND, lockTracked ? { scope, patch } : { scope, patch, lock: lockText });
|
|
670
|
+
// The outer workspace never writes inside a nested one (D2, #2551): that one upgrades itself.
|
|
671
|
+
const inNested = pathsInsideNested(worktreeProject, projectRel, changedPaths);
|
|
672
|
+
if (inNested.length > 0) {
|
|
673
|
+
throw new UpgradeError(`the upgrade would change files inside the nested workspace ${inNested[0].member} (${inNested.slice(0, 5).map((p) => p.path).join(", ")}). A nested workspace upgrades itself with its own chant workspace upgrade, and the outer one never writes inside it.`);
|
|
674
|
+
}
|
|
675
|
+
// Governance: decided by the rules at HEAD, never by the upgraded files.
|
|
676
|
+
const governed = changedPaths.filter(isGovernancePath);
|
|
677
|
+
let governance = null;
|
|
678
|
+
if (governed.length > 0) {
|
|
679
|
+
const existing = governed.filter((p) => existsSync(join(repo, p)));
|
|
680
|
+
const touched = existing.length === 0 ? [] : gitOut(repo, ["status", "--porcelain", "--", ...existing]).split("\n").filter(Boolean);
|
|
681
|
+
if (touched.length > 0) {
|
|
682
|
+
throw new UpgradeError(`the upgrade changes governance files that have uncommitted edits (${touched.map((l) => l.slice(3)).join(", ")}). Commit them first: their gates are read at HEAD.`);
|
|
683
|
+
}
|
|
684
|
+
governance = { paths: governed, approval: await rulesAtHead(root, repo, governed), rules: head };
|
|
685
|
+
}
|
|
686
|
+
// 5. Checks.
|
|
687
|
+
const checks = [];
|
|
688
|
+
for (const w of workflows.filter((w) => w.status === "failed")) {
|
|
689
|
+
checks.push({
|
|
690
|
+
name: "build",
|
|
691
|
+
status: "failed",
|
|
692
|
+
member: w.member,
|
|
693
|
+
detail: `${w.path} could not be rebuilt with \`${w.command}\` (the ${w.script} script), so it may differ from what this chant builds:\n${w.detail ?? ""}`,
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
for (const m of chantMigrations.filter((m) => !m.applied)) {
|
|
697
|
+
checks.push({
|
|
698
|
+
name: "migration",
|
|
699
|
+
status: "failed",
|
|
700
|
+
detail: `${m.id} was not applied: ${m.conflicts.map((c) => `${c.path}: ${c.reason}`).join("\n")}`,
|
|
701
|
+
});
|
|
702
|
+
}
|
|
703
|
+
if (changed) {
|
|
704
|
+
// Every `chant` member chant.workspace.json declares, so a template
|
|
705
|
+
// whose chant project sits in a member (the studio kit's `delivery/`)
|
|
706
|
+
// is built and linted there, not skipped for having no chant.config at
|
|
707
|
+
// the scope's root (#2804). A scope with no workspace declaration falls
|
|
708
|
+
// back to the root, as before.
|
|
709
|
+
const members = chantMemberDirs(worktreeProject);
|
|
710
|
+
const targets = members.length > 0 ? members : isChantProject(worktreeProject) ? ["."] : [];
|
|
711
|
+
if (targets.length > 0) {
|
|
712
|
+
const run = options.runChant ?? spawnChant;
|
|
713
|
+
const namedMember = targets.length > 1 || targets[0] !== ".";
|
|
714
|
+
// A member that installs its packages in its own directory resolves them from its node_modules, which is not
|
|
715
|
+
// an ancestor of the staging worktree: link it in from the project (#2847). The patch and its digest are
|
|
716
|
+
// computed above, so the links never reach them, and dispose() removes them with the worktree.
|
|
717
|
+
for (const member of targets) {
|
|
718
|
+
if (member === ".")
|
|
719
|
+
continue;
|
|
720
|
+
const from = join(root, member, "node_modules");
|
|
721
|
+
const to = join(worktreeProject, member, "node_modules");
|
|
722
|
+
if (existsSync(from) && !existsSync(to) && existsSync(dirname(to)))
|
|
723
|
+
symlinkSync(from, to, "dir");
|
|
724
|
+
}
|
|
725
|
+
for (const member of targets) {
|
|
726
|
+
const dir = member === "." ? worktreeProject : join(worktreeProject, member);
|
|
727
|
+
const at = namedMember ? { member } : {};
|
|
728
|
+
for (const command of ["build", "lint"]) {
|
|
729
|
+
const r = await run(command, dir);
|
|
730
|
+
checks.push(r.exitCode === 0 ? { name: command, status: "passed", ...at } : { name: command, status: "failed", detail: tail(r.output), ...at });
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
else {
|
|
735
|
+
for (const name of ["build", "lint"])
|
|
736
|
+
checks.push({ name, status: "skipped", detail: "not a chant project (no chant.config)" });
|
|
737
|
+
}
|
|
738
|
+
checks.push(lineageCheck(root, worktreeProject, result.manualSteps, scope));
|
|
739
|
+
}
|
|
740
|
+
return {
|
|
741
|
+
scope,
|
|
742
|
+
...(member !== undefined ? { member } : {}),
|
|
743
|
+
gate: member ?? scope,
|
|
744
|
+
template: lineage.template,
|
|
745
|
+
...(switching ? { switchedTo: onto.id } : {}),
|
|
746
|
+
kind: lineage.kind,
|
|
747
|
+
from: fromDir ? sourcePin(lineage.source) : lineage.ref ?? null,
|
|
748
|
+
to: fromDir ? sourcePin(staged.source) : staged.ref ?? null,
|
|
749
|
+
...(upstream.commit ? { commit: { ...(lineage.address?.commit ? { from: lineage.address.commit } : {}), to: upstream.commit } } : {}),
|
|
750
|
+
migrations: [...plan.chain.map((m) => m.migration.id), ...chantMigrations.filter((m) => m.applied).map((m) => m.id)],
|
|
751
|
+
chantMigrations,
|
|
752
|
+
workflows,
|
|
753
|
+
written: result.written,
|
|
754
|
+
merged: result.merged,
|
|
755
|
+
removed: result.removed,
|
|
756
|
+
kept: result.kept,
|
|
757
|
+
skipped: result.skipped,
|
|
758
|
+
manualSteps: result.manualSteps,
|
|
759
|
+
changedPaths,
|
|
760
|
+
patch,
|
|
761
|
+
lock: { path: lockRepoPath, tracked: lockTracked, text: lockText },
|
|
762
|
+
changed,
|
|
763
|
+
digest,
|
|
764
|
+
governance,
|
|
765
|
+
checks,
|
|
766
|
+
checksOk: checks.every((c) => c.status !== "failed"),
|
|
767
|
+
repo,
|
|
768
|
+
head,
|
|
769
|
+
worktree,
|
|
770
|
+
worktreeProject,
|
|
771
|
+
dispose,
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
catch (err) {
|
|
775
|
+
dispose();
|
|
776
|
+
throw err;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
/** A directory source's pin, for the summary: the directory it reads. */
|
|
780
|
+
function sourcePin(source) {
|
|
781
|
+
return source.type === "dir" ? dirLabel(source.path, source.member) : null;
|
|
782
|
+
}
|
|
783
|
+
/**
|
|
784
|
+
* `chant workspace check` in the worktree. A finding already present at HEAD
|
|
785
|
+
* is not the upgrade's doing, and the upgrade's own manual steps are what the
|
|
786
|
+
* gate approves; any other finding fails the check.
|
|
787
|
+
*/
|
|
788
|
+
function lineageCheck(root, worktreeProject, ownSteps, scope) {
|
|
789
|
+
const before = new Set(checkLineage(root).findings.map(findingKey));
|
|
790
|
+
const own = new Set(ownSteps.map((s) => (scope === "." ? s.path : `${scope}/${s.path}`)));
|
|
791
|
+
const report = checkLineage(worktreeProject);
|
|
792
|
+
const fresh = report.findings.filter((f) => !before.has(findingKey(f)) && !(f.code === "manual-step-open" && f.path !== undefined && own.has(f.path)));
|
|
793
|
+
if (fresh.length === 0)
|
|
794
|
+
return { name: "workspace check", status: "passed" };
|
|
795
|
+
return { name: "workspace check", status: "failed", detail: fresh.map((f) => `${f.path ?? f.scope ?? ""}: ${f.message}`).join("\n") };
|
|
796
|
+
}
|
|
797
|
+
// ── Apply or propose ─────────────────────────────────────────────────────────
|
|
798
|
+
/** Apply the staged patch to the project's tree. Leaves it uncommitted. */
|
|
799
|
+
export function applyStagedUpgrade(staged) {
|
|
800
|
+
if (!staged.lock.tracked)
|
|
801
|
+
writeFileSync(join(staged.repo, staged.lock.path), staged.lock.text);
|
|
802
|
+
if (!staged.patch)
|
|
803
|
+
return;
|
|
804
|
+
const file = join(mkdtempSync(join(tmpdir(), "chant-upgrade-patch-")), "upgrade.patch");
|
|
805
|
+
try {
|
|
806
|
+
writeFileSync(file, staged.patch);
|
|
807
|
+
execFileSync("git", ["apply", "--binary", "--whitespace=nowarn", file], { cwd: staged.repo, stdio: ["ignore", "pipe", "pipe"] });
|
|
808
|
+
}
|
|
809
|
+
catch (err) {
|
|
810
|
+
const stderr = err.stderr?.toString().trim();
|
|
811
|
+
throw new UpgradeError(`the approved patch no longer applies to the tree${stderr ? `: ${stderr}` : ""}`);
|
|
812
|
+
}
|
|
813
|
+
finally {
|
|
814
|
+
rmSync(join(file, ".."), { recursive: true, force: true });
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Commit the staged patch in the worktree and point `branch` at it. Returns
|
|
819
|
+
* the commit. The caller has already refused the default branch.
|
|
820
|
+
*/
|
|
821
|
+
export function commitStagedUpgrade(staged, branch, message) {
|
|
822
|
+
const identity = [];
|
|
823
|
+
const has = (key) => {
|
|
824
|
+
try {
|
|
825
|
+
return gitOut(staged.worktree, ["config", key]).trim().length > 0;
|
|
826
|
+
}
|
|
827
|
+
catch {
|
|
828
|
+
return false;
|
|
829
|
+
}
|
|
830
|
+
};
|
|
831
|
+
if (!has("user.name"))
|
|
832
|
+
identity.push("-c", "user.name=chant");
|
|
833
|
+
if (!has("user.email"))
|
|
834
|
+
identity.push("-c", "user.email=chant@localhost");
|
|
835
|
+
// An ignored lock is still part of the proposal: the branch starts tracking it.
|
|
836
|
+
if (!staged.lock.tracked)
|
|
837
|
+
gitOut(staged.worktree, ["add", "-f", "--", staged.lock.path]);
|
|
838
|
+
gitOut(staged.worktree, [...identity, "commit", "-q", "--no-verify", "-m", message]);
|
|
839
|
+
const commit = gitOut(staged.worktree, ["rev-parse", "HEAD"]).trim();
|
|
840
|
+
gitOut(staged.repo, ["branch", "-f", branch, commit]);
|
|
841
|
+
return commit;
|
|
842
|
+
}
|
|
843
|
+
/** One line per staged change, for the terminal and for a PR body. */
|
|
844
|
+
export function describeStaged(staged) {
|
|
845
|
+
const lines = [];
|
|
846
|
+
const at = (p) => (staged.scope === "." ? p : `${staged.scope}/${p}`);
|
|
847
|
+
lines.push(`${staged.gate} ${staged.template} ${staged.from ?? "(no ref)"} -> ${staged.to ?? "(no ref)"}`);
|
|
848
|
+
if (staged.switchedTo)
|
|
849
|
+
lines.push(` template: ${staged.template} -> ${staged.switchedTo}`);
|
|
850
|
+
const chantIds = new Set(staged.chantMigrations.map((m) => m.id));
|
|
851
|
+
for (const id of staged.migrations)
|
|
852
|
+
if (!chantIds.has(id))
|
|
853
|
+
lines.push(` migration: ${id}`);
|
|
854
|
+
for (const m of staged.chantMigrations) {
|
|
855
|
+
lines.push(` chant migration: ${m.id} (${m.applied ? "applied" : "not applied: it has conflicts"}), to ${m.description}`);
|
|
856
|
+
for (const c of m.changes)
|
|
857
|
+
lines.push(` ${c.action === "delete" ? "delete" : "write"}: ${at(c.path)} (${c.why}${c.edited ? "; it was edited since the template, and the edit stays in git history" : ""})`);
|
|
858
|
+
for (const n of m.notMoved)
|
|
859
|
+
lines.push(` not moved: ${n.what} -> ${n.where}`);
|
|
860
|
+
for (const c of m.conflicts)
|
|
861
|
+
lines.push(` conflict: ${at(c.path)}: ${c.reason}`);
|
|
862
|
+
}
|
|
863
|
+
for (const w of staged.workflows) {
|
|
864
|
+
if (w.status !== "unchanged")
|
|
865
|
+
lines.push(` workflow ${w.status === "rebuilt" ? "rebuilt" : "not rebuilt"}: ${w.path} (${w.script}: ${w.command})`);
|
|
866
|
+
}
|
|
867
|
+
for (const p of staged.written)
|
|
868
|
+
lines.push(` updated: ${at(p)}`);
|
|
869
|
+
for (const p of staged.merged)
|
|
870
|
+
lines.push(` merged: ${at(p)}`);
|
|
871
|
+
for (const p of staged.removed)
|
|
872
|
+
lines.push(` removed: ${at(p)}`);
|
|
873
|
+
for (const s of staged.skipped) {
|
|
874
|
+
if (s.class === "generated")
|
|
875
|
+
lines.push(` generated, not merged: ${at(s.path)}${s.command ? ` (rebuild with ${s.command})` : ""}`);
|
|
876
|
+
}
|
|
877
|
+
for (const s of staged.manualSteps)
|
|
878
|
+
lines.push(` manual step: ${at(s.path)} (${s.reason})`);
|
|
879
|
+
if (staged.governance) {
|
|
880
|
+
const q = staged.governance.approval.quorum;
|
|
881
|
+
lines.push(` governance: ${staged.governance.paths.join(", ")}; needs ${q.count} human approval(s)${q.roles ? ` with a role in ${q.roles.join(", ")}` : ""}, from the rules at ${staged.governance.rules.slice(0, 12)}`);
|
|
882
|
+
}
|
|
883
|
+
for (const c of staged.checks) {
|
|
884
|
+
const label = c.member !== undefined ? `${c.name} (${c.member})` : c.name;
|
|
885
|
+
lines.push(` ${label}: ${c.status}${c.status === "skipped" && c.detail ? ` (${c.detail})` : ""}`);
|
|
886
|
+
}
|
|
887
|
+
lines.push(` patch: ${staged.changedPaths.length} file(s)${staged.lock.tracked ? "" : ` and the untracked ${LOCK_FILE}`}, ${staged.digest}`);
|
|
888
|
+
return lines;
|
|
889
|
+
}
|