@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
|
@@ -24,17 +24,24 @@
|
|
|
24
24
|
*
|
|
25
25
|
* Under `--at` the revision's files are not on disk to fold, so a member
|
|
26
26
|
* whose lexicons report outputs gets a gap instead.
|
|
27
|
+
*
|
|
28
|
+
* The consumer side works the same way (#4397): a lexicon's `workspaceLinks`
|
|
29
|
+
* hook names the outputs of other members its declarations read, such as
|
|
30
|
+
* the tables an otel `clickhouse` exporter writes. {@link gatherLexiconLinks}
|
|
31
|
+
* folds every member whose lexicons have the hook and hands back what they
|
|
32
|
+
* report, in the shape a kind's link reader returns (`./kind-link-readers.ts`),
|
|
33
|
+
* so `resolveLinks` checks those links like a dbt project's sources.
|
|
27
34
|
*/
|
|
28
35
|
|
|
29
36
|
import { join, posix } from "node:path";
|
|
30
37
|
import type { StaticFieldsRead } from "../config-static";
|
|
31
38
|
import { isDeclarable, type Declarable } from "../declarable";
|
|
32
|
-
import type { LexiconUnreadSource, LexiconWorkspaceOutput } from "../graph-ir";
|
|
39
|
+
import type { LexiconUnreadSource, LexiconWorkspaceLinks, LexiconWorkspaceOutput } from "../graph-ir";
|
|
33
40
|
import type { BuildRootContext, BuildRootContribution, IntrinsicDef } from "../lexicon";
|
|
34
41
|
import type { Declaration, ResolvedGroup } from "./declaration";
|
|
35
42
|
import type { KindRegistry } from "./kinds";
|
|
36
43
|
import { kindHandles } from "./links";
|
|
37
|
-
import { readKindLinks } from "./kind-link-readers";
|
|
44
|
+
import { readKindLinks, type KindLinkRead } from "./kind-link-readers";
|
|
38
45
|
import { memberExcludes, sourceFiles } from "./member-handles";
|
|
39
46
|
import { memberDirOnDisk } from "./lexicon-symbols";
|
|
40
47
|
import type { WorkspaceTree } from "./tree";
|
|
@@ -51,6 +58,7 @@ export interface OutputsPlugin {
|
|
|
51
58
|
intrinsics?: () => IntrinsicDef[];
|
|
52
59
|
buildRoots?: (ctx: BuildRootContext) => Promise<BuildRootContribution>;
|
|
53
60
|
workspaceOutputs?: (entities: ReadonlyMap<string, Declarable>, unread?: readonly LexiconUnreadSource[]) => { outputs: LexiconWorkspaceOutput[]; gaps?: string[] } | undefined;
|
|
61
|
+
workspaceLinks?: (entities: ReadonlyMap<string, Declarable>, unread?: readonly LexiconUnreadSource[]) => LexiconWorkspaceLinks | undefined;
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
/** Loads a lexicon plugin by name; `loadPlugin` from the CLI unless a test swaps it. */
|
|
@@ -60,6 +68,8 @@ export interface GatherLexiconOutputsOptions {
|
|
|
60
68
|
/** Read under `--at`: the member's files are a revision's, not on disk, so nothing is folded. */
|
|
61
69
|
atRevision?: boolean;
|
|
62
70
|
load?: OutputsPluginLoader;
|
|
71
|
+
/** Links the members' lexicons read (#4397), from {@link gatherLexiconLinks}: the members they target are read too. */
|
|
72
|
+
lexiconLinks?: ReadonlyMap<string, KindLinkRead>;
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
const firstLine = (err: unknown): string => (err instanceof Error ? err.message : String(err)).split("\n")[0];
|
|
@@ -134,7 +144,7 @@ export async function gatherLexiconOutputs(
|
|
|
134
144
|
const targets = new Set(declaration.members.flatMap((m) => m.links.filter((l) => l.member !== m.name).map((l) => l.member)));
|
|
135
145
|
// Links a kind's reader finds in a member's files target members too (#3932). One that names no
|
|
136
146
|
// producer may be any other member's, so every other member is read.
|
|
137
|
-
for (const [consumer, read] of readKindLinks(declaration, tree, kinds)) {
|
|
147
|
+
for (const [consumer, read] of [...readKindLinks(declaration, tree, kinds), ...(options.lexiconLinks ?? new Map<string, KindLinkRead>())]) {
|
|
138
148
|
for (const link of read.links) {
|
|
139
149
|
if (link.member !== null) targets.add(link.member);
|
|
140
150
|
else for (const m of declaration.members) if (m.name !== consumer) targets.add(m.name);
|
|
@@ -165,14 +175,36 @@ function importedLexicons(tree: WorkspaceTree, files: readonly string[]): string
|
|
|
165
175
|
return [...names].sort();
|
|
166
176
|
}
|
|
167
177
|
|
|
168
|
-
|
|
178
|
+
type Hook = "workspaceOutputs" | "workspaceLinks";
|
|
179
|
+
|
|
180
|
+
/** A member's source folded for the lexicons that have `hook`, or why it wasn't. */
|
|
181
|
+
type FoldedMember =
|
|
182
|
+
| { status: "none" }
|
|
183
|
+
| { status: "gaps"; gaps: string[] }
|
|
184
|
+
| {
|
|
185
|
+
status: "folded";
|
|
186
|
+
reporting: { name: string; plugin: OutputsPlugin }[];
|
|
187
|
+
entities: Map<string, Declarable>;
|
|
188
|
+
unread: LexiconUnreadSource[];
|
|
189
|
+
gaps: string[];
|
|
190
|
+
/** The tree-relative file that exports each entity, and that file's text. */
|
|
191
|
+
sourceOf: (entity: Declarable) => { file: string; text: string } | undefined;
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Fold one member's source for the lexicons that implement `hook`, never
|
|
196
|
+
* running it. "none" when no lexicon of the member's has the hook.
|
|
197
|
+
*/
|
|
198
|
+
async function foldMember(
|
|
169
199
|
root: string,
|
|
170
200
|
declaration: Declaration,
|
|
171
201
|
tree: WorkspaceTree,
|
|
172
202
|
groups: readonly ResolvedGroup[],
|
|
173
203
|
m: Declaration["members"][number],
|
|
174
204
|
options: GatherLexiconOutputsOptions,
|
|
175
|
-
|
|
205
|
+
hook: Hook,
|
|
206
|
+
): Promise<FoldedMember> {
|
|
207
|
+
const what = hook === "workspaceOutputs" ? "outputs" : "links";
|
|
176
208
|
const dir = memberDirOnDisk(root, m.dir);
|
|
177
209
|
const { readConfigFieldsStatically } = await import("../config-static");
|
|
178
210
|
const files = withinSourceDir(
|
|
@@ -188,7 +220,7 @@ async function readMemberLexiconOutputs(
|
|
|
188
220
|
// source imports stand in for the ones it names.
|
|
189
221
|
names = importedLexicons(tree, files);
|
|
190
222
|
}
|
|
191
|
-
if (names.length === 0) return
|
|
223
|
+
if (names.length === 0) return { status: "none" };
|
|
192
224
|
const load = options.load ?? ((await import("../cli/plugins")).loadPlugin as unknown as OutputsPluginLoader);
|
|
193
225
|
const plugins: { name: string; plugin: OutputsPlugin }[] = [];
|
|
194
226
|
const gaps: string[] = [];
|
|
@@ -196,13 +228,13 @@ async function readMemberLexiconOutputs(
|
|
|
196
228
|
try {
|
|
197
229
|
plugins.push({ name, plugin: await load(name) });
|
|
198
230
|
} catch (err) {
|
|
199
|
-
gaps.push(`lexicon "${name}" could not be loaded, so the
|
|
231
|
+
gaps.push(`lexicon "${name}" could not be loaded, so the ${what} it reads were not (${firstLine(err)})`);
|
|
200
232
|
}
|
|
201
233
|
}
|
|
202
|
-
const reporting = plugins.filter((p) => typeof p.plugin
|
|
203
|
-
if (reporting.length === 0) return gaps.length ? {
|
|
234
|
+
const reporting = plugins.filter((p) => typeof p.plugin[hook] === "function");
|
|
235
|
+
if (reporting.length === 0) return gaps.length && hook === "workspaceOutputs" ? { status: "gaps", gaps } : { status: "none" };
|
|
204
236
|
if (options.atRevision) {
|
|
205
|
-
return {
|
|
237
|
+
return { status: "gaps", gaps: [`the ${what} of lexicon ${reporting.map((p) => p.name).join(", ")} are read from the working tree's files, not a revision's`] };
|
|
206
238
|
}
|
|
207
239
|
|
|
208
240
|
// Fold the member's source, never run it.
|
|
@@ -216,15 +248,15 @@ async function readMemberLexiconOutputs(
|
|
|
216
248
|
});
|
|
217
249
|
let entities: Map<string, Declarable> = new Map();
|
|
218
250
|
const unread: LexiconUnreadSource[] = [];
|
|
251
|
+
const folded: { file: string; rel: string; exports: Record<string, unknown> }[] = [];
|
|
219
252
|
try {
|
|
220
253
|
const { foldProject } = await import("../discovery/fold-import");
|
|
221
254
|
const { collectEntities } = await import("../discovery/collect");
|
|
222
255
|
const verdicts = await foldProject(files.map(abs), intrinsics, { lexicons: names, sandbox: true });
|
|
223
|
-
const folded: { file: string; exports: Record<string, unknown> }[] = [];
|
|
224
256
|
for (const file of files) {
|
|
225
257
|
const v = verdicts.get(abs(file));
|
|
226
258
|
if (v?.verdict === "fold" && v.exports) {
|
|
227
|
-
folded.push({ file: abs(file), exports: ownExports(v.exports, names) });
|
|
259
|
+
folded.push({ file: abs(file), rel: file, exports: ownExports(v.exports, names) });
|
|
228
260
|
continue;
|
|
229
261
|
}
|
|
230
262
|
let text = "";
|
|
@@ -238,7 +270,7 @@ async function readMemberLexiconOutputs(
|
|
|
238
270
|
}
|
|
239
271
|
entities = collectEntities(folded, dir);
|
|
240
272
|
} catch (err) {
|
|
241
|
-
return {
|
|
273
|
+
return { status: "gaps", gaps: [...gaps, `${m.dir}: its source could not be folded, so its lexicons' ${what} were not read (${firstLine(err)})`] };
|
|
242
274
|
}
|
|
243
275
|
|
|
244
276
|
// A reporting lexicon's own build roots (the sql lexicon's `.sql` files) join
|
|
@@ -257,6 +289,32 @@ async function readMemberLexiconOutputs(
|
|
|
257
289
|
}
|
|
258
290
|
}
|
|
259
291
|
|
|
292
|
+
const sourceOf = (entity: Declarable) => {
|
|
293
|
+
const f = folded.find((x) => Object.values(x.exports).includes(entity));
|
|
294
|
+
if (!f) return undefined;
|
|
295
|
+
let text = "";
|
|
296
|
+
try {
|
|
297
|
+
text = tree.read(f.rel);
|
|
298
|
+
} catch {
|
|
299
|
+
// The line falls back to 1.
|
|
300
|
+
}
|
|
301
|
+
return { file: f.rel, text };
|
|
302
|
+
};
|
|
303
|
+
return { status: "folded", reporting, entities, unread, gaps, sourceOf };
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
async function readMemberLexiconOutputs(
|
|
307
|
+
root: string,
|
|
308
|
+
declaration: Declaration,
|
|
309
|
+
tree: WorkspaceTree,
|
|
310
|
+
groups: readonly ResolvedGroup[],
|
|
311
|
+
m: Declaration["members"][number],
|
|
312
|
+
options: GatherLexiconOutputsOptions,
|
|
313
|
+
): Promise<MemberLexiconOutputs | undefined> {
|
|
314
|
+
const member = await foldMember(root, declaration, tree, groups, m, options, "workspaceOutputs");
|
|
315
|
+
if (member.status === "none") return undefined;
|
|
316
|
+
if (member.status === "gaps") return { outputs: [], gaps: member.gaps };
|
|
317
|
+
const { reporting, entities, unread, gaps } = member;
|
|
260
318
|
const outputs: MemberLexiconOutputs["outputs"] = [];
|
|
261
319
|
for (const { name, plugin } of reporting) {
|
|
262
320
|
try {
|
|
@@ -270,3 +328,64 @@ async function readMemberLexiconOutputs(
|
|
|
270
328
|
}
|
|
271
329
|
return { outputs, gaps };
|
|
272
330
|
}
|
|
331
|
+
|
|
332
|
+
/** The line of `export const <name>` (or any declaration of it) in `text`, from 1; 1 when not found. */
|
|
333
|
+
function declarationLine(text: string, name: string): number {
|
|
334
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
335
|
+
const at = text.search(new RegExp(`\\b(?:const|let|var|function|class)\\s+${escaped}\\b`));
|
|
336
|
+
return at < 0 ? 1 : text.slice(0, at).split("\n").length;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* The links each `chant` member's lexicons read from its declarations
|
|
341
|
+
* (#4397), keyed by member name, in the shape a kind's link reader returns.
|
|
342
|
+
* Only members with a lexicon that has a `workspaceLinks` hook are folded. A
|
|
343
|
+
* link carries the file and line of the declaration that states it, and the
|
|
344
|
+
* reader is named `lexicon <name>`.
|
|
345
|
+
*/
|
|
346
|
+
export async function gatherLexiconLinks(
|
|
347
|
+
root: string,
|
|
348
|
+
declaration: Declaration,
|
|
349
|
+
tree: WorkspaceTree,
|
|
350
|
+
groups: readonly ResolvedGroup[],
|
|
351
|
+
kinds: KindRegistry,
|
|
352
|
+
options: GatherLexiconOutputsOptions = {},
|
|
353
|
+
): Promise<Map<string, KindLinkRead>> {
|
|
354
|
+
const out = new Map<string, KindLinkRead>();
|
|
355
|
+
for (const m of declaration.members) {
|
|
356
|
+
const kind = kinds.get(m.kind);
|
|
357
|
+
if (!kind || kindHandles(m, kind) || tree.stat(memberDir(m.dir)) !== "dir") continue;
|
|
358
|
+
const member = await foldMember(root, declaration, tree, groups, m, options, "workspaceLinks");
|
|
359
|
+
if (member.status === "none") continue;
|
|
360
|
+
const where = memberDir(m.dir) || ".";
|
|
361
|
+
if (member.status === "gaps") {
|
|
362
|
+
out.set(m.name, { reader: "lexicon", links: [], gaps: member.gaps.map((message) => ({ file: where, line: 1, message })) });
|
|
363
|
+
continue;
|
|
364
|
+
}
|
|
365
|
+
for (const { name, plugin } of member.reporting) {
|
|
366
|
+
const read: KindLinkRead = { reader: `lexicon ${name}`, links: [], gaps: member.gaps.map((message) => ({ file: where, line: 1, message })) };
|
|
367
|
+
try {
|
|
368
|
+
const report = plugin.workspaceLinks!(member.entities, member.unread);
|
|
369
|
+
if (!report) continue;
|
|
370
|
+
for (const l of report.links) {
|
|
371
|
+
const entity = member.entities.get(l.entity);
|
|
372
|
+
const src = entity ? member.sourceOf(entity) : undefined;
|
|
373
|
+
read.links.push({
|
|
374
|
+
member: l.member ?? null,
|
|
375
|
+
output: l.output,
|
|
376
|
+
...(l.anchor ? { anchor: l.anchor } : {}),
|
|
377
|
+
file: src?.file ?? where,
|
|
378
|
+
line: src ? declarationLine(src.text, l.entity.split(".").pop() ?? l.entity) : 1,
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
for (const g of report.gaps ?? []) read.gaps.push({ file: where, line: 1, message: g });
|
|
382
|
+
} catch (err) {
|
|
383
|
+
read.gaps.push({ file: where, line: 1, message: `lexicon "${name}" workspaceLinks threw, so its links were not read (${firstLine(err)})` });
|
|
384
|
+
}
|
|
385
|
+
if (read.links.length === 0 && read.gaps.length === 0) continue;
|
|
386
|
+
const prev = out.get(m.name);
|
|
387
|
+
out.set(m.name, prev ? { reader: prev.reader, links: [...prev.links, ...read.links], gaps: [...prev.gaps, ...read.gaps] } : read);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
return out;
|
|
391
|
+
}
|
|
@@ -24,13 +24,14 @@
|
|
|
24
24
|
* (`changes-cli.ts`, #2773), which prints a document of its own.
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
|
-
import { realpathSync } from "node:fs";
|
|
27
|
+
import { readFileSync, realpathSync } from "node:fs";
|
|
28
28
|
import { join, relative, resolve, sep } from "node:path";
|
|
29
29
|
import { formatError, formatSuccess } from "../cli/format";
|
|
30
30
|
import type { CommandContext } from "../cli/registry";
|
|
31
31
|
import type { LintDiagnostic, LintRule } from "../lint/rule";
|
|
32
32
|
import { findWorkspaceRoot } from "../project-root";
|
|
33
33
|
import type { DeclarationCheckReport } from "./checks";
|
|
34
|
+
import type { ForgeRepoList } from "./checks/org";
|
|
34
35
|
import type { RecordFacts } from "./checks/records";
|
|
35
36
|
import { LOCK_FILE, LockError, parseLock, readLock } from "./lineage-lock";
|
|
36
37
|
import type { ReasonCode } from "./reason-codes";
|
|
@@ -91,7 +92,7 @@ export function findingKey(f: CheckFinding): string {
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
const USAGE =
|
|
94
|
-
"chant workspace check [--at <rev>] [--json] [--format stylish|json|sarif] [--generated] [--kind <kind file>] [--live --env <env>]\n chant workspace check --changes <base>..<head> [--work <id>] [--severity off|warn|fail] [--kind <kind file>...] [--json]";
|
|
95
|
+
"chant workspace check [--at <rev>] [--json] [--format stylish|json|sarif] [--generated] [--kind <kind file>] [--live --env <env>] [--forge-repos <file>]\n chant workspace check --changes <base>..<head> [--work <id>] [--severity off|warn|fail] [--kind <kind file>...] [--json]";
|
|
95
96
|
const FORMATS = ["stylish", "json", "sarif"] as const;
|
|
96
97
|
|
|
97
98
|
/** A lock finding as a lint diagnostic, for `--format json` and `--format sarif`. */
|
|
@@ -141,7 +142,7 @@ export type CheckDocument =
|
|
|
141
142
|
chant: string;
|
|
142
143
|
at: string | null;
|
|
143
144
|
/** The declaration's workspace, or null when there is none; `name` is null when it can't be read. */
|
|
144
|
-
workspace: { name: string | null; root: string } | null;
|
|
145
|
+
workspace: { name: string | null; root: string; repo: string | null } | null;
|
|
145
146
|
declaration?: DeclarationCheckReport;
|
|
146
147
|
})
|
|
147
148
|
| { $schema: string; contract: number; chant: string; error: { code: CheckErrorCode; message: string; location: null } };
|
|
@@ -152,7 +153,11 @@ export type CheckDocument =
|
|
|
152
153
|
* to `cwd`. `runGenerators` is `--generated`; with `at` it does nothing,
|
|
153
154
|
* since the member facts describe the working tree, not the revision.
|
|
154
155
|
*/
|
|
155
|
-
export async function runChecks(
|
|
156
|
+
export async function runChecks(
|
|
157
|
+
cwd: string,
|
|
158
|
+
at?: string,
|
|
159
|
+
options: { runGenerators?: boolean; kind?: string; live?: { env: string; onStderr?: (text: string) => void }; forgeRepos?: ForgeRepoList } = {},
|
|
160
|
+
): Promise<CheckDocument> {
|
|
156
161
|
// Loaded here, not at the top: `workspace upgrade` imports this module for checkLineage alone.
|
|
157
162
|
const [{ findDeclarationDir, readDeclaration, readerVersion }, { gitTop, gitTree, resolveCommit, workingTree }] = await Promise.all([
|
|
158
163
|
import("./declaration"),
|
|
@@ -190,7 +195,7 @@ export async function runChecks(cwd: string, at?: string, options: { runGenerato
|
|
|
190
195
|
}
|
|
191
196
|
|
|
192
197
|
let declaration: DeclarationCheckReport | undefined;
|
|
193
|
-
let workspace: { name: string | null; root: string } | null = null;
|
|
198
|
+
let workspace: { name: string | null; root: string; repo: string | null } | null = null;
|
|
194
199
|
if (found) {
|
|
195
200
|
const { runDeclarationChecks } = await import("./checks");
|
|
196
201
|
const { dir, tree } = found;
|
|
@@ -200,6 +205,7 @@ export async function runChecks(cwd: string, at?: string, options: { runGenerato
|
|
|
200
205
|
...(commit !== null ? { tree } : {}),
|
|
201
206
|
...(records ? { records } : {}),
|
|
202
207
|
...(options.live ? { live: options.live } : {}),
|
|
208
|
+
...(options.forgeRepos ? { forgeRepos: options.forgeRepos } : {}),
|
|
203
209
|
});
|
|
204
210
|
let name: string | null = null;
|
|
205
211
|
try {
|
|
@@ -207,7 +213,8 @@ export async function runChecks(cwd: string, at?: string, options: { runGenerato
|
|
|
207
213
|
} catch {
|
|
208
214
|
// The WSP001 finding already says why.
|
|
209
215
|
}
|
|
210
|
-
|
|
216
|
+
const { repoIdentity } = await import("./repo-ref");
|
|
217
|
+
workspace = { name, root: found.root, repo: repoIdentity(dir) };
|
|
211
218
|
}
|
|
212
219
|
const ok = report.ok && (declaration?.ok ?? true);
|
|
213
220
|
return { ...head, at: commit, workspace, ...report, ok, ...(declaration ? { declaration } : {}) };
|
|
@@ -267,7 +274,23 @@ export async function runWorkspaceCheck(ctx: CommandContext): Promise<number> {
|
|
|
267
274
|
const handed = await handToRootChant(root, ctx.args.at);
|
|
268
275
|
if (handed !== undefined) return handed;
|
|
269
276
|
}
|
|
270
|
-
|
|
277
|
+
// The forge's repository list (#3168) is input a warden writes; chant never asks the forge itself.
|
|
278
|
+
let forgeRepos: ForgeRepoList | undefined;
|
|
279
|
+
if (ctx.args.forgeRepos !== undefined) {
|
|
280
|
+
const { parseForgeRepos } = await import("./checks/org");
|
|
281
|
+
try {
|
|
282
|
+
forgeRepos = parseForgeRepos(readFileSync(resolve(ctx.args.forgeRepos), "utf-8"), ctx.args.forgeRepos);
|
|
283
|
+
} catch (err) {
|
|
284
|
+
console.error(formatError({ message: `--forge-repos: ${(err as Error).message}`, hint: USAGE }));
|
|
285
|
+
return 1;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
const doc = await runChecks(root, ctx.args.at, {
|
|
289
|
+
runGenerators: ctx.args.generated === true,
|
|
290
|
+
...(ctx.args.kind !== undefined ? { kind: ctx.args.kind } : {}),
|
|
291
|
+
...(ctx.args.live && ctx.args.env ? { live: { env: ctx.args.env, onStderr: (text: string) => process.stderr.write(text) } } : {}),
|
|
292
|
+
...(forgeRepos ? { forgeRepos } : {}),
|
|
293
|
+
});
|
|
271
294
|
if ("error" in doc) {
|
|
272
295
|
if (ctx.args.json || format === "json") console.log(JSON.stringify(doc, null, 2));
|
|
273
296
|
else console.error(formatError({ message: `${doc.error.code}: ${doc.error.message}`, hint: USAGE }));
|
package/src/workspace/links.ts
CHANGED
|
@@ -195,10 +195,11 @@ function nearNames(name: string, outputs: JoinHandle[]): string[] {
|
|
|
195
195
|
*/
|
|
196
196
|
export function resolveLinks(
|
|
197
197
|
declaration: Declaration,
|
|
198
|
-
|
|
198
|
+
sourceHandles: ReadonlyMap<string, MemberHandles>,
|
|
199
199
|
telemetry?: TelemetryTargets,
|
|
200
200
|
readLinks?: ReadonlyMap<string, KindLinkRead>,
|
|
201
201
|
): LinkTableRow[] {
|
|
202
|
+
const handles = withReaderOutputs(sourceHandles, readLinks);
|
|
202
203
|
const rows: LinkTableRow[] = [];
|
|
203
204
|
const declaredTargets = new Map<string, Set<string>>();
|
|
204
205
|
|
|
@@ -311,6 +312,28 @@ export function resolveLinks(
|
|
|
311
312
|
return [...rows, ...inferred];
|
|
312
313
|
}
|
|
313
314
|
|
|
315
|
+
/**
|
|
316
|
+
* `handles` with the outputs each member's kind reader found in its files
|
|
317
|
+
* (#3935) added to the member's own. The member stays complete unless a gap
|
|
318
|
+
* the reader flagged `outputs` left a name out. A member with no handles
|
|
319
|
+
* (its directory is missing, or its kind unknown) gets none.
|
|
320
|
+
*/
|
|
321
|
+
export function withReaderOutputs(handles: ReadonlyMap<string, MemberHandles>, reads: ReadonlyMap<string, KindLinkRead> | undefined): ReadonlyMap<string, MemberHandles> {
|
|
322
|
+
if (!reads) return handles;
|
|
323
|
+
let out: Map<string, MemberHandles> | undefined;
|
|
324
|
+
for (const [member, read] of reads) {
|
|
325
|
+
const base = handles.get(member);
|
|
326
|
+
const gaps = read.gaps.filter((g) => g.outputs);
|
|
327
|
+
if (!base || (!read.outputs?.length && gaps.length === 0)) continue;
|
|
328
|
+
const have = new Set(base.outputs.map((o) => o.name));
|
|
329
|
+
const added = (read.outputs ?? []).filter((o) => !have.has(o.name) && have.add(o.name)).map((o) => ({ name: o.name }));
|
|
330
|
+
const complete = base.complete && gaps.length === 0;
|
|
331
|
+
const why = base.why ?? (gaps.length === 0 ? null : gaps.length === 1 ? gaps[0].message : `${gaps[0].message}, and ${gaps.length - 1} more`);
|
|
332
|
+
(out ??= new Map(handles)).set(member, { ...base, outputs: [...base.outputs, ...added], complete, why: complete ? base.why : why, exposesNone: false });
|
|
333
|
+
}
|
|
334
|
+
return out ?? handles;
|
|
335
|
+
}
|
|
336
|
+
|
|
314
337
|
/** Match a declared or reader's output row against its producer's handles, setting its status and reason. */
|
|
315
338
|
function resolveOutput(row: LinkRow, handles: ReadonlyMap<string, MemberHandles>): void {
|
|
316
339
|
const producer = handles.get(row.producer);
|
|
@@ -129,7 +129,7 @@ describe("chant workspace ls on built workspaces", () => {
|
|
|
129
129
|
["tools", false, "kind-probe-failed"],
|
|
130
130
|
["vendor", true, null],
|
|
131
131
|
]);
|
|
132
|
-
expect(doc.members[2].reason?.message).toMatch(/known kinds: chant, design, other, workspace/);
|
|
132
|
+
expect(doc.members[2].reason?.message).toMatch(/known kinds: chant, design, other, repo, workspace/);
|
|
133
133
|
expect(doc.members[0].roles).toEqual([{ name: "frontend", path: "src" }]);
|
|
134
134
|
expect(doc.groups[0].reason?.code).toBe("no-matches");
|
|
135
135
|
expect(doc.summary).toEqual({ members: 5, unreadable: 3, groups: 1, matches: 0 });
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"required": ["name", "root", "file", "schema", "minReader", "pins"],
|
|
52
52
|
"properties": {
|
|
53
53
|
"name": { "type": "string", "description": "The declared name. With the revision, it identifies the workspace." },
|
|
54
|
+
"repo": { "type": ["string", "null"], "description": "Added in contract 1 by #3168. The repository the document came from: the URL of the remote origin of the git repository that holds the workspace, with any user name or password removed, or null when there is no origin or the workspace is outside git. With name, root and the revision, it says which repository's workspace a document describes, so a reader that gathers several repositories' documents, such as an org workspace's repo members, tells them apart." },
|
|
54
55
|
"root": {
|
|
55
56
|
"type": "string",
|
|
56
57
|
"description": "The workspace root relative to the git root, with / separators, \".\" for the git root itself. An absolute path outside a git repository."
|
|
@@ -158,6 +159,12 @@
|
|
|
158
159
|
"type": "array",
|
|
159
160
|
"items": { "$ref": "#/$defs/generatedFile" }
|
|
160
161
|
},
|
|
162
|
+
"repo": {
|
|
163
|
+
"description": "Added in contract 1 by #3168. For a member of kind repo, the other repository's workspace it names: url, the pinned rev and the workspace root inside that repository. Absent for every other kind. A repo member's dir is @repo/<name>, a marker that names no directory of this repository.",
|
|
164
|
+
"type": "object",
|
|
165
|
+
"required": ["url", "rev", "workspace"],
|
|
166
|
+
"properties": { "url": { "type": "string" }, "rev": { "type": "string" }, "workspace": { "type": "string" } }
|
|
167
|
+
},
|
|
161
168
|
"agents": {
|
|
162
169
|
"description": "Added in contract 1 by #3615. The names of the agent sessions the declaration binds to the member (agents[].member or agents[].members), in declaration order, read where workspace.agentsFrom says. Empty when none is. A session bound to several members is listed on each.",
|
|
163
170
|
"type": "array",
|
package/src/workspace/ls.ts
CHANGED
|
@@ -39,7 +39,8 @@ import {
|
|
|
39
39
|
} from "./declaration";
|
|
40
40
|
import type { ReasonCode } from "./reason-codes";
|
|
41
41
|
import { memberGenerated, type LsGenerated } from "./ls-generated";
|
|
42
|
-
import {
|
|
42
|
+
import { repoIdentity } from "./repo-ref";
|
|
43
|
+
import { loadKindRegistry, probeKind, REPO_KIND, type KindRegistry } from "./kinds";
|
|
43
44
|
import type { WorkspaceTree } from "./tree";
|
|
44
45
|
import { handToRootChant, locateWorkspace } from "./which-chant";
|
|
45
46
|
import { declaredSessions } from "./write-scope";
|
|
@@ -117,6 +118,8 @@ export interface LsMember {
|
|
|
117
118
|
generated: LsGenerated[];
|
|
118
119
|
/** The agent sessions bound to the member, in declaration order (#3615); empty when none is. */
|
|
119
120
|
agents: string[];
|
|
121
|
+
/** For a member of kind repo, the other repository's workspace it names (#3168). Absent for every other kind. */
|
|
122
|
+
repo?: { url: string; rev: string; workspace: string };
|
|
120
123
|
}
|
|
121
124
|
|
|
122
125
|
/**
|
|
@@ -168,6 +171,8 @@ export type LsDocument =
|
|
|
168
171
|
at: string | null;
|
|
169
172
|
workspace: {
|
|
170
173
|
name: string;
|
|
174
|
+
/** The repository the document came from (#3168): its origin URL, redacted, or null. */
|
|
175
|
+
repo: string | null;
|
|
171
176
|
/** The workspace root relative to the git root, `"."` for the git root itself. Absolute outside git. */
|
|
172
177
|
root: string;
|
|
173
178
|
file: string;
|
|
@@ -211,6 +216,8 @@ export interface LsQuery {
|
|
|
211
216
|
|
|
212
217
|
/** A member's reason code, or null when its kind can read it. */
|
|
213
218
|
export function memberReason(member: Member, tree: WorkspaceTree, kinds: KindRegistry): LsMember["reason"] {
|
|
219
|
+
// A repo member has no directory here (#3168); it is read from its own repository.
|
|
220
|
+
if (member.kind === REPO_KIND) return null;
|
|
214
221
|
if (tree.stat(member.dir === "." ? "" : member.dir) !== "dir") {
|
|
215
222
|
return { code: "dir-missing", message: `${member.dir} is not a directory${tree.label}` };
|
|
216
223
|
}
|
|
@@ -283,6 +290,7 @@ function readListing(query: LsQuery): { doc: LsDocument; declaration?: Declarati
|
|
|
283
290
|
records: unloaded(m.records),
|
|
284
291
|
generated: memberGenerated(m, tree, repoPrefix),
|
|
285
292
|
agents: sessions.agents.filter((a) => a.members.includes(m.name)).map((a) => a.name),
|
|
293
|
+
...(m.repo ? { repo: { ...m.repo } } : {}),
|
|
286
294
|
// The member's x- keys, as declared (#3595).
|
|
287
295
|
...extensionsAt(declaration, m.pointer),
|
|
288
296
|
};
|
|
@@ -311,6 +319,7 @@ function readListing(query: LsQuery): { doc: LsDocument; declaration?: Declarati
|
|
|
311
319
|
at,
|
|
312
320
|
workspace: {
|
|
313
321
|
name: declaration.name,
|
|
322
|
+
repo: repoIdentity(rootOnDisk),
|
|
314
323
|
root: located.root,
|
|
315
324
|
file: declaration.file,
|
|
316
325
|
schema: declaration.schema,
|
|
@@ -241,6 +241,8 @@ export function planMembers(verb: WorkspaceVerb, root: string, options: PlanOpti
|
|
|
241
241
|
const why =
|
|
242
242
|
entry.kind === "workspace"
|
|
243
243
|
? "a nested workspace runs its own chant workspace commands"
|
|
244
|
+
: entry.kind === "repo"
|
|
245
|
+
? "a repo member is another repository's workspace, which runs its own chant workspace commands; chant workspace graph reads it at its pinned revision"
|
|
244
246
|
: entry.kind === "design"
|
|
245
247
|
? "a design member is data: chant reads its files for record pins and builds nothing"
|
|
246
248
|
: `chant workspace ${verb} runs members of kind chant, and this one is kind ${entry.kind}`;
|
|
@@ -556,13 +558,17 @@ export async function runWorkspaceMembers(ctx: CommandContext, verb: WorkspaceVe
|
|
|
556
558
|
}
|
|
557
559
|
|
|
558
560
|
const results = await executePlan(plan, args);
|
|
559
|
-
|
|
561
|
+
// #2549: the disagreement lint, over every member's graph, when asked for.
|
|
562
|
+
const cross = verb === "lint" && args.crossRoot ? await runCrossRoot(found.dir, args) : undefined;
|
|
563
|
+
const anyFailed = results.some((r) => r.exitCode !== 0) || plan.unreadable.length > 0 || cross?.failed === true;
|
|
560
564
|
const workspace = { name: plan.workspace.name, root: plan.workspace.root };
|
|
561
565
|
|
|
562
566
|
if (verb === "lint" && args.format === "sarif") {
|
|
563
567
|
for (const r of results) if (r.stderr.trim()) process.stderr.write(r.stderr.endsWith("\n") ? r.stderr : `${r.stderr}\n`);
|
|
564
568
|
const unreadable: MemberOutput[] = plan.unreadable.map((s) => ({ id: s.name, member: s.name, dir: s.dir ?? ".", exitCode: 1, stdout: "", stderr: `${s.reason.code}: ${s.reason.message}` }));
|
|
565
|
-
|
|
569
|
+
const sarif = mergeSarif([...results, ...unreadable], plan.workspace.root) as { runs?: unknown[] };
|
|
570
|
+
if (cross) (sarif.runs ??= []).push(crossRootSarifRun(cross));
|
|
571
|
+
emitDocument(sarif, args.output);
|
|
566
572
|
console.error(summaryLine(plan, results));
|
|
567
573
|
return anyFailed ? 1 : 0;
|
|
568
574
|
}
|
|
@@ -598,6 +604,7 @@ export async function runWorkspaceMembers(ctx: CommandContext, verb: WorkspaceVe
|
|
|
598
604
|
...plan.unreadable.map((s) => ({ member: s.name, dir: s.dir, exitCode: 1, diagnostics: null, reason: s.reason })),
|
|
599
605
|
],
|
|
600
606
|
skipped: plan.skipped,
|
|
607
|
+
...(cross ? { crossRoot: crossRootJson(cross) } : {}),
|
|
601
608
|
};
|
|
602
609
|
}
|
|
603
610
|
emitDocument(doc, args.output);
|
|
@@ -608,5 +615,56 @@ export async function runWorkspaceMembers(ctx: CommandContext, verb: WorkspaceVe
|
|
|
608
615
|
// Text: each member's own output under a heading. A build without -o prints
|
|
609
616
|
// no templates, since several members' templates can't share one stdout.
|
|
610
617
|
printSections(plan, results, verb !== "build" || args.output !== undefined);
|
|
618
|
+
if (cross) printCrossRoot(cross);
|
|
611
619
|
return anyFailed ? 1 : 0;
|
|
612
620
|
}
|
|
621
|
+
|
|
622
|
+
// ── The disagreement lint (#2549) ────────────────────────────────────────────
|
|
623
|
+
|
|
624
|
+
interface CrossRootRun {
|
|
625
|
+
result?: import("./cross-root-lint").CrossRootLintResult;
|
|
626
|
+
/** Why the members' graphs could not be read. */
|
|
627
|
+
error?: string;
|
|
628
|
+
/** An error finding, or a graph that could not be read. */
|
|
629
|
+
failed: boolean;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
async function runCrossRoot(root: string, args: ParsedArgs): Promise<CrossRootRun> {
|
|
633
|
+
const { workspaceGraph } = await import("./graph-cli");
|
|
634
|
+
const { crossRootLint } = await import("./cross-root-lint");
|
|
635
|
+
const { doc, failed } = await workspaceGraph({ cwd: root, ...(args.members?.length ? { members: args.members } : {}), onStderr: (t) => process.stderr.write(t) });
|
|
636
|
+
if ("error" in doc) return { error: `${doc.error.code}: ${doc.error.message}`, failed: true };
|
|
637
|
+
const result = await crossRootLint(doc, args.env ? { env: args.env } : {});
|
|
638
|
+
return { result, failed: failed || result.findings.some((f) => f.severity === "error") };
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
function crossRootJson(cross: CrossRootRun): unknown {
|
|
642
|
+
return cross.result ? { findings: cross.result.findings, checks: cross.result.checks, unloaded: cross.result.unloaded } : { error: cross.error };
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
function crossRootSarifRun(cross: CrossRootRun): unknown {
|
|
646
|
+
const findings = cross.result?.findings ?? [];
|
|
647
|
+
return {
|
|
648
|
+
tool: { driver: { name: "chant", rules: [...new Set(findings.map((f) => f.checkId))].sort().map((id) => ({ id })) } },
|
|
649
|
+
automationDetails: { id: "cross-root/" },
|
|
650
|
+
properties: { crossRoot: true, checks: cross.result?.checks ?? [], unloaded: cross.result?.unloaded ?? [] },
|
|
651
|
+
results: findings.map((f) => ({
|
|
652
|
+
ruleId: f.checkId,
|
|
653
|
+
level: f.severity === "error" ? "error" : f.severity === "warning" ? "warning" : "note",
|
|
654
|
+
message: { text: f.message },
|
|
655
|
+
...(f.root ? { properties: { member: f.root } } : {}),
|
|
656
|
+
})),
|
|
657
|
+
...(cross.error ? { invocations: [{ executionSuccessful: false, toolExecutionNotifications: [{ message: { text: cross.error } }] }] } : {}),
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function printCrossRoot(cross: CrossRootRun): void {
|
|
662
|
+
if (!cross.result) {
|
|
663
|
+
console.log(`── cross-root (the members' graphs could not be read: ${cross.error})`);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
const { findings, checks, unloaded } = cross.result;
|
|
667
|
+
console.log(`── cross-root (${checks.join(", ")}; ${findings.length} finding${findings.length === 1 ? "" : "s"})`);
|
|
668
|
+
for (const f of findings) console.log(` ${f.severity.padEnd(7)} ${f.checkId}${f.root ? ` [${f.root}]` : ""} ${f.message}`);
|
|
669
|
+
for (const u of unloaded) console.log(` (lexicon ${u.lexicon}: its cross-root checks could not be loaded: ${u.reason})`);
|
|
670
|
+
}
|