@intentius/chant 0.124.46 → 0.124.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/dist/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/dist/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/dist/__golden__/wave-loop/op-cost-member.json +13 -0
- package/dist/__golden__/wave-loop/op-denied-source.json +16 -0
- package/dist/__golden__/wave-loop/op-denied.json +16 -0
- package/dist/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/dist/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/dist/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/dist/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/dist/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/dist/__golden__/wave-loop/op-held-on.json +16 -0
- package/dist/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/dist/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/dist/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/dist/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/dist/__golden__/wave-loop/op-overridden.json +16 -0
- package/dist/__golden__/wave-loop/op-per-run.json +20 -0
- package/dist/__golden__/wave-loop/op-point.json +13 -0
- package/dist/__golden__/wave-loop/op-pr-review.json +10 -0
- package/dist/__golden__/wave-loop/op-sealed.json +10 -0
- package/dist/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/dist/__golden__/wave-loop/op-spend.json +10 -0
- package/dist/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/dist/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/dist/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/dist/__golden__/wave-loop/op-wide.json +39 -0
- package/dist/action-pins.d.ts +61 -0
- package/dist/action-pins.d.ts.map +1 -0
- package/dist/action-pins.js +77 -0
- package/dist/cli/commands/carve.d.ts +3 -0
- package/dist/cli/commands/carve.d.ts.map +1 -1
- package/dist/cli/commands/carve.js +36 -7
- package/dist/cli/commands/import-report.d.ts +26 -0
- package/dist/cli/commands/import-report.d.ts.map +1 -0
- package/dist/cli/commands/import-report.js +65 -0
- package/dist/cli/commands/import.d.ts +11 -1
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/import.js +22 -3
- package/dist/cli/commands/migrate.d.ts +13 -1
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +134 -10
- package/dist/cli/handlers/approve.d.ts.map +1 -1
- package/dist/cli/handlers/approve.js +21 -2
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/build.js +6 -1
- package/dist/cli/handlers/ledger.d.ts +3 -0
- package/dist/cli/handlers/ledger.d.ts.map +1 -0
- package/dist/cli/handlers/ledger.js +55 -0
- package/dist/cli/handlers/migrate.d.ts.map +1 -1
- package/dist/cli/handlers/migrate.js +18 -11
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/misc.js +12 -1
- package/dist/cli/handlers/pr-env.js +2 -2
- package/dist/cli/handlers/pr.d.ts +15 -1
- package/dist/cli/handlers/pr.d.ts.map +1 -1
- package/dist/cli/handlers/pr.js +143 -39
- package/dist/cli/handlers/query.d.ts +7 -2
- package/dist/cli/handlers/query.d.ts.map +1 -1
- package/dist/cli/handlers/query.js +16 -4
- package/dist/cli/handlers/release.d.ts.map +1 -1
- package/dist/cli/handlers/release.js +6 -3
- package/dist/cli/handlers/search.d.ts +2 -4
- package/dist/cli/handlers/search.d.ts.map +1 -1
- package/dist/cli/handlers/search.js +13 -39
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +65 -14
- package/dist/cli/parse-args.d.ts.map +1 -1
- package/dist/cli/parse-args.js +36 -2
- package/dist/cli/registry.d.ts +14 -4
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/components/builders.d.ts +5 -1
- package/dist/components/builders.d.ts.map +1 -1
- package/dist/components/builders.js +5 -0
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.js +16 -1
- package/dist/components/capability-plugin.d.ts +14 -0
- package/dist/components/capability-plugin.d.ts.map +1 -1
- package/dist/components/pr-hooks.d.ts +21 -1
- package/dist/components/pr-hooks.d.ts.map +1 -1
- package/dist/components/pr-hooks.js +72 -4
- package/dist/components/pr-pipeline.d.ts +45 -10
- package/dist/components/pr-pipeline.d.ts.map +1 -1
- package/dist/components/pr-pipeline.js +47 -14
- package/dist/components/pr-policy.d.ts +36 -0
- package/dist/components/pr-policy.d.ts.map +1 -1
- package/dist/components/pr-policy.js +36 -0
- package/dist/components/starter-plugin.d.ts +1 -0
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/starter-plugin.js +5 -1
- package/dist/components/verbs/index.d.ts +2 -0
- package/dist/components/verbs/index.d.ts.map +1 -1
- package/dist/components/verbs/index.js +2 -0
- package/dist/components/verbs/publish-artifact.d.ts +65 -0
- package/dist/components/verbs/publish-artifact.d.ts.map +1 -0
- package/dist/components/verbs/publish-artifact.js +74 -0
- package/dist/components/verbs/publish-image.d.ts +129 -0
- package/dist/components/verbs/publish-image.d.ts.map +1 -0
- package/dist/components/verbs/publish-image.js +145 -0
- package/dist/config-environments.d.ts +20 -0
- package/dist/config-environments.d.ts.map +1 -1
- package/dist/config-environments.js +12 -0
- package/dist/config.d.ts +9 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +6 -2
- package/dist/gate-decision.d.ts +11 -2
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +15 -3
- package/dist/graph-ir.d.ts +25 -0
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-walk.d.ts +66 -0
- package/dist/graph-walk.d.ts.map +1 -0
- package/dist/graph-walk.js +70 -0
- package/dist/import/parser.d.ts +19 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/lexicon.d.ts +71 -6
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +11 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +2 -5
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/ledger-read.d.ts +65 -0
- package/dist/lifecycle/ledger-read.d.ts.map +1 -0
- package/dist/lifecycle/ledger-read.js +160 -0
- package/dist/lifecycle/release-workstation.d.ts +7 -0
- package/dist/lifecycle/release-workstation.d.ts.map +1 -1
- package/dist/lifecycle/release-workstation.js +25 -0
- package/dist/lifecycle/run-ledger.d.ts +4 -3
- package/dist/lifecycle/run-ledger.d.ts.map +1 -1
- package/dist/lifecycle/run-ledger.js +1 -0
- package/dist/lint/discover.js +3 -1
- package/dist/lint/post-synth.d.ts +127 -1
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lint/post-synth.js +84 -2
- package/dist/lint/rules/op/index.d.ts +1 -0
- package/dist/lint/rules/op/index.d.ts.map +1 -1
- package/dist/lint/rules/op/index.js +2 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts +32 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.d.ts.map +1 -0
- package/dist/lint/rules/op/ops019-workspace-op-target.js +63 -0
- package/dist/op/activities/activity-contracts.d.ts +5 -2
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.js +5 -2
- package/dist/op/activities/index.d.ts +2 -2
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/index.js +1 -1
- package/dist/op/activities/review-agent.d.ts +90 -4
- package/dist/op/activities/review-agent.d.ts.map +1 -1
- package/dist/op/activities/review-agent.js +217 -19
- package/dist/op/activities/work-evidence.d.ts +8 -1
- package/dist/op/activities/work-evidence.d.ts.map +1 -1
- package/dist/op/activities/work-evidence.js +1 -0
- package/dist/op/builders.d.ts +9 -5
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/builders.js +9 -5
- package/dist/op/composites/apply-op.d.ts +29 -2
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/apply-op.js +20 -1
- package/dist/op/gate-approval.d.ts +11 -5
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-approval.js +11 -6
- package/dist/op/gate-quorum.d.ts +100 -3
- package/dist/op/gate-quorum.d.ts.map +1 -1
- package/dist/op/gate-quorum.js +108 -6
- package/dist/op/gate-review.d.ts +9 -0
- package/dist/op/gate-review.d.ts.map +1 -1
- package/dist/op/gate-review.js +13 -0
- package/dist/op/gate.d.ts +44 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/gate.js +25 -4
- package/dist/op/index.d.ts +3 -3
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/index.js +1 -1
- package/dist/op/local-executor.d.ts +38 -3
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/local-executor.js +48 -6
- package/dist/op/op-waves-run.d.ts +26 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +259 -13
- package/dist/op/op-waves.d.ts +72 -5
- package/dist/op/op-waves.d.ts.map +1 -1
- package/dist/op/op-waves.js +110 -15
- package/dist/op/runtime.d.ts +11 -0
- package/dist/op/runtime.d.ts.map +1 -1
- package/dist/op/schedule-overdue.d.ts +16 -0
- package/dist/op/schedule-overdue.d.ts.map +1 -1
- package/dist/op/schedule-overdue.js +36 -0
- package/dist/op/stage-hooks.d.ts +9 -2
- package/dist/op/stage-hooks.d.ts.map +1 -1
- package/dist/op/stage-hooks.js +7 -5
- package/dist/op/workspace-run-env.d.ts +22 -0
- package/dist/op/workspace-run-env.d.ts.map +1 -0
- package/dist/op/workspace-run-env.js +21 -0
- package/dist/pr-forge.d.ts +24 -0
- package/dist/pr-forge.d.ts.map +1 -1
- package/dist/pr-forge.js +47 -0
- package/dist/pr-post.d.ts +42 -0
- package/dist/pr-post.d.ts.map +1 -1
- package/dist/pr-post.js +67 -1
- package/dist/read-filter.d.ts +65 -0
- package/dist/read-filter.d.ts.map +1 -0
- package/dist/read-filter.js +179 -0
- package/dist/run-event.d.ts +1 -1
- package/dist/run-event.d.ts.map +1 -1
- package/dist/terraform/carve.d.ts +24 -3
- package/dist/terraform/carve.d.ts.map +1 -1
- package/dist/terraform/carve.js +32 -14
- package/dist/terraform/cuts.d.ts +97 -0
- package/dist/terraform/cuts.d.ts.map +1 -0
- package/dist/terraform/cuts.js +138 -0
- package/dist/terraform/folds.d.ts +26 -0
- package/dist/terraform/folds.d.ts.map +1 -0
- package/dist/terraform/folds.js +38 -0
- package/dist/terraform/graph.d.ts.map +1 -1
- package/dist/terraform/graph.js +10 -0
- package/dist/terraform/reach.d.ts +140 -0
- package/dist/terraform/reach.d.ts.map +1 -0
- package/dist/terraform/reach.js +170 -0
- package/dist/terraform/score.d.ts +14 -0
- package/dist/terraform/score.d.ts.map +1 -1
- package/dist/terraform/score.js +14 -31
- package/dist/terraform/state.d.ts.map +1 -1
- package/dist/terraform/state.js +4 -2
- package/dist/terraform/types.d.ts +8 -0
- package/dist/terraform/types.d.ts.map +1 -1
- package/dist/wave-blocked.d.ts +10 -1
- package/dist/wave-blocked.d.ts.map +1 -1
- package/dist/wave-blocked.js +31 -3
- package/dist/wave-runtime.mjs +263 -254
- package/dist/workspace/check.schema.json +11 -2
- package/dist/workspace/checks/ci-branch.d.ts +44 -0
- package/dist/workspace/checks/ci-branch.d.ts.map +1 -0
- package/dist/workspace/checks/ci-branch.js +133 -0
- package/dist/workspace/checks/links.d.ts +3 -0
- package/dist/workspace/checks/links.d.ts.map +1 -1
- package/dist/workspace/checks/links.js +12 -1
- package/dist/workspace/checks/org.d.ts +48 -0
- package/dist/workspace/checks/org.d.ts.map +1 -0
- package/dist/workspace/checks/org.js +156 -0
- package/dist/workspace/checks.d.ts +11 -1
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/checks.js +59 -7
- package/dist/workspace/ci-branches.d.ts +16 -0
- package/dist/workspace/ci-branches.d.ts.map +1 -1
- package/dist/workspace/ci-branches.js +27 -0
- package/dist/workspace/ci-green-cli.js +7 -7
- package/dist/workspace/ci-green-workflow.d.ts +1 -1
- package/dist/workspace/ci-green-workflow.d.ts.map +1 -1
- package/dist/workspace/ci-green-workflow.js +13 -8
- package/dist/workspace/ci-green.d.ts +14 -0
- package/dist/workspace/ci-green.d.ts.map +1 -1
- package/dist/workspace/ci-green.js +44 -11
- package/dist/workspace/ci-run.d.ts +9 -1
- package/dist/workspace/ci-run.d.ts.map +1 -1
- package/dist/workspace/ci-run.js +67 -6
- package/dist/workspace/ci-serve.d.ts +9 -0
- package/dist/workspace/ci-serve.d.ts.map +1 -1
- package/dist/workspace/ci-serve.js +114 -76
- package/dist/workspace/compose-graph.d.ts +14 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +4 -1
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/composites.js +5 -2
- package/dist/workspace/composites.schema.json +22 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/dist/workspace/cross-root-lint.d.ts +56 -0
- package/dist/workspace/cross-root-lint.d.ts.map +1 -0
- package/dist/workspace/cross-root-lint.js +111 -0
- package/dist/workspace/dbt-models-reader.d.ts +44 -0
- package/dist/workspace/dbt-models-reader.d.ts.map +1 -0
- package/dist/workspace/dbt-models-reader.js +356 -0
- package/dist/workspace/dbt-project-common.d.ts +40 -0
- package/dist/workspace/dbt-project-common.d.ts.map +1 -0
- package/dist/workspace/dbt-project-common.js +106 -0
- package/dist/workspace/dbt-project-reader.d.ts +4 -3
- package/dist/workspace/dbt-project-reader.d.ts.map +1 -1
- package/dist/workspace/dbt-project-reader.js +14 -108
- package/dist/workspace/decision-rank.d.ts +26 -0
- package/dist/workspace/decision-rank.d.ts.map +1 -0
- package/dist/workspace/decision-rank.js +16 -0
- package/dist/workspace/declaration.d.ts +43 -2
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.js +45 -11
- package/dist/workspace/declaration.schema.json +133 -24
- package/dist/workspace/environments.d.ts +26 -2
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/environments.js +26 -2
- package/dist/workspace/flyway-dir.d.ts +39 -0
- package/dist/workspace/flyway-dir.d.ts.map +1 -0
- package/dist/workspace/flyway-dir.js +104 -0
- package/dist/workspace/flyway-layout.d.ts +96 -0
- package/dist/workspace/flyway-layout.d.ts.map +1 -0
- package/dist/workspace/flyway-layout.js +308 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/graph-cli.js +26 -8
- package/dist/workspace/graph.schema.json +34 -0
- package/dist/workspace/intent.d.ts +2 -3
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/intent.js +5 -9
- package/dist/workspace/kind-link-readers.d.ts +59 -2
- package/dist/workspace/kind-link-readers.d.ts.map +1 -1
- package/dist/workspace/kind-link-readers.js +17 -1
- package/dist/workspace/kinds.d.ts +66 -2
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/kinds.js +98 -4
- package/dist/workspace/ledger.schema.json +158 -0
- package/dist/workspace/lexicon-outputs.d.ts +20 -1
- package/dist/workspace/lexicon-outputs.d.ts.map +1 -1
- package/dist/workspace/lexicon-outputs.js +102 -10
- package/dist/workspace/lineage-check.d.ts +3 -0
- package/dist/workspace/lineage-check.d.ts.map +1 -1
- package/dist/workspace/lineage-check.js +23 -4
- package/dist/workspace/links.d.ts +8 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/links.js +25 -1
- package/dist/workspace/ls.d.ts +8 -0
- package/dist/workspace/ls.d.ts.map +1 -1
- package/dist/workspace/ls.js +7 -1
- package/dist/workspace/ls.schema.json +7 -0
- package/dist/workspace/member-commands.d.ts.map +1 -1
- package/dist/workspace/member-commands.js +54 -5
- package/dist/workspace/migrate-links.d.ts +45 -0
- package/dist/workspace/migrate-links.d.ts.map +1 -0
- package/dist/workspace/migrate-links.js +100 -0
- package/dist/workspace/migration-dirs.d.ts +74 -0
- package/dist/workspace/migration-dirs.d.ts.map +1 -0
- package/dist/workspace/migration-dirs.js +254 -0
- package/dist/workspace/reason-codes.d.ts +8 -0
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/reason-codes.js +11 -0
- package/dist/workspace/records-cli.d.ts +11 -0
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-cli.js +57 -5
- package/dist/workspace/records.schema.json +5 -0
- package/dist/workspace/release-candidates.d.ts +2 -0
- package/dist/workspace/release-candidates.d.ts.map +1 -1
- package/dist/workspace/release-candidates.js +5 -2
- package/dist/workspace/release-train.d.ts +53 -0
- package/dist/workspace/release-train.d.ts.map +1 -0
- package/dist/workspace/release-train.js +134 -0
- package/dist/workspace/release-workflow.d.ts.map +1 -1
- package/dist/workspace/release-workflow.js +4 -3
- package/dist/workspace/repo-ref.d.ts +45 -0
- package/dist/workspace/repo-ref.d.ts.map +1 -0
- package/dist/workspace/repo-ref.js +114 -0
- package/dist/workspace/run-event.schema.json +2 -2
- package/dist/workspace/runs-cli.d.ts +9 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs-cli.js +48 -3
- package/dist/workspace/runs.schema.json +7 -0
- package/dist/workspace/search-contract.d.ts +1 -1
- package/dist/workspace/search-contract.d.ts.map +1 -1
- package/dist/workspace/status-decisions.d.ts +37 -0
- package/dist/workspace/status-decisions.d.ts.map +1 -0
- package/dist/workspace/status-decisions.js +147 -0
- package/dist/workspace/status-gates.d.ts +9 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +4 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/status.js +14 -2
- package/dist/workspace/status.schema.json +6 -0
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-cli.js +5 -3
- package/dist/workspace/work-evidence-ops.d.ts +83 -0
- package/dist/workspace/work-evidence-ops.d.ts.map +1 -0
- package/dist/workspace/work-evidence-ops.js +169 -0
- package/dist/workspace/work-evidence.d.ts +12 -2
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-evidence.js +21 -3
- package/dist/workspace/work-evidence.schema.json +49 -2
- package/dist/workspace/workspace-gates.d.ts +110 -0
- package/dist/workspace/workspace-gates.d.ts.map +1 -0
- package/dist/workspace/workspace-gates.js +140 -0
- package/dist/workspace/workspace-kinds.schema.json +58 -3
- package/dist/workspace/workspace-ledger.d.ts +76 -0
- package/dist/workspace/workspace-ledger.d.ts.map +1 -0
- package/dist/workspace/workspace-ledger.js +91 -0
- package/dist/workspace/workspace-run.d.ts +112 -0
- package/dist/workspace/workspace-run.d.ts.map +1 -0
- package/dist/workspace/workspace-run.js +432 -0
- package/package.json +1 -1
- package/src/__golden__/wave-loop/op-by-apply-after-fails.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-hold.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-ignored.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-pass.json +10 -0
- package/src/__golden__/wave-loop/op-by-apply-skip.json +10 -0
- package/src/__golden__/wave-loop/op-cost-member-clash.json +6 -0
- package/src/__golden__/wave-loop/op-cost-member.json +13 -0
- package/src/__golden__/wave-loop/op-denied-source.json +16 -0
- package/src/__golden__/wave-loop/op-denied.json +16 -0
- package/src/__golden__/wave-loop/op-discover-rest-short.json +6 -0
- package/src/__golden__/wave-loop/op-discover-rest-stops.json +13 -0
- package/src/__golden__/wave-loop/op-discover-rest.json +26 -0
- package/src/__golden__/wave-loop/op-discover-wide.json +26 -0
- package/src/__golden__/wave-loop/op-held-on-again.json +16 -0
- package/src/__golden__/wave-loop/op-held-on-before-apply.json +16 -0
- package/src/__golden__/wave-loop/op-held-on.json +16 -0
- package/src/__golden__/wave-loop/op-hooks-apply-fails.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-after-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-fail-before-plan.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-held.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-hold-before-apply.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-pass.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-refused-at-base.json +13 -0
- package/src/__golden__/wave-loop/op-hooks-share.json +33 -0
- package/src/__golden__/wave-loop/op-outcome-held.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-approved.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan-forever.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-replan.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-stood-down.json +10 -0
- package/src/__golden__/wave-loop/op-outcome-unreadable.json +10 -0
- package/src/__golden__/wave-loop/op-overridden.json +16 -0
- package/src/__golden__/wave-loop/op-per-run.json +20 -0
- package/src/__golden__/wave-loop/op-point.json +13 -0
- package/src/__golden__/wave-loop/op-pr-review.json +10 -0
- package/src/__golden__/wave-loop/op-sealed.json +10 -0
- package/src/__golden__/wave-loop/op-spend-change-only.json +10 -0
- package/src/__golden__/wave-loop/op-spend.json +10 -0
- package/src/__golden__/wave-loop/op-wave-commands.json +55 -0
- package/src/__golden__/wave-loop/op-wide-refused.json +26 -0
- package/src/__golden__/wave-loop/op-wide-waiting.json +29 -0
- package/src/__golden__/wave-loop/op-wide.json +39 -0
- package/src/action-pins.test.ts +78 -0
- package/src/action-pins.ts +92 -0
- package/src/cli/commands/carve-score-once.test.ts +99 -0
- package/src/cli/commands/carve.ts +37 -6
- package/src/cli/commands/check-lexicon.test.ts +2 -2
- package/src/cli/commands/import-report.ts +71 -0
- package/src/cli/commands/import.ts +33 -3
- package/src/cli/commands/migrate-dialect.test.ts +145 -0
- package/src/cli/commands/migrate.ts +132 -11
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +4 -4
- package/src/cli/handlers/approve.ts +23 -2
- package/src/cli/handlers/build.ts +7 -1
- package/src/cli/handlers/ledger.ts +54 -0
- package/src/cli/handlers/migrate.ts +21 -12
- package/src/cli/handlers/misc.ts +10 -1
- package/src/cli/handlers/pr-env.ts +2 -2
- package/src/cli/handlers/pr.ts +138 -36
- package/src/cli/handlers/query.ts +16 -4
- package/src/cli/handlers/release.ts +6 -3
- package/src/cli/handlers/search.ts +13 -34
- package/src/cli/main.test.ts +15 -0
- package/src/cli/main.ts +65 -14
- package/src/cli/parse-args.ts +27 -2
- package/src/cli/registry.ts +14 -4
- package/src/components/builders.ts +8 -0
- package/src/components/capability-plugin-loader.ts +13 -1
- package/src/components/capability-plugin.ts +16 -0
- package/src/components/pr-hooks.test.ts +73 -5
- package/src/components/pr-hooks.ts +95 -5
- package/src/components/pr-pipeline.ts +64 -16
- package/src/components/pr-policy.test.ts +64 -1
- package/src/components/pr-policy.ts +53 -0
- package/src/components/registry.test.ts +1 -1
- package/src/components/starter-plugin.ts +6 -0
- package/src/components/verbs/index.ts +2 -0
- package/src/components/verbs/publish-artifact.test.ts +60 -0
- package/src/components/verbs/publish-artifact.ts +122 -0
- package/src/components/verbs/publish-image.test.ts +101 -0
- package/src/components/verbs/publish-image.ts +265 -0
- package/src/config-environments.ts +28 -1
- package/src/config.ts +8 -1
- package/src/gate-decision-bundle.test.ts +1 -0
- package/src/gate-decision-identity.test.ts +9 -0
- package/src/gate-decision.ts +26 -3
- package/src/graph-ir.ts +27 -0
- package/src/graph-walk.test.ts +44 -0
- package/src/graph-walk.ts +102 -0
- package/src/import/parser.ts +20 -0
- package/src/lexicon.ts +74 -6
- package/src/lifecycle/gate-ledger.ts +8 -0
- package/src/lifecycle/git.ts +2 -2
- package/src/lifecycle/ledger-read.test.ts +107 -0
- package/src/lifecycle/ledger-read.ts +195 -0
- package/src/lifecycle/release-workstation.ts +24 -0
- package/src/lifecycle/run-ledger.ts +5 -2
- package/src/lint/cross-root.test.ts +122 -0
- package/src/lint/discover.ts +3 -1
- package/src/lint/post-synth.ts +212 -2
- package/src/lint/rules/op/index.ts +2 -0
- package/src/lint/rules/op/ops019-workspace-op-target.ts +89 -0
- package/src/op/activities/activity-contracts.ts +5 -2
- package/src/op/activities/index.ts +2 -2
- package/src/op/activities/review-agent.test.ts +221 -4
- package/src/op/activities/review-agent.ts +265 -22
- package/src/op/activities/work-evidence.ts +9 -1
- package/src/op/builders.ts +9 -5
- package/src/op/composites/apply-op.test.ts +108 -0
- package/src/op/composites/apply-op.ts +37 -2
- package/src/op/gate-approval.test.ts +6 -1
- package/src/op/gate-approval.ts +12 -6
- package/src/op/gate-quorum-at-base.test.ts +211 -0
- package/src/op/gate-quorum.ts +156 -8
- package/src/op/gate-review.ts +14 -0
- package/src/op/gate.ts +67 -8
- package/src/op/index.ts +3 -2
- package/src/op/local-executor.ts +69 -9
- package/src/op/op-waves-depends-on.test.ts +81 -0
- package/src/op/op-waves-hook-targets.test.ts +4 -2
- package/src/op/op-waves-quorum-product.test.ts +158 -0
- package/src/op/op-waves-run.ts +288 -14
- package/src/op/op-waves.ts +143 -14
- package/src/op/runtime.ts +8 -0
- package/src/op/schedule-overdue.ts +33 -0
- package/src/op/stage-hooks.ts +13 -5
- package/src/op/workspace-run-env.ts +29 -0
- package/src/pr-forge-bundle.test.ts +2 -2
- package/src/pr-forge.test.ts +47 -0
- package/src/pr-forge.ts +68 -0
- package/src/pr-post-open.e2e.test.ts +36 -0
- package/src/pr-post.test.ts +102 -3
- package/src/pr-post.ts +89 -1
- package/src/read-filter.test.ts +54 -0
- package/src/read-filter.ts +193 -0
- package/src/run-event.ts +1 -1
- package/src/stage-hooks-bundle.test.ts +1 -0
- package/src/terraform/carve.ts +52 -15
- package/src/terraform/cuts.test.ts +173 -0
- package/src/terraform/cuts.ts +188 -0
- package/src/terraform/folds.ts +44 -0
- package/src/terraform/graph.ts +9 -0
- package/src/terraform/radius.test.ts +90 -0
- package/src/terraform/reach.test.ts +146 -0
- package/src/terraform/reach.ts +247 -0
- package/src/terraform/score.ts +27 -29
- package/src/terraform/state.ts +3 -1
- package/src/terraform/types.ts +8 -0
- package/src/wave-blocked.ts +28 -3
- package/src/wave-loop-golden.test.ts +4 -3
- package/src/workspace/behold-kinds.test.ts +1 -1
- package/src/workspace/check-contract.test.ts +7 -6
- package/src/workspace/check.schema.json +11 -2
- package/src/workspace/checks/ci-branch.test.ts +128 -0
- package/src/workspace/checks/ci-branch.ts +141 -0
- package/src/workspace/checks/links.ts +12 -1
- package/src/workspace/checks/org.ts +169 -0
- package/src/workspace/checks.ts +64 -7
- package/src/workspace/ci-branches.ts +31 -0
- package/src/workspace/ci-green-branches.test.ts +153 -0
- package/src/workspace/ci-green-cli.ts +7 -7
- package/src/workspace/ci-green-workflow.test.ts +4 -3
- package/src/workspace/ci-green-workflow.ts +13 -9
- package/src/workspace/ci-green.ts +49 -12
- package/src/workspace/ci-run.test.ts +72 -1
- package/src/workspace/ci-run.ts +68 -8
- package/src/workspace/ci-serve.test.ts +95 -0
- package/src/workspace/ci-serve.ts +106 -65
- package/src/workspace/component-environments.test.ts +25 -2
- package/src/workspace/compose-graph.ts +9 -2
- package/src/workspace/composites.schema.json +22 -0
- package/src/workspace/composites.test.ts +39 -8
- package/src/workspace/composites.ts +6 -2
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +105 -1
- package/src/workspace/cross-root-lint.test.ts +90 -0
- package/src/workspace/cross-root-lint.ts +126 -0
- package/src/workspace/dbt-kind.test.ts +3 -2
- package/src/workspace/dbt-models-reader.ts +362 -0
- package/src/workspace/dbt-models.test.ts +248 -0
- package/src/workspace/dbt-project-common.ts +113 -0
- package/src/workspace/dbt-project-reader.ts +29 -112
- package/src/workspace/decision-rank.ts +40 -0
- package/src/workspace/declaration.schema.json +133 -24
- package/src/workspace/declaration.ts +84 -15
- package/src/workspace/environments.ts +40 -4
- package/src/workspace/flyway-dir.ts +113 -0
- package/src/workspace/flyway-layout.ts +337 -0
- package/src/workspace/graph-cli.ts +25 -10
- package/src/workspace/graph-contract.test.ts +4 -2
- package/src/workspace/graph.schema.json +34 -0
- package/src/workspace/identity.test.ts +14 -2
- package/src/workspace/intent.ts +6 -14
- package/src/workspace/kind-link-readers.ts +68 -3
- package/src/workspace/kinds.test.ts +12 -7
- package/src/workspace/kinds.ts +132 -7
- package/src/workspace/ledger.schema.json +158 -0
- package/src/workspace/lexicon-outputs.ts +132 -13
- package/src/workspace/lineage-check.ts +30 -7
- package/src/workspace/links.ts +24 -1
- package/src/workspace/ls-contract.test.ts +1 -1
- package/src/workspace/ls.schema.json +7 -0
- package/src/workspace/ls.ts +10 -1
- package/src/workspace/member-commands.ts +60 -2
- package/src/workspace/member-file-schema.test.ts +124 -0
- package/src/workspace/migrate-links.test.ts +99 -0
- package/src/workspace/migrate-links.ts +108 -0
- package/src/workspace/migration-dirs.test.ts +272 -0
- package/src/workspace/migration-dirs.ts +267 -0
- package/src/workspace/org-scope.test.ts +238 -0
- package/src/workspace/reason-codes.test.ts +6 -1
- package/src/workspace/reason-codes.ts +11 -0
- package/src/workspace/records-cli.ts +58 -5
- package/src/workspace/records.schema.json +5 -0
- package/src/workspace/release-candidates.ts +7 -2
- package/src/workspace/release-train.ts +157 -0
- package/src/workspace/release-workflow.ts +4 -3
- package/src/workspace/repo-ref.ts +113 -0
- package/src/workspace/run-event.schema.json +2 -2
- package/src/workspace/runs-cli.ts +48 -4
- package/src/workspace/runs.schema.json +7 -0
- package/src/workspace/status-contract.test.ts +46 -1
- package/src/workspace/status-decisions.test.ts +100 -0
- package/src/workspace/status-decisions.ts +151 -0
- package/src/workspace/status-gates.ts +9 -0
- package/src/workspace/status.schema.json +6 -0
- package/src/workspace/status.ts +17 -3
- package/src/workspace/where-filters.test.ts +39 -0
- package/src/workspace/work-cli.ts +5 -3
- package/src/workspace/work-evidence-ops.test.ts +176 -0
- package/src/workspace/work-evidence-ops.ts +189 -0
- package/src/workspace/work-evidence.schema.json +49 -2
- package/src/workspace/work-evidence.ts +22 -3
- package/src/workspace/workspace-gates.ts +200 -0
- package/src/workspace/workspace-kinds.schema.json +58 -3
- package/src/workspace/workspace-ledger.ts +130 -0
- package/src/workspace/workspace-run.test.ts +322 -0
- package/src/workspace/workspace-run.ts +461 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `chant workspace run` (#2554, #2524 D17, ws-030): Ops that span members.
|
|
3
|
+
*
|
|
4
|
+
* A workspace run names `<member>/<op>` targets, or asks for the dependents
|
|
5
|
+
* of one member with `--dependents-of <member> --op <op>`. It:
|
|
6
|
+
*
|
|
7
|
+
* 1. reads every member's graph under the member's own toolchain, as
|
|
8
|
+
* `chant workspace graph` does (`readMembers` in `./graph-cli.ts`), and
|
|
9
|
+
* turns each composed member into a build root for the cross-root mode of
|
|
10
|
+
* post-synth checks (#1939): its graph nodes, Ops among them, become the
|
|
11
|
+
* root's entities;
|
|
12
|
+
* 2. runs OPS019 over those roots, so every target names a composed member
|
|
13
|
+
* and an Op it declares, and runs nothing when one doesn't;
|
|
14
|
+
* 3. orders the targets so a producer runs before the members that link to
|
|
15
|
+
* it (the declared and inferred member links of the composed graph), and
|
|
16
|
+
* otherwise keeps the order given;
|
|
17
|
+
* 4. runs each target's `chant run <op>` in the member's directory under the
|
|
18
|
+
* member's toolchain, one at a time, stopping at the first that does not
|
|
19
|
+
* pass. Each member run gets the workspace run's id in its environment
|
|
20
|
+
* (`CHANT_WORKSPACE_RUN`), and its run record cites it;
|
|
21
|
+
* 5. writes the workspace run's record under `_members/_workspace/<env>/`.
|
|
22
|
+
*
|
|
23
|
+
* With `--gate <name>`, member runs that stop at their own gates are
|
|
24
|
+
* gathered into one pending fact of the workspace gate `<name>`; see
|
|
25
|
+
* `./workspace-gates.ts` for when its approval stands in for theirs.
|
|
26
|
+
*
|
|
27
|
+
* `chant run` at a declared root is untouched: it runs the root's own Ops,
|
|
28
|
+
* and Op discovery leaves member directories out (#2527).
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
import { randomUUID } from "node:crypto";
|
|
32
|
+
import { resolve } from "node:path";
|
|
33
|
+
import { formatError } from "../cli/format";
|
|
34
|
+
import type { CommandContext, ParsedArgs } from "../cli/registry";
|
|
35
|
+
import { runCrossRootChecks, type CrossRootInput, type PostSynthDiagnostic } from "../lint/post-synth";
|
|
36
|
+
import { formatWorkspaceOpTarget, ops019Check, parseWorkspaceOpTarget, type WorkspaceOpTarget } from "../lint/rules/op/ops019-workspace-op-target";
|
|
37
|
+
import type { Declarable } from "../declarable";
|
|
38
|
+
import { readBlobFromPath } from "../lifecycle/git";
|
|
39
|
+
import { GATES_DIR, latestPendingGate, parseGateLedger } from "../lifecycle/gate-ledger";
|
|
40
|
+
import { readRunLedger, DEFAULT_RUN_ENV } from "../lifecycle/run-ledger";
|
|
41
|
+
import { WORKSPACE_GATE_ENV, WORKSPACE_RUN_ENV } from "../op/workspace-run-env";
|
|
42
|
+
import type { ComposedNode, WorkspaceGraph } from "./compose-graph";
|
|
43
|
+
import { readDeclaration, WorkspaceReadError } from "./declaration";
|
|
44
|
+
import { loadKindRegistry } from "./kinds";
|
|
45
|
+
import { executePlan, planMembers } from "./member-commands";
|
|
46
|
+
import { locateWorkspace } from "./which-chant";
|
|
47
|
+
import { appendWorkspaceRun, type WorkspaceRunRecord, type WorkspaceRunStep } from "./workspace-ledger";
|
|
48
|
+
import { appendWorkspaceGatePending, type WorkspaceGateCover, type WorkspaceGatePending } from "./workspace-gates";
|
|
49
|
+
|
|
50
|
+
/** `chant run`'s exit code for a run that stopped at an unapproved gate (`GATED_EXIT_CODE`). */
|
|
51
|
+
const GATED_EXIT = 3;
|
|
52
|
+
|
|
53
|
+
const USAGE =
|
|
54
|
+
"chant workspace run <member>/<op>... [--env <env>] [--gate <name>] [--dry-run] [--json] | chant workspace run --dependents-of <member> --op <op> [--env <env>] [--gate <name>] [--dry-run] [--json] | chant workspace run approve <gate> [--plan <digest>] [--approver <principal>]";
|
|
55
|
+
|
|
56
|
+
// ── Roots from the composed graph ────────────────────────────────────────────
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* One build root per composed member (#1939's `CrossRootInput`): the member's
|
|
60
|
+
* graph nodes become its entities, keyed by the member's own ids, with their
|
|
61
|
+
* attributes as `props`. The member was read under its own toolchain, so
|
|
62
|
+
* this process builds nothing. Members that were skipped or failed have no root.
|
|
63
|
+
*/
|
|
64
|
+
export function crossRootInputs(graph: Pick<WorkspaceGraph, "members" | "nodes">, env?: string): CrossRootInput[] {
|
|
65
|
+
const byMember = new Map<string, ComposedNode[]>();
|
|
66
|
+
for (const n of graph.nodes) {
|
|
67
|
+
if (n.nested !== undefined) continue;
|
|
68
|
+
const list = byMember.get(n.member) ?? [];
|
|
69
|
+
list.push(n);
|
|
70
|
+
byMember.set(n.member, list);
|
|
71
|
+
}
|
|
72
|
+
return graph.members
|
|
73
|
+
.filter((m) => m.status === "composed" && m.kind !== "workspace")
|
|
74
|
+
.map((m) => {
|
|
75
|
+
const entities = new Map<string, Declarable>();
|
|
76
|
+
for (const n of byMember.get(m.name) ?? []) {
|
|
77
|
+
const id = n.id.startsWith(`${m.name}/`) ? n.id.slice(m.name.length + 1) : n.id;
|
|
78
|
+
entities.set(id, { lexicon: n.lexicon, entityType: n.kind, props: n.attrs } as unknown as Declarable);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
root: m.name,
|
|
82
|
+
dir: m.dir,
|
|
83
|
+
...(env ? { env } : {}),
|
|
84
|
+
buildResult: { outputs: new Map(), entities, warnings: [], errors: [], sourceFileCount: 0 },
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── Order ────────────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
/** Producer to consumers, from the composed graph's member links (declared and inferred, any status but invalid). */
|
|
92
|
+
export function memberDependents(links: WorkspaceGraph["links"]): Map<string, Set<string>> {
|
|
93
|
+
const out = new Map<string, Set<string>>();
|
|
94
|
+
for (const row of links) {
|
|
95
|
+
const r = row as { producer?: unknown; consumer?: unknown; status?: unknown };
|
|
96
|
+
if (typeof r.producer !== "string" || typeof r.consumer !== "string") continue;
|
|
97
|
+
if (r.status === "invalid" || r.producer === r.consumer) continue;
|
|
98
|
+
const set = out.get(r.producer) ?? new Set<string>();
|
|
99
|
+
set.add(r.consumer);
|
|
100
|
+
out.set(r.producer, set);
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Every member that links to `member`, directly or through others, nearest first. */
|
|
106
|
+
export function dependentsOf(member: string, links: WorkspaceGraph["links"]): string[] {
|
|
107
|
+
const edges = memberDependents(links);
|
|
108
|
+
const seen = new Set<string>([member]);
|
|
109
|
+
const order: string[] = [];
|
|
110
|
+
let frontier = [member];
|
|
111
|
+
while (frontier.length > 0) {
|
|
112
|
+
const next: string[] = [];
|
|
113
|
+
for (const m of frontier) {
|
|
114
|
+
for (const c of [...(edges.get(m) ?? [])].sort()) {
|
|
115
|
+
if (seen.has(c)) continue;
|
|
116
|
+
seen.add(c);
|
|
117
|
+
order.push(c);
|
|
118
|
+
next.push(c);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
frontier = next;
|
|
122
|
+
}
|
|
123
|
+
return order;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Order targets so a producer's targets run before its consumers', keeping
|
|
128
|
+
* the given order otherwise. A cycle among the targets' members keeps the
|
|
129
|
+
* given order for the members in it.
|
|
130
|
+
*/
|
|
131
|
+
export function orderTargets(targets: readonly WorkspaceOpTarget[], links: WorkspaceGraph["links"]): WorkspaceOpTarget[] {
|
|
132
|
+
const edges = memberDependents(links);
|
|
133
|
+
const members = [...new Set(targets.map((t) => t.member))];
|
|
134
|
+
const reach = (from: string, to: string): boolean => {
|
|
135
|
+
const seen = new Set<string>();
|
|
136
|
+
const stack = [from];
|
|
137
|
+
while (stack.length > 0) {
|
|
138
|
+
const m = stack.pop()!;
|
|
139
|
+
for (const c of edges.get(m) ?? []) {
|
|
140
|
+
if (c === to) return true;
|
|
141
|
+
if (!seen.has(c)) {
|
|
142
|
+
seen.add(c);
|
|
143
|
+
stack.push(c);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return false;
|
|
148
|
+
};
|
|
149
|
+
// Kahn's algorithm over the targets' members, choosing the earliest given member each time.
|
|
150
|
+
const before = new Map(members.map((m) => [m, members.filter((o) => o !== m && reach(o, m) && !reach(m, o))]));
|
|
151
|
+
const placed: string[] = [];
|
|
152
|
+
const left = [...members];
|
|
153
|
+
while (left.length > 0) {
|
|
154
|
+
const i = left.findIndex((m) => before.get(m)!.every((o) => placed.includes(o)));
|
|
155
|
+
const pick = left.splice(i < 0 ? 0 : i, 1)[0]!;
|
|
156
|
+
placed.push(pick);
|
|
157
|
+
}
|
|
158
|
+
return placed.flatMap((m) => targets.filter((t) => t.member === m));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── The run ──────────────────────────────────────────────────────────────────
|
|
162
|
+
|
|
163
|
+
/** What a member's `chant run` answered. */
|
|
164
|
+
export interface MemberOpResult {
|
|
165
|
+
exitCode: number;
|
|
166
|
+
stdout: string;
|
|
167
|
+
stderr: string;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface WorkspaceRunQuery {
|
|
171
|
+
cwd: string;
|
|
172
|
+
/** `<member>/<op>` targets. Empty with {@link dependentsOf}. */
|
|
173
|
+
targets: string[];
|
|
174
|
+
/** Run `op` in every member that links to this one, directly or not, and not in the member itself. */
|
|
175
|
+
dependentsOf?: string;
|
|
176
|
+
/** The Op `dependentsOf` runs. */
|
|
177
|
+
op?: string;
|
|
178
|
+
env?: string;
|
|
179
|
+
/** The workspace gate member gates may wait on together. */
|
|
180
|
+
gate?: string;
|
|
181
|
+
dryRun?: boolean;
|
|
182
|
+
/** Extra flags each member's `chant run` gets, such as `--on <lexicon>`. */
|
|
183
|
+
runArgs?: string[];
|
|
184
|
+
/** Overrides, for tests. */
|
|
185
|
+
readGraph?: (cwd: string) => Promise<{ graph: WorkspaceGraph; failed: boolean } | { error: string }>;
|
|
186
|
+
runMember?: (member: { name: string; dir: string }, argv: string[], env: Record<string, string>) => Promise<MemberOpResult>;
|
|
187
|
+
now?: () => string;
|
|
188
|
+
/** Where the member's output goes as each step ends. */
|
|
189
|
+
onOutput?: (target: string, result: MemberOpResult) => void;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** A step a dependents run left out, and why. */
|
|
193
|
+
export interface WorkspaceRunSkip {
|
|
194
|
+
member: string;
|
|
195
|
+
reason: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export type WorkspaceRunOutcome =
|
|
199
|
+
| { kind: "refused"; message: string; findings: PostSynthDiagnostic[] }
|
|
200
|
+
| { kind: "planned"; id: string; targets: string[]; skipped: WorkspaceRunSkip[] }
|
|
201
|
+
| { kind: "ran"; record: WorkspaceRunRecord; skipped: WorkspaceRunSkip[]; pending: WorkspaceGatePending | null; ledgerError: string | null };
|
|
202
|
+
|
|
203
|
+
async function defaultReadGraph(cwd: string): Promise<{ graph: WorkspaceGraph; failed: boolean } | { error: string }> {
|
|
204
|
+
const { workspaceGraph } = await import("./graph-cli");
|
|
205
|
+
const { doc, failed } = await workspaceGraph({ cwd, onStderr: (t) => process.stderr.write(t) });
|
|
206
|
+
if ("error" in doc) return { error: `${doc.error.code}: ${doc.error.message}` };
|
|
207
|
+
return { graph: doc, failed };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Run one member's `chant run`, under the member's own toolchain (the one
|
|
212
|
+
* `chant workspace graph` reads it with), from inside its directory.
|
|
213
|
+
*/
|
|
214
|
+
async function defaultRunMember(cwd: string, member: { name: string; dir: string }, argv: string[], env: Record<string, string>): Promise<MemberOpResult> {
|
|
215
|
+
const located = locateWorkspace(cwd);
|
|
216
|
+
const declaration = readDeclaration(located.tree, "", { rootChant: true });
|
|
217
|
+
const { registry: kinds } = loadKindRegistry(declaration.pins, located.rootOnDisk);
|
|
218
|
+
const plan = planMembers("graph", located.rootOnDisk, { only: [member.name], tree: located.tree, kinds });
|
|
219
|
+
if (plan.groups.length === 0) return { exitCode: 1, stdout: "", stderr: `member ${member.name} has no chant to run it\n` };
|
|
220
|
+
const saved = Object.fromEntries(Object.keys(env).map((k) => [k, process.env[k]]));
|
|
221
|
+
Object.assign(process.env, env);
|
|
222
|
+
try {
|
|
223
|
+
const [r] = await executePlan(plan, {} as ParsedArgs, () => argv);
|
|
224
|
+
return r ? { exitCode: r.exitCode, stdout: r.stdout, stderr: r.stderr } : { exitCode: 1, stdout: "", stderr: `member ${member.name} did not run\n` };
|
|
225
|
+
} finally {
|
|
226
|
+
for (const [k, v] of Object.entries(saved)) {
|
|
227
|
+
if (v === undefined) delete process.env[k];
|
|
228
|
+
else process.env[k] = v;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** The environment directory a member Op run records under: its `labels.Env`, else `local` (`runEnvOf`). */
|
|
234
|
+
function opEnv(graph: WorkspaceGraph, t: WorkspaceOpTarget): string {
|
|
235
|
+
for (const n of graph.nodes) {
|
|
236
|
+
if (n.member !== t.member || n.kind !== "Chant::Op") continue;
|
|
237
|
+
const attrs = n.attrs as { name?: unknown; labels?: { Env?: unknown } };
|
|
238
|
+
if (attrs.name === t.op) return typeof attrs.labels?.Env === "string" ? attrs.labels.Env : DEFAULT_RUN_ENV;
|
|
239
|
+
}
|
|
240
|
+
return DEFAULT_RUN_ENV;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/** The member run that cites workspace run `id`, and the gate it stopped at, read from the member's ledgers. */
|
|
244
|
+
async function memberRunOf(cwd: string, member: string, op: string, env: string, id: string): Promise<{ run: string | null; gate?: WorkspaceRunStep["gate"] }> {
|
|
245
|
+
const { records } = await readRunLedger(env, op, { cwd, member });
|
|
246
|
+
const record = records.filter((r) => r.workspaceRun?.id === id).at(-1);
|
|
247
|
+
if (!record) return { run: null };
|
|
248
|
+
if (record.status !== "gated" || !record.gate) return { run: record.id };
|
|
249
|
+
const gateOp = record.gate.op ?? op;
|
|
250
|
+
const content = await readBlobFromPath(GATES_DIR, `${gateOp}.jsonl`, { cwd, member });
|
|
251
|
+
const pending = content ? parseGateLedger(content).pending.filter((p) => p.runId === record.id) : [];
|
|
252
|
+
const fact = latestPendingGate(pending, record.gate.name);
|
|
253
|
+
return {
|
|
254
|
+
run: record.id,
|
|
255
|
+
gate: { op: gateOp, name: record.gate.name, planDigest: fact?.planDigest ?? null, environment: fact?.environment ?? null },
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/** Plan and, unless `dryRun`, run a workspace run. Throws a {@link WorkspaceReadError} when the declaration can't be read. */
|
|
260
|
+
export async function workspaceRun(query: WorkspaceRunQuery): Promise<WorkspaceRunOutcome> {
|
|
261
|
+
const now = query.now ?? (() => new Date().toISOString());
|
|
262
|
+
const id = `ws-${randomUUID()}`;
|
|
263
|
+
|
|
264
|
+
// Targets, before anything is read.
|
|
265
|
+
let targets: WorkspaceOpTarget[] = [];
|
|
266
|
+
for (const text of query.targets) {
|
|
267
|
+
const t = parseWorkspaceOpTarget(text);
|
|
268
|
+
if (!t) return { kind: "refused", message: `"${text}" is not a <member>/<op> target`, findings: [] };
|
|
269
|
+
targets.push(t);
|
|
270
|
+
}
|
|
271
|
+
if (query.dependentsOf !== undefined && !query.op) return { kind: "refused", message: "--dependents-of needs the Op to run: --op <op>", findings: [] };
|
|
272
|
+
if (query.dependentsOf === undefined && targets.length === 0) return { kind: "refused", message: "name at least one <member>/<op> target, or --dependents-of <member> --op <op>", findings: [] };
|
|
273
|
+
|
|
274
|
+
const read = await (query.readGraph ?? defaultReadGraph)(query.cwd);
|
|
275
|
+
if ("error" in read) return { kind: "refused", message: `the workspace graph could not be read: ${read.error}`, findings: [] };
|
|
276
|
+
const { graph } = read;
|
|
277
|
+
const roots = crossRootInputs(graph, query.env);
|
|
278
|
+
|
|
279
|
+
const skipped: WorkspaceRunSkip[] = [];
|
|
280
|
+
if (query.dependentsOf !== undefined) {
|
|
281
|
+
const op = query.op!;
|
|
282
|
+
if (!graph.members.some((m) => m.name === query.dependentsOf)) {
|
|
283
|
+
return { kind: "refused", message: `--dependents-of ${query.dependentsOf}: the workspace declares no such member`, findings: [] };
|
|
284
|
+
}
|
|
285
|
+
for (const member of dependentsOf(query.dependentsOf, graph.links)) {
|
|
286
|
+
const root = roots.find((r) => r.root === member);
|
|
287
|
+
const hasOp = root && [...root.buildResult.entities.values()].some((e) => e.entityType === "Chant::Op" && (e as unknown as { props?: { name?: unknown } }).props?.name === op);
|
|
288
|
+
if (hasOp) targets.push({ member, op });
|
|
289
|
+
else skipped.push({ member, reason: root ? `declares no Op named "${op}"` : "is not a composed chant member" });
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// OPS019 over the composed roots: the targets must exist before anything runs.
|
|
294
|
+
const findings = runCrossRootChecks([ops019Check(targets)], roots, query.env ? { env: query.env } : undefined);
|
|
295
|
+
if (findings.some((f) => f.severity === "error")) {
|
|
296
|
+
return { kind: "refused", message: "a target does not name an Op of a composed member", findings };
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
targets = orderTargets(targets, graph.links);
|
|
300
|
+
if (query.dryRun) return { kind: "planned", id, targets: targets.map(formatWorkspaceOpTarget), skipped };
|
|
301
|
+
|
|
302
|
+
const started = now();
|
|
303
|
+
const steps: WorkspaceRunStep[] = targets.map((t) => ({ target: formatWorkspaceOpTarget(t), member: t.member, op: t.op, status: "not-run", exitCode: null, memberRun: null }));
|
|
304
|
+
const env: Record<string, string> = { [WORKSPACE_RUN_ENV]: id, ...(query.gate ? { [WORKSPACE_GATE_ENV]: query.gate } : {}) };
|
|
305
|
+
const runMember = query.runMember ?? ((m, argv, e) => defaultRunMember(query.cwd, m, argv, e));
|
|
306
|
+
let status: WorkspaceRunRecord["status"] = "ok";
|
|
307
|
+
for (let i = 0; i < targets.length; i++) {
|
|
308
|
+
const t = targets[i]!;
|
|
309
|
+
const step = steps[i]!;
|
|
310
|
+
const member = graph.members.find((m) => m.name === t.member)!;
|
|
311
|
+
const argv = ["run", t.op, ...(query.env ? ["--env", query.env] : []), ...(query.runArgs ?? [])];
|
|
312
|
+
const result = await runMember({ name: member.name, dir: member.dir }, argv, env);
|
|
313
|
+
query.onOutput?.(step.target, result);
|
|
314
|
+
step.exitCode = result.exitCode;
|
|
315
|
+
step.status = result.exitCode === 0 ? "ok" : result.exitCode === GATED_EXIT ? "gated" : "fail";
|
|
316
|
+
try {
|
|
317
|
+
const found = await memberRunOf(query.cwd, t.member, t.op, opEnv(graph, t), id);
|
|
318
|
+
step.memberRun = found.run;
|
|
319
|
+
if (found.gate) step.gate = found.gate;
|
|
320
|
+
} catch {
|
|
321
|
+
// A member whose ledger can't be read still ran; the step keeps no member run id.
|
|
322
|
+
}
|
|
323
|
+
if (step.status === "fail") {
|
|
324
|
+
status = "fail";
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
if (step.status === "gated") {
|
|
328
|
+
status = "gated";
|
|
329
|
+
// With a workspace gate, the other targets still run to their gates, so one approval covers them all.
|
|
330
|
+
if (!query.gate) break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const record: WorkspaceRunRecord = {
|
|
335
|
+
version: 1,
|
|
336
|
+
id,
|
|
337
|
+
started,
|
|
338
|
+
ended: now(),
|
|
339
|
+
status,
|
|
340
|
+
env: query.env ?? null,
|
|
341
|
+
gate: query.gate ?? null,
|
|
342
|
+
dependentsOf: query.dependentsOf ?? null,
|
|
343
|
+
steps,
|
|
344
|
+
};
|
|
345
|
+
|
|
346
|
+
let pending: WorkspaceGatePending | null = null;
|
|
347
|
+
let ledgerError: string | null = null;
|
|
348
|
+
try {
|
|
349
|
+
const covers: WorkspaceGateCover[] = steps
|
|
350
|
+
.filter((s) => s.status === "gated" && s.gate?.planDigest)
|
|
351
|
+
.map((s) => ({ member: s.member, op: s.gate!.op, gate: s.gate!.name, planDigest: s.gate!.planDigest!, ...(s.gate!.environment ? { environment: s.gate!.environment } : {}) }));
|
|
352
|
+
if (query.gate && covers.length > 0) pending = await appendWorkspaceGatePending(query.cwd, { gate: query.gate, run: id, timestamp: record.ended, covers });
|
|
353
|
+
await appendWorkspaceRun(query.cwd, record);
|
|
354
|
+
} catch (err) {
|
|
355
|
+
ledgerError = err instanceof Error ? err.message : String(err);
|
|
356
|
+
}
|
|
357
|
+
return { kind: "ran", record, skipped, pending, ledgerError };
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ── The command ──────────────────────────────────────────────────────────────
|
|
361
|
+
|
|
362
|
+
function describeFinding(f: PostSynthDiagnostic): string {
|
|
363
|
+
return `${f.checkId}: ${f.message}`;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export async function runWorkspaceRun(ctx: CommandContext): Promise<number> {
|
|
367
|
+
const { args } = ctx;
|
|
368
|
+
const words = args.positionals ?? [];
|
|
369
|
+
// positionals[0] is "run".
|
|
370
|
+
const rest = words[0] === "run" ? words.slice(1) : words;
|
|
371
|
+
if (rest[0] === "approve") return runWorkspaceRunApprove(ctx, rest.slice(1));
|
|
372
|
+
|
|
373
|
+
const cwd = resolve(".");
|
|
374
|
+
// The root's chant runs the workspace run (ws-021).
|
|
375
|
+
const { handToRootChant } = await import("./which-chant");
|
|
376
|
+
const handed = await handToRootChant(cwd, undefined);
|
|
377
|
+
if (handed !== undefined) return handed;
|
|
378
|
+
let outcome: WorkspaceRunOutcome;
|
|
379
|
+
try {
|
|
380
|
+
outcome = await workspaceRun({
|
|
381
|
+
cwd,
|
|
382
|
+
targets: rest,
|
|
383
|
+
...(args.dependentsOf !== undefined ? { dependentsOf: args.dependentsOf } : {}),
|
|
384
|
+
...(args.op !== undefined ? { op: args.op } : {}),
|
|
385
|
+
...(args.env !== undefined ? { env: args.env } : {}),
|
|
386
|
+
...(args.gate !== undefined ? { gate: args.gate } : {}),
|
|
387
|
+
...(args.dryRun ? { dryRun: true } : {}),
|
|
388
|
+
...(args.on !== undefined ? { runArgs: ["--on", args.on] } : {}),
|
|
389
|
+
onOutput: args.json
|
|
390
|
+
? undefined
|
|
391
|
+
: (target, r) => {
|
|
392
|
+
process.stderr.write(`── ${target} (exit ${r.exitCode})\n`);
|
|
393
|
+
if (r.stdout) process.stderr.write(r.stdout.endsWith("\n") ? r.stdout : `${r.stdout}\n`);
|
|
394
|
+
if (r.stderr) process.stderr.write(r.stderr.endsWith("\n") ? r.stderr : `${r.stderr}\n`);
|
|
395
|
+
},
|
|
396
|
+
});
|
|
397
|
+
} catch (err) {
|
|
398
|
+
if (!(err instanceof WorkspaceReadError)) throw err;
|
|
399
|
+
console.error(formatError({ message: `${err.code}: ${err.describe()}`, hint: USAGE }));
|
|
400
|
+
return 1;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
if (outcome.kind === "refused") {
|
|
404
|
+
if (args.json) console.log(JSON.stringify({ status: "refused", message: outcome.message, findings: outcome.findings }, null, 2));
|
|
405
|
+
console.error(formatError({ message: outcome.message, hint: USAGE }));
|
|
406
|
+
for (const f of outcome.findings) console.error(` ${describeFinding(f)}`);
|
|
407
|
+
return 1;
|
|
408
|
+
}
|
|
409
|
+
if (outcome.kind === "planned") {
|
|
410
|
+
if (args.json) {
|
|
411
|
+
console.log(JSON.stringify({ status: "planned", targets: outcome.targets, skipped: outcome.skipped }, null, 2));
|
|
412
|
+
} else {
|
|
413
|
+
console.log(`chant workspace run would run, in order:`);
|
|
414
|
+
for (const t of outcome.targets) console.log(` ${t}`);
|
|
415
|
+
for (const s of outcome.skipped) console.log(` (skipped ${s.member}: ${s.reason})`);
|
|
416
|
+
}
|
|
417
|
+
return 0;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const { record, pending, ledgerError, skipped } = outcome;
|
|
421
|
+
if (args.json) {
|
|
422
|
+
console.log(JSON.stringify({ ...record, skipped, pending, ledgerError }, null, 2));
|
|
423
|
+
} else {
|
|
424
|
+
console.log(`workspace run ${record.id}: ${record.status}`);
|
|
425
|
+
for (const s of record.steps) console.log(` ${s.target.padEnd(32)} ${s.status}${s.memberRun ? ` (run ${s.memberRun})` : ""}${s.gate ? ` gate ${s.gate.name}` : ""}`);
|
|
426
|
+
for (const s of skipped) console.log(` (skipped ${s.member}: ${s.reason})`);
|
|
427
|
+
if (pending) {
|
|
428
|
+
console.log(`Workspace gate "${pending.gate}" is pending over ${pending.covers.length} member gate(s), digest ${pending.digest}.`);
|
|
429
|
+
console.log(` Approve: chant workspace run approve ${pending.gate} --plan ${pending.digest}`);
|
|
430
|
+
console.log(` It stands in only for members that set acceptWorkspaceGates: true at base; the others need their own approval.`);
|
|
431
|
+
}
|
|
432
|
+
if (ledgerError) console.error(formatError({ message: `the workspace run record was not written: ${ledgerError}` }));
|
|
433
|
+
}
|
|
434
|
+
if (record.status === "fail") return 1;
|
|
435
|
+
if (record.status === "gated") return GATED_EXIT;
|
|
436
|
+
return 0;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
async function runWorkspaceRunApprove(ctx: CommandContext, words: string[]): Promise<number> {
|
|
440
|
+
const gate = words[0];
|
|
441
|
+
if (!gate) {
|
|
442
|
+
console.error(formatError({ message: "chant workspace run approve needs the workspace gate's name", hint: USAGE }));
|
|
443
|
+
return 1;
|
|
444
|
+
}
|
|
445
|
+
const { approveWorkspaceGate } = await import("./workspace-gates");
|
|
446
|
+
const approvedBy = ctx.args.approver ?? ctx.args.actor ?? process.env.GITHUB_ACTOR ?? process.env.GITLAB_USER_LOGIN ?? process.env.USER ?? "unknown";
|
|
447
|
+
try {
|
|
448
|
+
const record = await approveWorkspaceGate(resolve("."), {
|
|
449
|
+
gate,
|
|
450
|
+
...(ctx.args.plan !== undefined ? { digest: ctx.args.plan } : {}),
|
|
451
|
+
approvedBy,
|
|
452
|
+
timestamp: new Date().toISOString(),
|
|
453
|
+
});
|
|
454
|
+
if (ctx.args.json) console.log(JSON.stringify(record, null, 2));
|
|
455
|
+
else console.log(`Approved workspace gate "${gate}" (${record.digest}) as ${approvedBy}, covering ${record.covers.map((c) => `${c.member}/${c.op}:${c.gate}`).join(", ")}.`);
|
|
456
|
+
return 0;
|
|
457
|
+
} catch (err) {
|
|
458
|
+
console.error(formatError({ message: err instanceof Error ? err.message : String(err), hint: USAGE }));
|
|
459
|
+
return 1;
|
|
460
|
+
}
|
|
461
|
+
}
|