@intentius/chant 0.124.12 → 0.124.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/chant +11 -0
- package/dist/agents/checks.js +326 -0
- package/dist/agents/discover.js +885 -0
- package/dist/agents/importer.js +17 -0
- package/dist/agents/index.js +12 -0
- package/dist/agents/types.js +19 -0
- package/dist/apply.js +151 -0
- package/dist/attrref.js +70 -0
- package/dist/audit/catalog.js +350 -0
- package/dist/audit/core.js +252 -0
- package/dist/audit/discover.js +633 -0
- package/dist/audit/fetch.js +666 -0
- package/dist/audit/lineage.js +91 -0
- package/dist/audit/nginx.js +366 -0
- package/dist/audit/prior-art.js +132 -0
- package/dist/audit/proof.js +321 -0
- package/dist/audit/report-html.js +194 -0
- package/dist/audit/report-model.js +198 -0
- package/dist/audit/report.js +102 -0
- package/dist/audit/rules-doc.js +144 -0
- package/dist/audit/secrets.js +405 -0
- package/dist/audit/terraform-state.js +140 -0
- package/dist/audit/wrangler.js +262 -0
- package/dist/behaviour-delta.js +401 -0
- package/dist/behaviour-engine.js +357 -0
- package/dist/behaviour-graph.js +83 -0
- package/dist/behaviour-http.js +188 -0
- package/dist/behaviour-kinds.js +172 -0
- package/dist/behaviour-overlay.js +50 -0
- package/dist/behaviour-predict.js +188 -0
- package/dist/behaviour-request.js +194 -0
- package/dist/behaviour.js +1325 -0
- package/dist/build-params.js +108 -0
- package/dist/build.js +668 -0
- package/dist/builder.js +44 -0
- package/dist/cdk/advise.js +30 -0
- package/dist/cdk/assembly.js +122 -0
- package/dist/cdk/graph.js +444 -0
- package/dist/cdk/tier-map.js +64 -0
- package/dist/cdk/types.js +24 -0
- package/dist/change-set.js +312 -0
- package/dist/child-project.js +21 -0
- package/dist/claimed-fields.js +135 -0
- package/dist/cli/build-options.js +70 -0
- package/dist/cli/build-params-cli.js +139 -0
- package/dist/cli/command-group.js +123 -0
- package/dist/cli/commands/audit-agents.js +326 -0
- package/dist/cli/commands/audit.js +571 -0
- package/dist/cli/commands/build.js +920 -0
- package/dist/cli/commands/carve-apply.js +153 -0
- package/dist/cli/commands/carve-bridge.js +201 -0
- package/dist/cli/commands/carve-emit.js +332 -0
- package/dist/cli/commands/carve-status.js +119 -0
- package/dist/cli/commands/carve.js +204 -0
- package/dist/cli/commands/check-lexicon-docs.js +79 -0
- package/dist/cli/commands/check-lexicon-examples.js +177 -0
- package/dist/cli/commands/check-lexicon-intrinsics.js +291 -0
- package/dist/cli/commands/check-lexicon-mcp.js +82 -0
- package/dist/cli/commands/check-lexicon-plugin.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon-plugin.js +104 -0
- package/dist/cli/commands/check-lexicon.js +766 -0
- package/dist/cli/commands/describe.js +85 -0
- package/dist/cli/commands/diff.js +175 -0
- package/dist/cli/commands/doctor.js +350 -0
- package/dist/cli/commands/import-agents.js +155 -0
- package/dist/cli/commands/import.js +670 -0
- package/dist/cli/commands/init-lexicon/templates/codegen.js +194 -0
- package/dist/cli/commands/init-lexicon/templates/docs.js +100 -0
- package/dist/cli/commands/init-lexicon/templates/examples.js +29 -0
- package/dist/cli/commands/init-lexicon/templates/lint.js +34 -0
- package/dist/cli/commands/init-lexicon/templates/lsp.js +37 -0
- package/dist/cli/commands/init-lexicon/templates/plugin.js +108 -0
- package/dist/cli/commands/init-lexicon/templates/project.js +240 -0
- package/dist/cli/commands/init-lexicon/templates/spec.js +56 -0
- package/dist/cli/commands/init-lexicon/templates/tests.js +66 -0
- package/dist/cli/commands/init-lexicon.js +172 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/lexicon-rolling-upgrade.js +145 -0
- package/dist/cli/commands/lexicon-surface-diff.js +145 -0
- package/dist/cli/commands/licenses.js +125 -0
- package/dist/cli/commands/lint.d.ts.map +1 -1
- package/dist/cli/commands/lint.js +948 -0
- package/dist/cli/commands/list.js +63 -0
- package/dist/cli/commands/migrate.d.ts.map +1 -1
- package/dist/cli/commands/migrate.js +423 -0
- package/dist/cli/commands/onboard.js +403 -0
- package/dist/cli/commands/pinned-upgrade.js +191 -0
- package/dist/cli/commands/update.js +194 -0
- package/dist/cli/commands/vendor.js +217 -0
- package/dist/cli/conflict-check.js +104 -0
- package/dist/cli/debug.js +8 -0
- package/dist/cli/format.js +104 -0
- package/dist/cli/handlers/build.js +267 -0
- package/dist/cli/handlers/carve-apply.js +30 -0
- package/dist/cli/handlers/carve-bridge.js +28 -0
- package/dist/cli/handlers/carve-emit.js +50 -0
- package/dist/cli/handlers/carve-status.js +26 -0
- package/dist/cli/handlers/carve.js +40 -0
- package/dist/cli/handlers/change-set.js +46 -0
- package/dist/cli/handlers/components.js +730 -0
- package/dist/cli/handlers/dev.js +113 -0
- package/dist/cli/handlers/emulator.js +233 -0
- package/dist/cli/handlers/explain.js +54 -0
- package/dist/cli/handlers/fan-out.js +422 -0
- package/dist/cli/handlers/gate-resume.js +275 -0
- package/dist/cli/handlers/generate.js +84 -0
- package/dist/cli/handlers/graph.js +969 -0
- package/dist/cli/handlers/init.js +102 -0
- package/dist/cli/handlers/lifecycle.js +1727 -0
- package/dist/cli/handlers/lint.js +62 -0
- package/dist/cli/handlers/migrate.js +48 -0
- package/dist/cli/handlers/misc.js +391 -0
- package/dist/cli/handlers/operator.js +1162 -0
- package/dist/cli/handlers/override-approve.js +102 -0
- package/dist/cli/handlers/pr.js +503 -0
- package/dist/cli/handlers/promote.js +342 -0
- package/dist/cli/handlers/run-generate.js +206 -0
- package/dist/cli/handlers/run-wave.js +66 -0
- package/dist/cli/handlers/run.js +1191 -0
- package/dist/cli/handlers/scenario.js +325 -0
- package/dist/cli/handlers/search.js +924 -0
- package/dist/cli/handlers/serve.js +32 -0
- package/dist/cli/handlers/vendor.js +154 -0
- package/dist/cli/index.js +3 -0
- package/dist/cli/is-entry-point.js +23 -0
- package/dist/cli/lsp/capabilities.js +28 -0
- package/dist/cli/lsp/diagnostics.js +34 -0
- package/dist/cli/lsp/server.js +329 -0
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +2540 -0
- package/dist/cli/mcp/lifecycle-tools.js +80 -0
- package/dist/cli/mcp/op-tools.js +306 -0
- package/dist/cli/mcp/resource-handlers.js +258 -0
- package/dist/cli/mcp/resources/context.js +85 -0
- package/dist/cli/mcp/server.js +353 -0
- package/dist/cli/mcp/tools/build.js +111 -0
- package/dist/cli/mcp/tools/composites.js +95 -0
- package/dist/cli/mcp/tools/explain.js +166 -0
- package/dist/cli/mcp/tools/import.js +49 -0
- package/dist/cli/mcp/tools/lint.js +41 -0
- package/dist/cli/mcp/tools/scaffold.js +111 -0
- package/dist/cli/mcp/tools/search.js +112 -0
- package/dist/cli/mcp/types.js +1 -0
- package/dist/cli/mcp/workspace-plugins.js +91 -0
- package/dist/cli/mcp/workspace-tools.d.ts +1 -1
- package/dist/cli/mcp/workspace-tools.js +564 -0
- package/dist/cli/mcp-config.js +70 -0
- package/dist/cli/plugins.js +313 -0
- package/dist/cli/registry.js +23 -0
- package/dist/cli/reporters/stylish.js +329 -0
- package/dist/cli/version.js +15 -0
- package/dist/cli/watch.js +79 -0
- package/dist/codegen/bound-property-types.js +82 -0
- package/dist/codegen/coverage.js +119 -0
- package/dist/codegen/docs-file-markers.js +60 -0
- package/dist/codegen/docs-pages.js +115 -0
- package/dist/codegen/docs-rule-scanning.js +164 -0
- package/dist/codegen/docs-rules.js +76 -0
- package/dist/codegen/docs-sections.js +117 -0
- package/dist/codegen/docs-sidebar.js +65 -0
- package/dist/codegen/docs-types.js +4 -0
- package/dist/codegen/docs.js +356 -0
- package/dist/codegen/fetch.js +340 -0
- package/dist/codegen/generate-post-synth-barrel.js +63 -0
- package/dist/codegen/generate-registry.js +71 -0
- package/dist/codegen/generate-runtime-index.js +56 -0
- package/dist/codegen/generate-typescript.js +119 -0
- package/dist/codegen/generate.js +115 -0
- package/dist/codegen/json-patch.js +141 -0
- package/dist/codegen/json-schema-to-ts.js +344 -0
- package/dist/codegen/json-schema.js +246 -0
- package/dist/codegen/lexicon-regen.js +412 -0
- package/dist/codegen/naming.js +217 -0
- package/dist/codegen/okf-lexicon.js +245 -0
- package/dist/codegen/package.js +150 -0
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.js +494 -0
- package/dist/codegen/registry.js +60 -0
- package/dist/codegen/rehype-base-url.mjs +68 -0
- package/dist/codegen/rolling-upgrade.js +217 -0
- package/dist/codegen/surface-snapshot.js +537 -0
- package/dist/codegen/testdata/postgres-tags.json +242 -0
- package/dist/codegen/topo-sort.js +36 -0
- package/dist/codegen/typecheck.js +115 -0
- package/dist/codegen/validate.js +200 -0
- package/dist/codegen/version-bump.js +35 -0
- package/dist/components/auto-release.js +143 -0
- package/dist/components/builders.js +47 -0
- package/dist/components/capability-plugin-loader.js +175 -0
- package/dist/components/capability-plugin-schema.js +46 -0
- package/dist/components/capability-plugin.js +99 -0
- package/dist/components/capability.js +60 -0
- package/dist/components/changed-files.js +72 -0
- package/dist/components/cli-support.js +427 -0
- package/dist/components/component.js +120 -0
- package/dist/components/component.schema.json +271 -0
- package/dist/components/config-defaults.js +130 -0
- package/dist/components/deploy-units.js +60 -0
- package/dist/components/discover.d.ts.map +1 -1
- package/dist/components/discover.js +189 -0
- package/dist/components/driver-output.js +86 -0
- package/dist/components/driver.js +728 -0
- package/dist/components/fan-out-output.js +165 -0
- package/dist/components/fan-out-record.js +94 -0
- package/dist/components/fan-out-run.js +373 -0
- package/dist/components/fan-out-support.js +60 -0
- package/dist/components/fan-out.js +273 -0
- package/dist/components/gate-plan.js +41 -0
- package/dist/components/gated-wave-pipeline.js +46 -0
- package/dist/components/index.js +24 -0
- package/dist/components/layers.js +28 -0
- package/dist/components/manifest-persistence.js +108 -0
- package/dist/components/pilots/alb-ecs.pilot.js +59 -0
- package/dist/components/pilots/dynamodb.pilot.js +51 -0
- package/dist/components/pilots/jar-emr.pilot.js +65 -0
- package/dist/components/pilots/lambda.pilot.js +52 -0
- package/dist/components/pilots/neo4j-fanout.pilot.js +68 -0
- package/dist/components/pilots/project.js +12 -0
- package/dist/components/pr-pipeline.js +134 -0
- package/dist/components/pr-run.js +363 -0
- package/dist/components/presets/ecs-fargate.js +72 -0
- package/dist/components/presets/index.js +28 -0
- package/dist/components/presets/lambda.js +34 -0
- package/dist/components/presets/single-host-compose.js +41 -0
- package/dist/components/promote.js +549 -0
- package/dist/components/registry.js +34 -0
- package/dist/components/run-progress.js +33 -0
- package/dist/components/sandbox/driver.d.ts.map +1 -1
- package/dist/components/sandbox/driver.js +93 -0
- package/dist/components/sandbox/run.js +115 -0
- package/dist/components/starter-plugin.js +104 -0
- package/dist/components/verbs/__tests__/mock-cloud-executor.js +68 -0
- package/dist/components/verbs/__tests__/mock-process-runner.js +45 -0
- package/dist/components/verbs/__tests__/mock-sbom-generator.js +56 -0
- package/dist/components/verbs/bom-writer.js +287 -0
- package/dist/components/verbs/build-archive.js +188 -0
- package/dist/components/verbs/build.js +142 -0
- package/dist/components/verbs/cloud-executor.js +110 -0
- package/dist/components/verbs/component-bom.js +125 -0
- package/dist/components/verbs/ensure-secret.js +50 -0
- package/dist/components/verbs/index.js +61 -0
- package/dist/components/verbs/license-policy.js +75 -0
- package/dist/components/verbs/lockfile-sbom-generator.js +191 -0
- package/dist/components/verbs/process-runner.js +78 -0
- package/dist/components/verbs/r2-sync.js +93 -0
- package/dist/components/verbs/reproducibility.js +62 -0
- package/dist/components/verbs/run-agent.js +577 -0
- package/dist/components/verbs/sbom-generator.js +119 -0
- package/dist/components/verbs/sbom.js +97 -0
- package/dist/components/verbs/shell.js +32 -0
- package/dist/components/verbs/sign.js +221 -0
- package/dist/components/verbs/stub.js +28 -0
- package/dist/components/verbs/tool-sbom-generator.js +154 -0
- package/dist/components/verbs/verify.js +112 -0
- package/dist/components/verbs/vex.js +131 -0
- package/dist/components/verbs/vuln-gate.js +152 -0
- package/dist/components/verbs/vuln-scan.js +288 -0
- package/dist/components/verbs/wait-verify.js +106 -0
- package/dist/components/verbs/wrangler.js +179 -0
- package/dist/components/wave-plan.js +102 -0
- package/dist/composite.js +305 -0
- package/dist/config-import.d.ts.map +1 -1
- package/dist/config-import.js +22 -0
- package/dist/config-sandbox.js +122 -0
- package/dist/config-static.js +206 -0
- package/dist/config.js +605 -0
- package/dist/content-digest.js +23 -0
- package/dist/declarable.js +114 -0
- package/dist/deep-observation.js +437 -0
- package/dist/detectLexicon.js +54 -0
- package/dist/discovery/cache.js +70 -0
- package/dist/discovery/collect.js +208 -0
- package/dist/discovery/cycles.js +95 -0
- package/dist/discovery/entity-wire-codec.js +391 -0
- package/dist/discovery/entity-wire.js +42 -0
- package/dist/discovery/files.js +121 -0
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/fold-import.js +4178 -0
- package/dist/discovery/fold-rank.js +292 -0
- package/dist/discovery/graph.js +115 -0
- package/dist/discovery/import.d.ts.map +1 -1
- package/dist/discovery/import.js +65 -0
- package/dist/discovery/index.js +333 -0
- package/dist/discovery/param-deps.js +487 -0
- package/dist/discovery/resolve.js +39 -0
- package/dist/discovery/sandbox/bundle.js +214 -0
- package/dist/discovery/sandbox/child-errors.js +26 -0
- package/dist/discovery/sandbox/config-run.js +100 -0
- package/dist/discovery/sandbox/config-wire.js +183 -0
- package/dist/discovery/sandbox/driver.d.ts.map +1 -1
- package/dist/discovery/sandbox/driver.js +333 -0
- package/dist/discovery/sandbox/fork.js +229 -0
- package/dist/discovery/sandbox/policy-run.js +142 -0
- package/dist/discovery/sandbox/policy-wire.js +152 -0
- package/dist/discovery/sandbox/run.js +77 -0
- package/dist/discovery/specifier-resolve.js +320 -0
- package/dist/discovery/walk.js +284 -0
- package/dist/effect-receipt.js +340 -0
- package/dist/env.js +55 -0
- package/dist/errors.js +62 -0
- package/dist/fold/fold.js +1434 -0
- package/dist/fold/foldable-helpers.js +229 -0
- package/dist/fold/subset.js +696 -0
- package/dist/fold-provenance.js +414 -0
- package/dist/gate-decision.d.ts +36 -4
- package/dist/gate-decision.d.ts.map +1 -1
- package/dist/gate-decision.js +260 -0
- package/dist/gate-resume-run.js +154 -0
- package/dist/gated-waves.js +165 -0
- package/dist/governance.js +43 -0
- package/dist/graph-declared.js +45 -0
- package/dist/graph-detail.js +207 -0
- package/dist/graph-dot.js +54 -0
- package/dist/graph-effective.js +107 -0
- package/dist/graph-ir.js +623 -0
- package/dist/graph-layout.js +184 -0
- package/dist/graph-lens.js +105 -0
- package/dist/graph-mermaid.js +83 -0
- package/dist/graph-ops.js +39 -0
- package/dist/graph-refs.js +156 -0
- package/dist/held-elsewhere.js +87 -0
- package/dist/identity.js +251 -0
- package/dist/import/base-parser.js +34 -0
- package/dist/import/embedded.js +255 -0
- package/dist/import/generator.js +1 -0
- package/dist/import/ir-utils.js +85 -0
- package/dist/import/parser-options.js +45 -0
- package/dist/import/parser.js +1 -0
- package/dist/index.js +118 -0
- package/dist/intrinsic-interpolation.js +73 -0
- package/dist/intrinsic.js +31 -0
- package/dist/join-key.js +35 -0
- package/dist/kubectl-context.js +150 -0
- package/dist/lexicon-config.js +58 -0
- package/dist/lexicon-integrity.js +47 -0
- package/dist/lexicon-manifest.js +70 -0
- package/dist/lexicon-module.d.ts.map +1 -1
- package/dist/lexicon-module.js +241 -0
- package/dist/lexicon-output.js +218 -0
- package/dist/lexicon-plugin-helpers.js +104 -0
- package/dist/lexicon-schema.js +136 -0
- package/dist/lexicon.js +130 -0
- package/dist/lifecycle/affected.js +224 -0
- package/dist/lifecycle/assert-live.js +110 -0
- package/dist/lifecycle/build-ledger-store.js +160 -0
- package/dist/lifecycle/build-ledger.js +155 -0
- package/dist/lifecycle/change-set.js +356 -0
- package/dist/lifecycle/converge-ledger.js +161 -0
- package/dist/lifecycle/deep-diff.js +233 -0
- package/dist/lifecycle/deep-observe.js +147 -0
- package/dist/lifecycle/digest.js +143 -0
- package/dist/lifecycle/disruption.js +135 -0
- package/dist/lifecycle/gate-applied.js +113 -0
- package/dist/lifecycle/gate-audit.js +341 -0
- package/dist/lifecycle/gate-ledger-select.js +89 -0
- package/dist/lifecycle/gate-ledger.d.ts +8 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.js +193 -0
- package/dist/lifecycle/gate-origin.js +117 -0
- package/dist/lifecycle/gate-pending.js +58 -0
- package/dist/lifecycle/git.js +1182 -0
- package/dist/lifecycle/identity.js +58 -0
- package/dist/lifecycle/index.js +26 -0
- package/dist/lifecycle/lease.js +283 -0
- package/dist/lifecycle/ledger-port.js +1 -0
- package/dist/lifecycle/legacy-digest.js +91 -0
- package/dist/lifecycle/live-diff.js +274 -0
- package/dist/lifecycle/local-note.js +15 -0
- package/dist/lifecycle/member-ledger.js +122 -0
- package/dist/lifecycle/observation-baseline.js +155 -0
- package/dist/lifecycle/observe.js +375 -0
- package/dist/lifecycle/oras-referrer-lookup.js +82 -0
- package/dist/lifecycle/override-ledger.js +54 -0
- package/dist/lifecycle/plan-digest.js +110 -0
- package/dist/lifecycle/plan-ledger.js +129 -0
- package/dist/lifecycle/receipt-plan.js +192 -0
- package/dist/lifecycle/release-ledger.js +155 -0
- package/dist/lifecycle/release-read.js +64 -0
- package/dist/lifecycle/replay.js +193 -0
- package/dist/lifecycle/rollback.js +102 -0
- package/dist/lifecycle/run-ledger.js +183 -0
- package/dist/lifecycle/scenario-eval.js +204 -0
- package/dist/lifecycle/scenario.js +214 -0
- package/dist/lifecycle/snapshot.js +239 -0
- package/dist/lifecycle/status.js +447 -0
- package/dist/lifecycle/symptoms.js +117 -0
- package/dist/lifecycle/teardown.js +255 -0
- package/dist/lifecycle/types.js +1 -0
- package/dist/lifecycle/unobserved-gate.js +33 -0
- package/dist/lifecycle/wave-plans.js +68 -0
- package/dist/lifecycle/work-item-id.js +36 -0
- package/dist/lifecycle/work-lease.js +393 -0
- package/dist/lint/component-checks.js +87 -0
- package/dist/lint/config.js +483 -0
- package/dist/lint/declarative.js +122 -0
- package/dist/lint/discover.d.ts.map +1 -1
- package/dist/lint/discover.js +138 -0
- package/dist/lint/engine.js +246 -0
- package/dist/lint/knowledge-checks.js +64 -0
- package/dist/lint/named-checks.js +22 -0
- package/dist/lint/output-checks.js +87 -0
- package/dist/lint/output-docs.js +163 -0
- package/dist/lint/parser.js +33 -0
- package/dist/lint/pipeline-change-gate.js +70 -0
- package/dist/lint/policy-import.d.ts +1 -1
- package/dist/lint/policy-import.d.ts.map +1 -1
- package/dist/lint/policy-import.js +62 -0
- package/dist/lint/policy-sandbox.js +86 -0
- package/dist/lint/policy.js +122 -0
- package/dist/lint/post-synth.js +87 -0
- package/dist/lint/presets/relaxed.json +26 -0
- package/dist/lint/presets/strict.json +24 -24
- package/dist/lint/receipt-checks.js +83 -0
- package/dist/lint/rule-loader.d.ts.map +1 -1
- package/dist/lint/rule-loader.js +89 -0
- package/dist/lint/rule-registry.js +86 -0
- package/dist/lint/rule.js +1 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-a.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp000-discovery-error/broken-b.component.js +7 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/fail/orphan-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/emr-job.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp001/pass/jar-lib.component.js +9 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/fail/search-service.component.js +25 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/jar-lib.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp002/pass/search-service.component.js +21 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/fail/migrator.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/agent-turn.component.js +24 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/migrator.component.js +17 -0
- package/dist/lint/rules/__fixtures__/comp/comp003/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/fail/neo4j-cluster.component.js +18 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/neo4j-cluster.component.js +20 -0
- package/dist/lint/rules/__fixtures__/comp/comp004/pass/orders-table.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/fail/search-service.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp005/pass/search-service.component.js +16 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/fail/legacy-tool.component.js +8 -0
- package/dist/lint/rules/__fixtures__/comp/comp006/pass/legacy-tool.component.js +12 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/inventory-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/fail/orders-table.component.js +11 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/orders-table.component.js +10 -0
- package/dist/lint/rules/__fixtures__/comp/comp007/pass/search-service.component.js +16 -0
- package/dist/lint/rules/comp/comp001-publishes-never-applies.js +69 -0
- package/dist/lint/rules/comp/comp002-dangling-wiring-ref.js +84 -0
- package/dist/lint/rules/comp/comp003-mutating-no-rollback.js +103 -0
- package/dist/lint/rules/comp/comp004-gate-needs-durable-runtime.js +70 -0
- package/dist/lint/rules/comp/comp005-capability-kind-is-noun.js +109 -0
- package/dist/lint/rules/comp/comp006-shell-needs-reason.js +49 -0
- package/dist/lint/rules/comp/comp007-composition-sprawl.js +64 -0
- package/dist/lint/rules/comp/index.js +33 -0
- package/dist/lint/rules/comp/support.js +129 -0
- package/dist/lint/rules/composite-scope.js +51 -0
- package/dist/lint/rules/cor017-composite-name-match.js +93 -0
- package/dist/lint/rules/cor018-composite-prefer-lexicon-type.js +136 -0
- package/dist/lint/rules/cor021-env-literal-name.js +100 -0
- package/dist/lint/rules/cor022-receipt-leaf.js +118 -0
- package/dist/lint/rules/cor024-receipt-secret-pointer.js +199 -0
- package/dist/lint/rules/declarable-naming-convention.js +62 -0
- package/dist/lint/rules/evl001-non-literal-expression.js +66 -0
- package/dist/lint/rules/evl002-control-flow-resource.js +69 -0
- package/dist/lint/rules/evl003-dynamic-property-access.js +44 -0
- package/dist/lint/rules/evl004-spread-non-const.js +94 -0
- package/dist/lint/rules/evl005-resource-block-body.js +41 -0
- package/dist/lint/rules/evl007-invalid-siblings.js +105 -0
- package/dist/lint/rules/evl009-composite-no-constant.js +158 -0
- package/dist/lint/rules/evl010-composite-no-transform.js +59 -0
- package/dist/lint/rules/evl011-symbolic-in-template.js +106 -0
- package/dist/lint/rules/export-required.js +115 -0
- package/dist/lint/rules/file-declarable-limit.js +88 -0
- package/dist/lint/rules/flat-declarations.js +62 -0
- package/dist/lint/rules/index.js +90 -0
- package/dist/lint/rules/no-cyclic-declarable-ref.js +138 -0
- package/dist/lint/rules/no-redundant-type-import.js +76 -0
- package/dist/lint/rules/no-redundant-value-cast.js +41 -0
- package/dist/lint/rules/no-string-ref.js +59 -0
- package/dist/lint/rules/no-unused-declarable-import.js +75 -0
- package/dist/lint/rules/no-unused-declarable.js +142 -0
- package/dist/lint/rules/op/index.js +28 -0
- package/dist/lint/rules/op/ops012-activity-contract.js +54 -0
- package/dist/lint/rules/op/ops013-step-output-ref.js +88 -0
- package/dist/lint/rules/op/ops014-converge-rule-refusals.js +114 -0
- package/dist/lint/rules/op/ops015-gate-approval.js +45 -0
- package/dist/lint/rules/op/support.js +11 -0
- package/dist/lint/rules/op/sys010-key-over-plain-http.js +100 -0
- package/dist/lint/rules/property-kind.js +56 -0
- package/dist/lint/rules/single-concern-file.js +71 -0
- package/dist/lint/rules/sys001-no-literal-key.js +60 -0
- package/dist/lint/selectors.js +168 -0
- package/dist/lint/suppressions.js +129 -0
- package/dist/lint/typescript.js +17 -0
- package/dist/live-endpoint.js +113 -0
- package/dist/live-read-session.js +76 -0
- package/dist/lsp/lexicon-providers.js +163 -0
- package/dist/lsp/types.js +5 -0
- package/dist/managed-fields.js +293 -0
- package/dist/mcp/types.js +4 -0
- package/dist/notify-verify.js +0 -1
- package/dist/notify.js +0 -1
- package/dist/notify.schema.json +72 -0
- package/dist/observation.js +266 -0
- package/dist/okf-read.js +134 -0
- package/dist/okf.js +275 -0
- package/dist/op/__fixtures__/decide-stub-backend.js +125 -0
- package/dist/op/activities/activity-contracts.js +313 -0
- package/dist/op/activities/apply.js +582 -0
- package/dist/op/activities/build.js +18 -0
- package/dist/op/activities/change-coverage.js +40 -0
- package/dist/op/activities/change-set.js +64 -0
- package/dist/op/activities/converge.js +492 -0
- package/dist/op/activities/decide.js +211 -0
- package/dist/op/activities/env-teardown.js +110 -0
- package/dist/op/activities/factory.js +591 -0
- package/dist/op/activities/forge-pull-request.js +82 -0
- package/dist/op/activities/gh-host.js +78 -0
- package/dist/op/activities/guard-validate.js +165 -0
- package/dist/op/activities/http-check.js +40 -0
- package/dist/op/activities/index.js +59 -0
- package/dist/op/activities/lexicon-upgrade.js +629 -0
- package/dist/op/activities/lifecycle.js +109 -0
- package/dist/op/activities/pipeline-audit.js +147 -0
- package/dist/op/activities/policy.js +26 -0
- package/dist/op/activities/predict-behaviour.js +341 -0
- package/dist/op/activities/propose-upgrade.js +165 -0
- package/dist/op/activities/reconcile.js +997 -0
- package/dist/op/activities/shell.js +118 -0
- package/dist/op/activities/source-release.js +97 -0
- package/dist/op/activities/source-rollback.js +165 -0
- package/dist/op/activities/teardown.js +17 -0
- package/dist/op/activities/util.js +6 -0
- package/dist/op/activities/wait.js +51 -0
- package/dist/op/activities/work-evidence.js +35 -0
- package/dist/op/activities/workflow-audit.js +133 -0
- package/dist/op/activity-contract-registry.js +106 -0
- package/dist/op/activity-contract.js +232 -0
- package/dist/op/activity-failure.js +31 -0
- package/dist/op/activity-profiles.js +129 -0
- package/dist/op/activity-registry.js +105 -0
- package/dist/op/activity-runtime.js +28 -0
- package/dist/op/builders.js +801 -0
- package/dist/op/change-signal.js +118 -0
- package/dist/op/composites/apply-op.js +151 -0
- package/dist/op/composites/behaviour-op.js +65 -0
- package/dist/op/composites/converge-op.js +141 -0
- package/dist/op/composites/index.js +19 -0
- package/dist/op/composites/lexicon-upgrade-op.js +107 -0
- package/dist/op/composites/pipeline-audit-op.js +50 -0
- package/dist/op/composites/reconcile-op.js +84 -0
- package/dist/op/composites/watch-op.js +69 -0
- package/dist/op/composites/workflow-audit-op.js +57 -0
- package/dist/op/converge-rule.js +205 -0
- package/dist/op/cron.js +146 -0
- package/dist/op/decide-backend.js +181 -0
- package/dist/op/decide-config.js +68 -0
- package/dist/op/decide-read-inputs.js +141 -0
- package/dist/op/discover.d.ts.map +1 -1
- package/dist/op/discover.js +213 -0
- package/dist/op/duration.js +21 -0
- package/dist/op/emulator-freshness.js +80 -0
- package/dist/op/emulator-lifecycle.js +269 -0
- package/dist/op/factory.js +83 -0
- package/dist/op/gate-approval.js +172 -0
- package/dist/op/gate-name.js +86 -0
- package/dist/op/gate-plan-context.js +167 -0
- package/dist/op/gate-point-run.js +67 -0
- package/dist/op/gate-point.js +111 -0
- package/dist/op/gate-resume-plan.js +155 -0
- package/dist/op/gate-resume.js +31 -0
- package/dist/op/gate-review.js +290 -0
- package/dist/op/gate-run-locator.js +85 -0
- package/dist/op/gate-summary.js +100 -0
- package/dist/op/gate-wait.js +56 -0
- package/dist/op/gate.js +449 -0
- package/dist/op/generate-pipeline.js +124 -0
- package/dist/op/index.js +51 -0
- package/dist/op/lifecycle-receipt-store.js +45 -0
- package/dist/op/local-executor.js +1164 -0
- package/dist/op/local-output.js +140 -0
- package/dist/op/op-ir.js +317 -0
- package/dist/op/op-verb-class.js +131 -0
- package/dist/op/op-waves-notify.js +136 -0
- package/dist/op/op-waves-run.d.ts +1 -1
- package/dist/op/op-waves-run.d.ts.map +1 -1
- package/dist/op/op-waves-run.js +1657 -0
- package/dist/op/op-waves.js +409 -0
- package/dist/op/operator.js +743 -0
- package/dist/op/receipt-store.js +94 -0
- package/dist/op/resource.js +23 -0
- package/dist/op/run-context.js +28 -0
- package/dist/op/run-live.js +256 -0
- package/dist/op/runtime.js +21 -0
- package/dist/op/runtimes/local.js +195 -0
- package/dist/op/source-archive.js +131 -0
- package/dist/op/step-output-ref.js +397 -0
- package/dist/op/steward-beside.js +169 -0
- package/dist/op/steward-points.js +138 -0
- package/dist/op/steward-turn.js +59 -0
- package/dist/op/steward.js +317 -0
- package/dist/op/types.js +25 -0
- package/dist/op/work-lease-decl.js +81 -0
- package/dist/op/work-lease-run.js +393 -0
- package/dist/override-gate.js +284 -0
- package/dist/owner-chain.js +74 -0
- package/dist/ownership.js +92 -0
- package/dist/params.js +61 -0
- package/dist/plan-summary.js +711 -0
- package/dist/point-decision.js +211 -0
- package/dist/pr-forge.js +810 -0
- package/dist/pr-loop.js +203 -0
- package/dist/project-codegen.js +191 -0
- package/dist/project-root.js +74 -0
- package/dist/project-validation.js +50 -0
- package/dist/provenance.js +157 -0
- package/dist/pseudo-parameter.js +40 -0
- package/dist/reconcile.js +450 -0
- package/dist/resource-attributes.js +33 -0
- package/dist/runtime-adapter.js +77 -0
- package/dist/runtime.js +66 -0
- package/dist/secret-materialization.js +153 -0
- package/dist/secret-provenance.js +250 -0
- package/dist/serializer-walker.js +112 -0
- package/dist/serializer.js +1 -0
- package/dist/sort.js +45 -0
- package/dist/stack-output.js +115 -0
- package/dist/telemetry-attribution.js +149 -0
- package/dist/terraform/__fixtures__/build-graph.js +63 -0
- package/dist/terraform/adopt-state.js +40 -0
- package/dist/terraform/aws-resources.js +384 -0
- package/dist/terraform/bridge.js +204 -0
- package/dist/terraform/carve-provider.js +155 -0
- package/dist/terraform/carve.js +138 -0
- package/dist/terraform/data-source-shape.js +57 -0
- package/dist/terraform/emit-source.js +36 -0
- package/dist/terraform/excise.js +123 -0
- package/dist/terraform/graduate.js +128 -0
- package/dist/terraform/graph.js +435 -0
- package/dist/terraform/hcl2json.js +60 -0
- package/dist/terraform/manifest.js +149 -0
- package/dist/terraform/parse.js +81 -0
- package/dist/terraform/providers/aws.js +146 -0
- package/dist/terraform/providers/gcp.js +294 -0
- package/dist/terraform/providers/index.js +17 -0
- package/dist/terraform/providers/kubernetes.js +253 -0
- package/dist/terraform/score.js +151 -0
- package/dist/terraform/state.js +67 -0
- package/dist/terraform/tier-map.js +74 -0
- package/dist/terraform/types.js +13 -0
- package/dist/terraform/unified-diff.js +132 -0
- package/dist/testing.js +295 -0
- package/dist/toml-emit.js +153 -0
- package/dist/toml-parse.js +355 -0
- package/dist/toml-utils.js +60 -0
- package/dist/toml.js +428 -0
- package/dist/ts-loader.d.ts +46 -0
- package/dist/ts-loader.d.ts.map +1 -0
- package/dist/ts-loader.js +103 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +61 -0
- package/dist/validation.js +20 -0
- package/dist/vendor/js-yaml-load.js +1662 -0
- package/dist/workspace/__fixtures__/contract-repo.js +103 -0
- package/dist/workspace/__fixtures__/decide-workspace.js +112 -0
- package/dist/workspace/__fixtures__/sessions.js +91 -0
- package/dist/workspace/__fixtures__/two-member-workspace.js +34 -0
- package/dist/workspace/agent-cli.js +99 -0
- package/dist/workspace/agent.schema.json +390 -0
- package/dist/workspace/answers-ledger.js +89 -0
- package/dist/workspace/box-cli.js +142 -0
- package/dist/workspace/box-factory-write.js +196 -0
- package/dist/workspace/box-factory-write.schema.json +342 -0
- package/dist/workspace/box-factory.js +88 -0
- package/dist/workspace/box-intent.js +126 -0
- package/dist/workspace/box-isolation.js +169 -0
- package/dist/workspace/box-listing-write.schema.json +204 -0
- package/dist/workspace/box-listing.js +298 -0
- package/dist/workspace/box-publish.js +352 -0
- package/dist/workspace/box-publish.schema.json +498 -0
- package/dist/workspace/box-services.js +39 -0
- package/dist/workspace/broker-protocol.js +359 -0
- package/dist/workspace/broker-protocol.schema.json +228 -0
- package/dist/workspace/change-set.schema.json +460 -0
- package/dist/workspace/changes-cli.js +56 -0
- package/dist/workspace/changes.js +446 -0
- package/dist/workspace/changes.schema.json +642 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-fly-site.js +198 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-live-names.js +155 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-rollback.js +214 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-inputs.js +180 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit-ship-policy.js +99 -0
- package/dist/workspace/chant-migrations/chud-lexicon-exit.js +847 -0
- package/dist/workspace/chant-migrations.js +113 -0
- package/dist/workspace/check.schema.json +433 -0
- package/dist/workspace/checks/box-isolation.js +62 -0
- package/dist/workspace/checks/boxes.js +491 -0
- package/dist/workspace/checks/diagrams.js +104 -0
- package/dist/workspace/checks/generated.js +419 -0
- package/dist/workspace/checks/ledgers.js +212 -0
- package/dist/workspace/checks/links.js +191 -0
- package/dist/workspace/checks/live.js +100 -0
- package/dist/workspace/checks/pipelines.js +188 -0
- package/dist/workspace/checks/records.js +169 -0
- package/dist/workspace/checks.js +426 -0
- package/dist/workspace/ci-green-cli.js +125 -0
- package/dist/workspace/ci-green-forge.js +83 -0
- package/dist/workspace/ci-green-workflow.js +199 -0
- package/dist/workspace/ci-green.js +325 -0
- package/dist/workspace/ci-last-green.schema.json +158 -0
- package/dist/workspace/compose-graph.js +235 -0
- package/dist/workspace/compose-reports.js +146 -0
- package/dist/workspace/composites.js +264 -0
- package/dist/workspace/composites.schema.json +617 -0
- package/dist/workspace/conformance/__fixture__/app/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/app/src/server.mjs +29 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.kind.mjs +54 -0
- package/dist/workspace/conformance/__fixture__/decisions/decision.schema.json +512 -0
- package/dist/workspace/conformance/__fixture__/decisions/fix-001-how-the-app-is-deployed.md +40 -0
- package/dist/workspace/conformance/__fixture__/delivery/chant.config.ts +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/lexicon/index.ts +26 -0
- package/dist/workspace/conformance/__fixture__/delivery/package.json +7 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.component.ts +14 -0
- package/dist/workspace/conformance/__fixture__/delivery/src/app.ts +4 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.js +205 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/dist/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/dist/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/dist/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/dist/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/dist/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/dist/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/dist/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/dist/workspace/conformance/broker.js +736 -0
- package/dist/workspace/conformance/index.js +673 -0
- package/dist/workspace/conformance/vitest.js +108 -0
- package/dist/workspace/conformance/writer.js +1080 -0
- package/dist/workspace/decide.js +879 -0
- package/dist/workspace/decision-points.schema.json +135 -135
- package/dist/workspace/declaration-write-cli.js +74 -0
- package/dist/workspace/declaration-write.js +238 -0
- package/dist/workspace/declaration.js +938 -0
- package/dist/workspace/declaration.schema.json +1413 -1413
- package/dist/workspace/declared-kinds.js +106 -0
- package/dist/workspace/environments.js +164 -0
- package/dist/workspace/evidence.schema.json +279 -0
- package/dist/workspace/export-cli.js +185 -0
- package/dist/workspace/export.js +499 -0
- package/dist/workspace/factory-rules.js +175 -0
- package/dist/workspace/generated-files.js +92 -0
- package/dist/workspace/glob.js +45 -0
- package/dist/workspace/graph-cache.js +352 -0
- package/dist/workspace/graph-cli.js +348 -0
- package/dist/workspace/graph.schema.json +1338 -0
- package/dist/workspace/identity-gate-rule.d.ts +65 -0
- package/dist/workspace/identity-gate-rule.d.ts.map +1 -0
- package/dist/workspace/identity-gate-rule.js +75 -0
- package/dist/workspace/identity.d.ts +4 -2
- package/dist/workspace/identity.d.ts.map +1 -1
- package/dist/workspace/identity.js +126 -0
- package/dist/workspace/import.js +283 -0
- package/dist/workspace/init.js +620 -0
- package/dist/workspace/intent-cli.js +263 -0
- package/dist/workspace/intent-joins.js +201 -0
- package/dist/workspace/intent-record.js +352 -0
- package/dist/workspace/intent-record.schema.json +864 -0
- package/dist/workspace/intent.js +1582 -0
- package/dist/workspace/intent.schema.json +2420 -0
- package/dist/workspace/json-edit.js +221 -0
- package/dist/workspace/jsonc.js +235 -0
- package/dist/workspace/kind-readers.js +103 -0
- package/dist/workspace/kinds.js +587 -0
- package/dist/workspace/lexicon-symbols.js +112 -0
- package/dist/workspace/lineage-adopt-cli.js +102 -0
- package/dist/workspace/lineage-adopt.js +360 -0
- package/dist/workspace/lineage-check.js +282 -0
- package/dist/workspace/lineage-cli.js +121 -0
- package/dist/workspace/lineage-hash-index.js +284 -0
- package/dist/workspace/lineage-init.js +507 -0
- package/dist/workspace/lineage-lock.js +387 -0
- package/dist/workspace/lineage-merge.js +45 -0
- package/dist/workspace/lineage-migrations.d.ts.map +1 -1
- package/dist/workspace/lineage-migrations.js +329 -0
- package/dist/workspace/lineage-provenance.js +36 -0
- package/dist/workspace/lineage-update.js +138 -0
- package/dist/workspace/lineage-upgrade-cli.js +131 -0
- package/dist/workspace/lineage-upgrade.js +889 -0
- package/dist/workspace/lineage-vendor.js +171 -0
- package/dist/workspace/lineage-version.js +128 -0
- package/dist/workspace/lineage-versions.js +275 -0
- package/dist/workspace/links.js +330 -0
- package/dist/workspace/ls-generated.js +95 -0
- package/dist/workspace/ls.js +277 -0
- package/dist/workspace/ls.schema.json +333 -0
- package/dist/workspace/member-commands.js +508 -0
- package/dist/workspace/member-handles.js +216 -0
- package/dist/workspace/member-pipeline.js +258 -0
- package/dist/workspace/member-run.js +117 -0
- package/dist/workspace/member-write.schema.json +193 -0
- package/dist/workspace/nested-graph.js +156 -0
- package/dist/workspace/nesting.js +38 -0
- package/dist/workspace/patch.js +301 -0
- package/dist/workspace/patch.schema.json +321 -0
- package/dist/workspace/pin-cli.js +55 -0
- package/dist/workspace/pin-integrity.js +100 -0
- package/dist/workspace/plan-summary.schema.json +155 -0
- package/dist/workspace/point-answer.schema.json +129 -129
- package/dist/workspace/points-cli.js +291 -0
- package/dist/workspace/points-write.schema.json +660 -0
- package/dist/workspace/points.js +521 -0
- package/dist/workspace/points.schema.json +916 -0
- package/dist/workspace/pr-report.schema.json +108 -0
- package/dist/workspace/principal-classes.d.ts +3 -14
- package/dist/workspace/principal-classes.d.ts.map +1 -1
- package/dist/workspace/principal-classes.js +245 -0
- package/dist/workspace/reason-codes.js +326 -0
- package/dist/workspace/record-assets.js +151 -0
- package/dist/workspace/record-decided.js +105 -0
- package/dist/workspace/record-sessions.js +96 -0
- package/dist/workspace/record-source.js +114 -0
- package/dist/workspace/records-amend.schema.json +284 -0
- package/dist/workspace/records-checkout.js +76 -0
- package/dist/workspace/records-cli.js +707 -0
- package/dist/workspace/records-close.js +116 -0
- package/dist/workspace/records-close.schema.json +278 -0
- package/dist/workspace/records-new.schema.json +202 -0
- package/dist/workspace/records-review.schema.json +367 -0
- package/dist/workspace/records-since.js +317 -0
- package/dist/workspace/records-since.schema.json +218 -0
- package/dist/workspace/records-write.js +1229 -0
- package/dist/workspace/records.js +1345 -0
- package/dist/workspace/records.schema.json +604 -0
- package/dist/workspace/reference-kinds/app/package.json +10 -0
- package/dist/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/dist/workspace/returns.js +303 -0
- package/dist/workspace/root-refusal.js +75 -0
- package/dist/workspace/run-statement.schema.json +622 -0
- package/dist/workspace/runs-cli.js +584 -0
- package/dist/workspace/runs-write.schema.json +994 -0
- package/dist/workspace/runs.js +708 -0
- package/dist/workspace/runs.schema.json +1257 -0
- package/dist/workspace/runtimes.js +76 -0
- package/dist/workspace/session-kinds.js +83 -0
- package/dist/workspace/signers.schema.json +206 -0
- package/dist/workspace/source-block.js +125 -0
- package/dist/workspace/squash.js +177 -0
- package/dist/workspace/status-gates.js +162 -0
- package/dist/workspace/status-stewards.js +330 -0
- package/dist/workspace/status.js +514 -0
- package/dist/workspace/status.schema.json +998 -0
- package/dist/workspace/steward-index.js +191 -0
- package/dist/workspace/symbols.js +188 -0
- package/dist/workspace/template-manifest.js +227 -0
- package/dist/workspace/template-pins.js +115 -0
- package/dist/workspace/trailer-joins.js +65 -0
- package/dist/workspace/trailers.js +111 -0
- package/dist/workspace/tree.js +136 -0
- package/dist/workspace/trust/attestor.js +63 -0
- package/dist/workspace/trust/dsse.js +108 -0
- package/dist/workspace/trust/evidence-cli.js +175 -0
- package/dist/workspace/trust/evidence.js +161 -0
- package/dist/workspace/trust/gate-seal.js +226 -0
- package/dist/workspace/trust/policy.js +190 -0
- package/dist/workspace/trust/provenance.js +180 -0
- package/dist/workspace/trust/rotation.js +298 -0
- package/dist/workspace/trust/run-commits.js +101 -0
- package/dist/workspace/trust/run-statement.js +182 -0
- package/dist/workspace/trust/seal.js +272 -0
- package/dist/workspace/trust/signers-cli.js +152 -0
- package/dist/workspace/trust/ssh-commit.js +178 -0
- package/dist/workspace/trust/test-repo.js +118 -0
- package/dist/workspace/trust/trust-files.js +193 -0
- package/dist/workspace/trust/verify-cli.js +63 -0
- package/dist/workspace/trust/verify.js +192 -0
- package/dist/workspace/which-chant.js +141 -0
- package/dist/workspace/wip-cli.js +95 -0
- package/dist/workspace/wip-write.schema.json +504 -0
- package/dist/workspace/wip.js +631 -0
- package/dist/workspace/wip.schema.json +334 -0
- package/dist/workspace/work-cli.js +448 -0
- package/dist/workspace/work-evidence.js +122 -0
- package/dist/workspace/work-evidence.schema.json +222 -0
- package/dist/workspace/work-history.schema.json +421 -0
- package/dist/workspace/work-lease.schema.json +246 -0
- package/dist/workspace/work-size.js +77 -0
- package/dist/workspace/work.js +283 -0
- package/dist/workspace/workspace-kinds.schema.json +259 -259
- package/dist/workspace/workspace-principals.schema.json +53 -53
- package/dist/workspace/write-lock-cli.js +105 -0
- package/dist/workspace/write-lock.js +424 -0
- package/dist/workspace/write-lock.schema.json +172 -0
- package/dist/workspace/write-scope.js +484 -0
- package/dist/yaml.js +459 -0
- package/package.json +2 -2
- package/src/cli/commands/check-lexicon-plugin.ts +2 -0
- package/src/cli/commands/lint.ts +36 -6
- package/src/cli/commands/migrate.ts +2 -0
- package/src/cli/compiled-cli.e2e.test.ts +165 -0
- package/src/cli/main.ts +121 -27
- package/src/cli/mcp/workspace-tools.ts +1 -1
- package/src/codegen/pinned-upgrade.ts +2 -0
- package/src/components/discover.ts +2 -0
- package/src/components/sandbox/driver.ts +3 -1
- package/src/config-import.ts +3 -0
- package/src/discovery/fold-import.ts +23 -14
- package/src/discovery/import.ts +2 -0
- package/src/discovery/sandbox/driver.ts +3 -1
- package/src/gate-decision-bundle.test.ts +3 -2
- package/src/gate-decision-identity.test.ts +176 -0
- package/src/gate-decision.ts +100 -22
- package/src/lexicon-module.ts +3 -0
- package/src/lifecycle/gate-ledger.ts +8 -0
- package/src/lint/config.ts +1 -1
- package/src/lint/discover.ts +28 -8
- package/src/lint/policy-import.ts +4 -1
- package/src/lint/rule-loader.ts +2 -0
- package/src/op/discover.ts +3 -0
- package/src/op/op-waves-point.test.ts +1 -0
- package/src/op/op-waves-run.ts +5 -4
- package/src/op/op-waves.test.ts +14 -0
- package/src/ts-loader.test.ts +23 -0
- package/src/ts-loader.ts +122 -0
- package/src/workspace/chant-migrations/chud-lexicon-exit.ts +1 -1
- package/src/workspace/declaration.ts +1 -1
- package/src/workspace/identity-gate-rule.ts +109 -0
- package/src/workspace/identity.ts +8 -18
- package/src/workspace/kinds.ts +1 -1
- package/src/workspace/lineage-migrations.ts +2 -0
- package/src/workspace/points.ts +1 -1
- package/src/workspace/principal-classes.ts +5 -30
package/dist/pr-forge.js
ADDED
|
@@ -0,0 +1,810 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What chant and the products built on it ask of a forge: keep one comment
|
|
3
|
+
* (a merge request note on GitLab) on a pull request up to date, set a commit
|
|
4
|
+
* status, keep one tracking issue in the repository, list who approved a pull
|
|
5
|
+
* request, find the pull request that merged a commit, and open or edit a
|
|
6
|
+
* pull request (a merge request on GitLab) for a branch.
|
|
7
|
+
*
|
|
8
|
+
* The pull-request loop (#3183) uses the note, the status and the review
|
|
9
|
+
* calls. `reconcilePr`'s `comment` and `issue` finding modes post through the
|
|
10
|
+
* same clients (#3757), so a finding needs no `gh` on the runner. terragucci
|
|
11
|
+
* and SQL Yodeler post their own notes, statuses and drift issues through
|
|
12
|
+
* them too (#3759): bodies stay with each product, the finding by marker and
|
|
13
|
+
* the forge's REST shapes live here.
|
|
14
|
+
*
|
|
15
|
+
* GitHub and Forgejo speak the same REST shapes for most of this, at
|
|
16
|
+
* different base URLs (`$GITHUB_API_URL` is right on both, #2305); they part
|
|
17
|
+
* on the commit-to-pull-request lookup, on review states and on page size.
|
|
18
|
+
* GitLab has its own API for all of it. Each client takes a `fetch`, so the
|
|
19
|
+
* tests drive them with a recording fake and no network.
|
|
20
|
+
*
|
|
21
|
+
* A reviewer is named the way #3163 names a person: `github:<login>`,
|
|
22
|
+
* `gitlab:<login>`, or `<forge>@<host>:<login>` off the forge's default host.
|
|
23
|
+
* The apply compares that string with the approval's `resolvedBy`.
|
|
24
|
+
*
|
|
25
|
+
* Opening a pull request goes over REST too (#3798): `gh pr` speaks GitHub's
|
|
26
|
+
* GraphQL, which Forgejo does not serve, so chant's own pull-request paths
|
|
27
|
+
* open theirs through {@link PrForge.openPullRequest} on Forgejo and GitLab.
|
|
28
|
+
*
|
|
29
|
+
* Like `./pr-loop.ts`, this bundles without the TypeScript toolchain (#3421):
|
|
30
|
+
* it imports nothing but `node:fs`, to read a CI job's event payload.
|
|
31
|
+
* `./pr-forge-bundle.test.ts` holds it to that.
|
|
32
|
+
*/
|
|
33
|
+
import { readFileSync } from "node:fs";
|
|
34
|
+
export const FORGE_KINDS = ["github", "gitlab", "forgejo"];
|
|
35
|
+
/** Every {@link ForgeStatusState}, for a caller that reads one from its own input. */
|
|
36
|
+
export const FORGE_STATUS_STATES = ["pending", "running", "success", "failed", "failure", "canceled", "error"];
|
|
37
|
+
/**
|
|
38
|
+
* What each forge is sent for a {@link ForgeStatusState} (#3834). GitHub
|
|
39
|
+
* keeps `pending`, `success`, `failure` and `error`; Forgejo the same and
|
|
40
|
+
* `warning`; GitLab `pending`, `running`, `success`, `failed` and `canceled`.
|
|
41
|
+
* A state the forge lacks becomes its nearest one.
|
|
42
|
+
*/
|
|
43
|
+
const STATUS_STATE = {
|
|
44
|
+
github: { pending: "pending", running: "pending", success: "success", failed: "failure", failure: "failure", canceled: "error", error: "error" },
|
|
45
|
+
gitlab: { pending: "pending", running: "running", success: "success", failed: "failed", failure: "failed", canceled: "canceled", error: "failed" },
|
|
46
|
+
};
|
|
47
|
+
/** The state `kind` is sent for `state`. Forgejo takes GitHub's. */
|
|
48
|
+
export function statusStateFor(kind, state) {
|
|
49
|
+
const mapped = STATUS_STATE[kind === "gitlab" ? "gitlab" : "github"][state];
|
|
50
|
+
if (mapped === undefined)
|
|
51
|
+
throw new Error(`a commit status state is one of ${FORGE_STATUS_STATES.join(", ")}, not ${JSON.stringify(state)}`);
|
|
52
|
+
return mapped;
|
|
53
|
+
}
|
|
54
|
+
/** Statuses a forge answers a refused merge with: not allowed, head moved, conflict, invalid. */
|
|
55
|
+
const MERGE_REFUSED = new Set([405, 406, 409, 422]);
|
|
56
|
+
/** A refused merge as a result, any other failure rethrown. */
|
|
57
|
+
function refusedMerge(err) {
|
|
58
|
+
if (err instanceof ForgeApiError && MERGE_REFUSED.has(err.status)) {
|
|
59
|
+
let reason = err.detail;
|
|
60
|
+
try {
|
|
61
|
+
const j = JSON.parse(err.detail);
|
|
62
|
+
const m = j.message ?? j.error;
|
|
63
|
+
if (typeof m === "string")
|
|
64
|
+
reason = m;
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
/* not JSON: the raw text is the reason */
|
|
68
|
+
}
|
|
69
|
+
return { merged: false, reason: reason.slice(0, 300) || `the forge refused the merge (${err.status})` };
|
|
70
|
+
}
|
|
71
|
+
throw err;
|
|
72
|
+
}
|
|
73
|
+
/** Thrown when a forge answers a call with an error status. */
|
|
74
|
+
export class ForgeApiError extends Error {
|
|
75
|
+
constructor(method, url, status, detail) {
|
|
76
|
+
super(`${method} ${url} answered ${status}${detail ? `: ${detail.slice(0, 300)}` : ""}`);
|
|
77
|
+
this.method = method;
|
|
78
|
+
this.url = url;
|
|
79
|
+
this.status = status;
|
|
80
|
+
this.detail = detail;
|
|
81
|
+
this.name = "ForgeApiError";
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
const DEFAULT_HOST = { github: "github.com", gitlab: "gitlab.com", forgejo: null };
|
|
85
|
+
/** `<forge>:<login>` on the forge's default host, `<forge>@<host>:<login>` elsewhere, lower-cased (#3163's form). */
|
|
86
|
+
export function forgePrincipalOf(kind, host, login) {
|
|
87
|
+
const h = host.toLowerCase();
|
|
88
|
+
const l = login.toLowerCase();
|
|
89
|
+
return h === DEFAULT_HOST[kind] ? `${kind}:${l}` : `${kind}@${h}:${l}`;
|
|
90
|
+
}
|
|
91
|
+
function transport(base, headers, fetchImpl) {
|
|
92
|
+
const root = base.replace(/\/+$/, "");
|
|
93
|
+
const call = async (method, path, body) => {
|
|
94
|
+
const url = `${root}${path}`;
|
|
95
|
+
const res = await fetchImpl(url, {
|
|
96
|
+
method,
|
|
97
|
+
headers: { ...headers, ...(body !== undefined ? { "Content-Type": "application/json" } : {}) },
|
|
98
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
99
|
+
});
|
|
100
|
+
const text = await res.text();
|
|
101
|
+
if (!res.ok)
|
|
102
|
+
throw new ForgeApiError(method, url, res.status, text);
|
|
103
|
+
return text ? JSON.parse(text) : null;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
call,
|
|
107
|
+
async list(path, pageParams, pageSize) {
|
|
108
|
+
const out = [];
|
|
109
|
+
for (let page = 1; page <= 50; page++) {
|
|
110
|
+
const sep = path.includes("?") ? "&" : "?";
|
|
111
|
+
const items = await call("GET", `${path}${sep}${pageParams(page)}`);
|
|
112
|
+
if (!Array.isArray(items))
|
|
113
|
+
break;
|
|
114
|
+
out.push(...items);
|
|
115
|
+
if (items.length < pageSize)
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
},
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
123
|
+
const loginOf = (v) => (isObject(v) && isObject(v.user) && typeof v.user.login === "string" ? v.user.login : undefined);
|
|
124
|
+
const str = (v) => (typeof v === "string" ? v : undefined);
|
|
125
|
+
const num = (v) => (typeof v === "number" ? v : typeof v === "string" && /^\d+$/.test(v) ? Number(v) : undefined);
|
|
126
|
+
const carries = (body, marker, match) => match === "anywhere" ? body.includes(marker) : body.startsWith(marker);
|
|
127
|
+
/** Whether `author` is one of `want`, without case. No `want` (or `""`) takes anyone. */
|
|
128
|
+
const authorIn = (want, author) => {
|
|
129
|
+
if (want === undefined || want === "")
|
|
130
|
+
return true;
|
|
131
|
+
const logins = (typeof want === "string" ? [want] : want).map((l) => l.toLowerCase());
|
|
132
|
+
return author !== undefined && logins.includes(author.toLowerCase());
|
|
133
|
+
};
|
|
134
|
+
const ownedBy = (marker, opts) => (t) => carries(t.body, marker, opts.match) && authorIn(opts.author, t.author);
|
|
135
|
+
function checkMarker(what, marker, body, match) {
|
|
136
|
+
if (!marker)
|
|
137
|
+
throw new Error(`the ${what} needs a marker to be found again`);
|
|
138
|
+
if (!carries(body, marker, match)) {
|
|
139
|
+
throw new Error(`the ${what} body ${match === "anywhere" ? "does not carry" : "does not start with"} its marker ${JSON.stringify(marker)}, so the next run could not find it`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** The oldest comment on `pr` that `opts` takes for the caller's own. */
|
|
143
|
+
async function ownComment(t, pr, marker, opts) {
|
|
144
|
+
if (!marker)
|
|
145
|
+
throw new Error("the comment needs a marker to be found");
|
|
146
|
+
return (await t.comments(pr)).filter(ownedBy(marker, opts)).sort((a, b) => a.id - b.id)[0];
|
|
147
|
+
}
|
|
148
|
+
async function upsertCommentWith(t, pr, marker, body, opts, check) {
|
|
149
|
+
if (check)
|
|
150
|
+
checkMarker("comment", marker, body, opts.match);
|
|
151
|
+
const mine = await ownComment(t, pr, marker, opts);
|
|
152
|
+
if (!mine) {
|
|
153
|
+
const made = await t.addComment(pr, body);
|
|
154
|
+
return { action: "created", id: made?.id ?? 0, ...(made?.url ? { url: made.url } : {}) };
|
|
155
|
+
}
|
|
156
|
+
if (mine.body === body)
|
|
157
|
+
return { action: "unchanged", id: mine.id, ...(mine.url ? { url: mine.url } : {}) };
|
|
158
|
+
const edited = await t.editComment(pr, mine.id, body);
|
|
159
|
+
const url = edited?.url ?? mine.url;
|
|
160
|
+
return { action: "updated", id: mine.id, ...(url ? { url } : {}) };
|
|
161
|
+
}
|
|
162
|
+
async function trackIssueWith(t, marker, finding, opts, check) {
|
|
163
|
+
if (finding && check)
|
|
164
|
+
checkMarker("issue", marker, finding.body, opts.match);
|
|
165
|
+
const mine = (await t.openIssues(marker)).filter(ownedBy(marker, opts)).sort((a, b) => a.id - b.id)[0];
|
|
166
|
+
const at = (i) => i ? { number: i.id, ...(i.url ? { url: i.url } : {}), ...(i.created ? { created: i.created } : {}) } : {};
|
|
167
|
+
if (finding === null) {
|
|
168
|
+
if (!mine)
|
|
169
|
+
return { action: "none" };
|
|
170
|
+
if (!opts.closeOnClear)
|
|
171
|
+
return { action: "left", ...at(mine) };
|
|
172
|
+
await t.closeIssue(mine.id, opts.clearComment);
|
|
173
|
+
return { action: "closed", ...at(mine) };
|
|
174
|
+
}
|
|
175
|
+
if (!mine)
|
|
176
|
+
return { action: "opened", ...at(await t.openIssue(finding.title, finding.body)) };
|
|
177
|
+
if (sameIssue({ title: mine.title ?? "", body: mine.body }, finding, opts.sameWhen))
|
|
178
|
+
return { action: "unchanged", ...at(mine) };
|
|
179
|
+
const edited = await t.editIssue(mine.id, finding.title, finding.body);
|
|
180
|
+
return { action: "updated", ...at(mine), ...(edited?.url ? { url: edited.url } : {}) };
|
|
181
|
+
}
|
|
182
|
+
function sameIssue(open, finding, sameWhen) {
|
|
183
|
+
if (typeof sameWhen === "function")
|
|
184
|
+
return sameWhen(open, finding);
|
|
185
|
+
if (open.title !== finding.title)
|
|
186
|
+
return false;
|
|
187
|
+
return typeof sameWhen === "string" && sameWhen !== "" ? open.body.includes(sameWhen) : open.body === finding.body;
|
|
188
|
+
}
|
|
189
|
+
/** The recipes every client shares, over its own {@link Threads}. */
|
|
190
|
+
function threadCalls(t) {
|
|
191
|
+
return {
|
|
192
|
+
async addComment(pr, body) {
|
|
193
|
+
const made = await t.addComment(pr, body);
|
|
194
|
+
return { id: made?.id ?? 0, ...(made?.url ? { url: made.url } : {}) };
|
|
195
|
+
},
|
|
196
|
+
async findIssue(marker, opts = {}) {
|
|
197
|
+
if (!marker)
|
|
198
|
+
throw new Error("the issue needs a marker to be found");
|
|
199
|
+
const i = (await t.openIssues(marker)).filter(ownedBy(marker, opts)).sort((a, b) => a.id - b.id)[0];
|
|
200
|
+
return i ? { number: i.id, title: i.title ?? "", body: i.body, ...(i.created ? { created: i.created } : {}), ...(i.url ? { url: i.url } : {}) } : undefined;
|
|
201
|
+
},
|
|
202
|
+
async findComment(pr, marker, opts = {}) {
|
|
203
|
+
const c = await ownComment(t, pr, marker, opts);
|
|
204
|
+
return c ? { id: c.id, body: c.body, ...(c.url ? { url: c.url } : {}) } : undefined;
|
|
205
|
+
},
|
|
206
|
+
upsertComment: (pr, marker, body, opts = {}) => upsertCommentWith(t, pr, marker, body, opts, true),
|
|
207
|
+
upsertNote: async (pr, marker, body) => (await upsertCommentWith(t, pr, marker, body, {}, false)).url,
|
|
208
|
+
trackIssue: (marker, finding, opts = {}) => trackIssueWith(t, marker, finding, opts, true),
|
|
209
|
+
upsertIssue: async (marker, title, body) => (await trackIssueWith(t, marker, { title, body }, {}, false)).url,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
/** GitHub keeps a status description to 140 characters; Forgejo follows. */
|
|
213
|
+
const GITHUB_DESCRIPTION = 140;
|
|
214
|
+
/** GitLab keeps a status description to 255 characters. */
|
|
215
|
+
const GITLAB_DESCRIPTION = 255;
|
|
216
|
+
/** Which of the two GitHub-shaped forges a client is talking to. */
|
|
217
|
+
function githubShaped(kind, opts) {
|
|
218
|
+
const host = (opts.host ?? "github.com").toLowerCase();
|
|
219
|
+
const api = transport(opts.apiBase, kind === "github"
|
|
220
|
+
? { ...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}), Accept: "application/vnd.github+json" }
|
|
221
|
+
: { ...(opts.token ? { Authorization: `token ${opts.token}` } : {}), Accept: "application/json" }, opts.fetch ?? globalThis.fetch);
|
|
222
|
+
const repo = `/repos/${opts.repo}`;
|
|
223
|
+
// GitHub pages with per_page (up to 100); Forgejo with limit (capped at 50 by default).
|
|
224
|
+
const pageSize = kind === "github" ? 100 : 50;
|
|
225
|
+
const pageParams = (page) => (kind === "github" ? `per_page=100&page=${page}` : `limit=50&page=${page}`);
|
|
226
|
+
const thread = (v) => {
|
|
227
|
+
if (!isObject(v))
|
|
228
|
+
return undefined;
|
|
229
|
+
const id = num(v.number) ?? num(v.id);
|
|
230
|
+
if (id === undefined)
|
|
231
|
+
return undefined;
|
|
232
|
+
const author = loginOf(v);
|
|
233
|
+
const url = str(v.html_url);
|
|
234
|
+
const created = str(v.created_at);
|
|
235
|
+
return { id, body: str(v.body) ?? "", ...(created ? { created } : {}), ...(str(v.title) !== undefined ? { title: str(v.title) } : {}), ...(author ? { author } : {}), ...(url ? { url } : {}) };
|
|
236
|
+
};
|
|
237
|
+
const threads = (items) => items.map(thread).filter((t) => t !== undefined);
|
|
238
|
+
const pull = (v) => {
|
|
239
|
+
if (!isObject(v))
|
|
240
|
+
return undefined;
|
|
241
|
+
const number = num(v.number);
|
|
242
|
+
const head = isObject(v.head) ? str(v.head.ref) : undefined;
|
|
243
|
+
if (number === undefined)
|
|
244
|
+
return undefined;
|
|
245
|
+
const base = isObject(v.base) ? str(v.base.ref) : undefined;
|
|
246
|
+
const url = str(v.html_url);
|
|
247
|
+
return { number, title: str(v.title) ?? "", body: str(v.body) ?? "", head: head ?? "", ...(base ? { base } : {}), ...(url ? { url } : {}) };
|
|
248
|
+
};
|
|
249
|
+
/** A pull request whose head branch lives in this repository, not a fork. */
|
|
250
|
+
const fromHere = (v, head) => {
|
|
251
|
+
if (!isObject(v) || !isObject(v.head) || v.head.ref !== head)
|
|
252
|
+
return false;
|
|
253
|
+
const full = isObject(v.head.repo) ? str(v.head.repo.full_name) : undefined;
|
|
254
|
+
return full === undefined || full.toLowerCase() === opts.repo.toLowerCase();
|
|
255
|
+
};
|
|
256
|
+
const t = {
|
|
257
|
+
comments: async (pr) => threads(await api.list(`${repo}/issues/${pr}/comments`, pageParams, pageSize)),
|
|
258
|
+
addComment: async (pr, body) => thread(await api.call("POST", `${repo}/issues/${pr}/comments`, { body })),
|
|
259
|
+
editComment: async (_pr, id, body) => thread(await api.call("PATCH", `${repo}/issues/comments/${id}`, { body })),
|
|
260
|
+
// Paged in full rather than searched: GitHub's search index lags a
|
|
261
|
+
// write, so a run straight after another would miss the issue it just
|
|
262
|
+
// opened, and Forgejo has no `/search/issues` at all. Both list pull
|
|
263
|
+
// requests among issues; one of those is never ours.
|
|
264
|
+
openIssues: async () => threads((await api.list(`${repo}/issues?state=open`, pageParams, pageSize)).filter((i) => isObject(i) && !isObject(i.pull_request))),
|
|
265
|
+
openIssue: async (title, body) => thread(await api.call("POST", `${repo}/issues`, { title, body })),
|
|
266
|
+
editIssue: async (n, title, body) => thread(await api.call("PATCH", `${repo}/issues/${n}`, { title, body })),
|
|
267
|
+
async closeIssue(n, comment) {
|
|
268
|
+
if (comment)
|
|
269
|
+
await api.call("POST", `${repo}/issues/${n}/comments`, { body: comment });
|
|
270
|
+
await api.call("PATCH", `${repo}/issues/${n}`, { state: "closed" });
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
return {
|
|
274
|
+
kind,
|
|
275
|
+
host,
|
|
276
|
+
...(opts.runUrl ? { runUrl: opts.runUrl } : {}),
|
|
277
|
+
principalOf: (login) => forgePrincipalOf(kind, host, login),
|
|
278
|
+
...threadCalls(t),
|
|
279
|
+
async setStatus(sha, status) {
|
|
280
|
+
await api.call("POST", `${repo}/statuses/${sha}`, {
|
|
281
|
+
state: statusStateFor(kind, status.state),
|
|
282
|
+
context: status.context,
|
|
283
|
+
description: status.description.slice(0, GITHUB_DESCRIPTION),
|
|
284
|
+
...(status.url ? { target_url: status.url } : {}),
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
async approvers(pr) {
|
|
288
|
+
// A reviewer's newest deciding review is their standing one. A comment
|
|
289
|
+
// review decides nothing; a dismissed one (GitHub's state, Forgejo's
|
|
290
|
+
// flag) no longer approves.
|
|
291
|
+
const reviews = await api.list(`${repo}/pulls/${pr}/reviews`, pageParams, pageSize);
|
|
292
|
+
const standing = new Map();
|
|
293
|
+
for (const r of reviews) {
|
|
294
|
+
const login = loginOf(r);
|
|
295
|
+
if (!login || !isObject(r) || typeof r.state !== "string")
|
|
296
|
+
continue;
|
|
297
|
+
const state = r.dismissed === true ? "DISMISSED" : r.state.toUpperCase();
|
|
298
|
+
if (state === "COMMENTED" || state === "COMMENT" || state === "PENDING")
|
|
299
|
+
continue;
|
|
300
|
+
standing.set(login, state);
|
|
301
|
+
}
|
|
302
|
+
return [...standing].filter(([, state]) => state === "APPROVED").map(([login]) => login).sort();
|
|
303
|
+
},
|
|
304
|
+
async pullRequestFor(sha) {
|
|
305
|
+
if (kind === "forgejo") {
|
|
306
|
+
try {
|
|
307
|
+
const pr = await api.call("GET", `${repo}/commits/${sha}/pull`);
|
|
308
|
+
return isObject(pr) && typeof pr.number === "number" ? pr.number : null;
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
if (err instanceof ForgeApiError && err.status === 404)
|
|
312
|
+
return null;
|
|
313
|
+
throw err;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const prs = await api.call("GET", `${repo}/commits/${sha}/pulls`);
|
|
317
|
+
if (!Array.isArray(prs))
|
|
318
|
+
return null;
|
|
319
|
+
const merged = prs.filter((p) => isObject(p) && p.merged_at);
|
|
320
|
+
const exact = merged.find((p) => isObject(p) && p.merge_commit_sha === sha);
|
|
321
|
+
const pick = (exact ?? merged[0]);
|
|
322
|
+
return pick && typeof pick.number === "number" ? pick.number : null;
|
|
323
|
+
},
|
|
324
|
+
async openPullRequest(spec) {
|
|
325
|
+
const base = spec.base ?? (await defaultBranchOf(api, repo, "default_branch"));
|
|
326
|
+
const title = spec.draft && kind === "forgejo" ? `WIP: ${spec.title}` : spec.title;
|
|
327
|
+
const made = await api.call("POST", `${repo}/pulls`, {
|
|
328
|
+
title,
|
|
329
|
+
body: spec.body,
|
|
330
|
+
head: spec.head,
|
|
331
|
+
base,
|
|
332
|
+
...(spec.draft && kind === "github" ? { draft: true } : {}),
|
|
333
|
+
});
|
|
334
|
+
return pull(made) ?? { number: 0, title, body: spec.body, head: spec.head, base };
|
|
335
|
+
},
|
|
336
|
+
async findPullRequest(head) {
|
|
337
|
+
// GitHub filters by `owner:branch` server-side; Forgejo's list takes no
|
|
338
|
+
// head filter, so every open page is read and matched here.
|
|
339
|
+
const owner = opts.repo.split("/")[0];
|
|
340
|
+
const query = kind === "github" ? `?state=open&head=${encodeURIComponent(`${owner}:${head}`)}` : "?state=open";
|
|
341
|
+
let listed;
|
|
342
|
+
try {
|
|
343
|
+
listed = await api.list(`${repo}/pulls${query}`, pageParams, pageSize);
|
|
344
|
+
}
|
|
345
|
+
catch (err) {
|
|
346
|
+
// Forgejo answers the list with 404 while it still counts the repository
|
|
347
|
+
// as empty (just after the first push). That is no pull request; a
|
|
348
|
+
// repository that is really missing 404s on its own read too.
|
|
349
|
+
if (kind !== "forgejo" || !(err instanceof ForgeApiError) || err.status !== 404)
|
|
350
|
+
throw err;
|
|
351
|
+
await api.call("GET", repo);
|
|
352
|
+
return undefined;
|
|
353
|
+
}
|
|
354
|
+
const open = listed.filter((p) => fromHere(p, head));
|
|
355
|
+
return open.map(pull).filter((p) => p !== undefined).sort((a, b) => a.number - b.number)[0];
|
|
356
|
+
},
|
|
357
|
+
async editPullRequest(pr, change) {
|
|
358
|
+
return pull(await api.call("PATCH", `${repo}/pulls/${pr}`, { ...(change.title !== undefined ? { title: change.title } : {}), ...(change.body !== undefined ? { body: change.body } : {}) }));
|
|
359
|
+
},
|
|
360
|
+
async addLabels(pr, labels) {
|
|
361
|
+
if (labels.length === 0)
|
|
362
|
+
return;
|
|
363
|
+
await api.call("POST", `${repo}/issues/${pr}/labels`, { labels: [...labels] });
|
|
364
|
+
},
|
|
365
|
+
async mergePullRequest(pr, m) {
|
|
366
|
+
const method = m.method ?? "merge";
|
|
367
|
+
let res;
|
|
368
|
+
try {
|
|
369
|
+
res =
|
|
370
|
+
kind === "github"
|
|
371
|
+
? await api.call("PUT", `${repo}/pulls/${pr}/merge`, {
|
|
372
|
+
sha: m.sha,
|
|
373
|
+
merge_method: method,
|
|
374
|
+
...(m.title !== undefined ? { commit_title: m.title } : {}),
|
|
375
|
+
...(m.message !== undefined ? { commit_message: m.message } : {}),
|
|
376
|
+
})
|
|
377
|
+
: await api.call("POST", `${repo}/pulls/${pr}/merge`, {
|
|
378
|
+
Do: method,
|
|
379
|
+
head_commit_id: m.sha,
|
|
380
|
+
...(m.title !== undefined ? { MergeTitleField: m.title } : {}),
|
|
381
|
+
...(m.message !== undefined ? { MergeMessageField: m.message } : {}),
|
|
382
|
+
...(m.deleteBranch ? { delete_branch_after_merge: true } : {}),
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
catch (err) {
|
|
386
|
+
return refusedMerge(err);
|
|
387
|
+
}
|
|
388
|
+
if (isObject(res) && res.merged === false)
|
|
389
|
+
return { merged: false, reason: str(res.message) ?? "the forge did not merge it" };
|
|
390
|
+
// Forgejo answers an empty body, so the merge commit is read back.
|
|
391
|
+
const after = await api.call("GET", `${repo}/pulls/${pr}`).catch(() => undefined);
|
|
392
|
+
const sha = (isObject(res) ? str(res.sha) : undefined) ?? (isObject(after) ? str(after.merge_commit_sha) : undefined);
|
|
393
|
+
if (kind === "github" && m.deleteBranch && isObject(after) && isObject(after.head) && str(after.head.ref) && fromHere(after, str(after.head.ref))) {
|
|
394
|
+
const ref = str(after.head.ref).split("/").map(encodeURIComponent).join("/");
|
|
395
|
+
await api.call("DELETE", `${repo}/git/refs/heads/${ref}`).catch(() => undefined);
|
|
396
|
+
}
|
|
397
|
+
return { merged: true, ...(sha ? { sha } : {}) };
|
|
398
|
+
},
|
|
399
|
+
};
|
|
400
|
+
}
|
|
401
|
+
/** The repository's default branch, from `GET` on the repository (`/repos/{repo}`, `/projects/{id}`). */
|
|
402
|
+
async function defaultBranchOf(api, path, field) {
|
|
403
|
+
const r = await api.call("GET", path);
|
|
404
|
+
const branch = isObject(r) ? str(r[field]) : undefined;
|
|
405
|
+
if (!branch)
|
|
406
|
+
throw new Error(`${path} names no default branch to open the pull request against; pass base`);
|
|
407
|
+
return branch;
|
|
408
|
+
}
|
|
409
|
+
/** A GitHub client (github.com or GitHub Enterprise Server). */
|
|
410
|
+
export function githubForge(opts) {
|
|
411
|
+
return githubShaped("github", opts);
|
|
412
|
+
}
|
|
413
|
+
/** A Forgejo (or Gitea) client. `host` is required: Forgejo has no default host. */
|
|
414
|
+
export function forgejoForge(opts) {
|
|
415
|
+
return githubShaped("forgejo", opts);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* A GitLab client. Writing notes needs an access token with the `api` scope
|
|
419
|
+
* on most instances: the job token reaches only the endpoints the instance's
|
|
420
|
+
* job-token allowlist names.
|
|
421
|
+
*/
|
|
422
|
+
export function gitlabForge(opts) {
|
|
423
|
+
const host = (opts.host ?? "gitlab.com").toLowerCase();
|
|
424
|
+
const api = transport(opts.apiBase, opts.token ? { [opts.tokenHeader ?? "PRIVATE-TOKEN"]: opts.token } : {}, opts.fetch ?? globalThis.fetch);
|
|
425
|
+
const project = `/projects/${encodeURIComponent(decodeURIComponent(opts.project))}`;
|
|
426
|
+
const pageParams = (page) => `per_page=100&page=${page}`;
|
|
427
|
+
const authorOf = (v) => (isObject(v.author) ? str(v.author.username) : undefined);
|
|
428
|
+
const note = (v) => {
|
|
429
|
+
if (!isObject(v))
|
|
430
|
+
return undefined;
|
|
431
|
+
const id = num(v.id);
|
|
432
|
+
if (id === undefined)
|
|
433
|
+
return undefined;
|
|
434
|
+
const author = authorOf(v);
|
|
435
|
+
return { id, body: str(v.body) ?? "", ...(author ? { author } : {}) };
|
|
436
|
+
};
|
|
437
|
+
const issue = (v) => {
|
|
438
|
+
if (!isObject(v))
|
|
439
|
+
return undefined;
|
|
440
|
+
const id = num(v.iid);
|
|
441
|
+
if (id === undefined)
|
|
442
|
+
return undefined;
|
|
443
|
+
const author = authorOf(v);
|
|
444
|
+
const url = str(v.web_url);
|
|
445
|
+
const created = str(v.created_at);
|
|
446
|
+
return { id, body: str(v.description) ?? "", ...(created ? { created } : {}), ...(str(v.title) !== undefined ? { title: str(v.title) } : {}), ...(author ? { author } : {}), ...(url ? { url } : {}) };
|
|
447
|
+
};
|
|
448
|
+
const notes = `${project}/merge_requests`;
|
|
449
|
+
const mergeRequest = (v) => {
|
|
450
|
+
if (!isObject(v))
|
|
451
|
+
return undefined;
|
|
452
|
+
const number = num(v.iid);
|
|
453
|
+
if (number === undefined)
|
|
454
|
+
return undefined;
|
|
455
|
+
const base = str(v.target_branch);
|
|
456
|
+
const url = str(v.web_url);
|
|
457
|
+
return { number, title: str(v.title) ?? "", body: str(v.description) ?? "", head: str(v.source_branch) ?? "", ...(base ? { base } : {}), ...(url ? { url } : {}) };
|
|
458
|
+
};
|
|
459
|
+
const t = {
|
|
460
|
+
comments: async (mr) => (await api.list(`${notes}/${mr}/notes`, pageParams, 100))
|
|
461
|
+
// System notes ("added 1 commit") are the forge's own, never ours.
|
|
462
|
+
.filter((n) => !(isObject(n) && n.system === true))
|
|
463
|
+
.map(note)
|
|
464
|
+
.filter((n) => n !== undefined),
|
|
465
|
+
addComment: async (mr, body) => note(await api.call("POST", `${notes}/${mr}/notes`, { body })),
|
|
466
|
+
editComment: async (mr, id, body) => note(await api.call("PUT", `${notes}/${mr}/notes/${id}`, { body })),
|
|
467
|
+
// `search` narrows the list server-side to issues whose description
|
|
468
|
+
// carries the marker, as `reconcilePr`'s GitLab issue does (#2292); the
|
|
469
|
+
// match itself is still decided here.
|
|
470
|
+
openIssues: async (marker) => (await api.list(`${project}/issues?state=opened&search=${encodeURIComponent(marker)}&in=description`, pageParams, 100))
|
|
471
|
+
.map(issue)
|
|
472
|
+
.filter((i) => i !== undefined),
|
|
473
|
+
openIssue: async (title, body) => issue(await api.call("POST", `${project}/issues`, { title, description: body })),
|
|
474
|
+
editIssue: async (n, title, body) => issue(await api.call("PUT", `${project}/issues/${n}`, { title, description: body })),
|
|
475
|
+
async closeIssue(n, comment) {
|
|
476
|
+
if (comment)
|
|
477
|
+
await api.call("POST", `${project}/issues/${n}/notes`, { body: comment });
|
|
478
|
+
await api.call("PUT", `${project}/issues/${n}`, { state_event: "close" });
|
|
479
|
+
},
|
|
480
|
+
};
|
|
481
|
+
return {
|
|
482
|
+
kind: "gitlab",
|
|
483
|
+
host,
|
|
484
|
+
...(opts.runUrl ? { runUrl: opts.runUrl } : {}),
|
|
485
|
+
principalOf: (login) => forgePrincipalOf("gitlab", host, login),
|
|
486
|
+
...threadCalls(t),
|
|
487
|
+
async setStatus(sha, status) {
|
|
488
|
+
try {
|
|
489
|
+
await api.call("POST", `${project}/statuses/${sha}`, {
|
|
490
|
+
state: statusStateFor("gitlab", status.state),
|
|
491
|
+
name: status.context,
|
|
492
|
+
description: status.description.slice(0, GITLAB_DESCRIPTION),
|
|
493
|
+
...(status.url ? { target_url: status.url } : {}),
|
|
494
|
+
...(status.pipelineId !== undefined ? { pipeline_id: status.pipelineId } : {}),
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
catch (err) {
|
|
498
|
+
// GitLab answers 400 to a status set again to the state it already
|
|
499
|
+
// has ("Cannot transition status via :success from :success"): the
|
|
500
|
+
// status is what was asked for.
|
|
501
|
+
if (err instanceof ForgeApiError && err.status === 400 && /cannot transition status/i.test(err.message))
|
|
502
|
+
return;
|
|
503
|
+
throw err;
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
async approvers(mr) {
|
|
507
|
+
const approvals = await api.call("GET", `${project}/merge_requests/${mr}/approvals`);
|
|
508
|
+
const by = isObject(approvals) && Array.isArray(approvals.approved_by) ? approvals.approved_by : [];
|
|
509
|
+
const logins = by
|
|
510
|
+
.map((a) => (isObject(a) && isObject(a.user) && typeof a.user.username === "string" ? a.user.username : undefined))
|
|
511
|
+
.filter((l) => l !== undefined);
|
|
512
|
+
return [...new Set(logins)].sort();
|
|
513
|
+
},
|
|
514
|
+
async pullRequestFor(sha) {
|
|
515
|
+
const mrs = await api.call("GET", `${project}/repository/commits/${sha}/merge_requests`);
|
|
516
|
+
if (!Array.isArray(mrs))
|
|
517
|
+
return null;
|
|
518
|
+
const merged = mrs.find((m) => isObject(m) && m.state === "merged" && (m.merge_commit_sha === sha || m.squash_commit_sha === sha))
|
|
519
|
+
?? mrs.find((m) => isObject(m) && m.state === "merged");
|
|
520
|
+
return isObject(merged) && typeof merged.iid === "number" ? merged.iid : null;
|
|
521
|
+
},
|
|
522
|
+
async openPullRequest(spec) {
|
|
523
|
+
const base = spec.base ?? (await defaultBranchOf(api, project, "default_branch"));
|
|
524
|
+
const title = spec.draft ? `Draft: ${spec.title}` : spec.title;
|
|
525
|
+
const made = await api.call("POST", notes, { source_branch: spec.head, target_branch: base, title, description: spec.body });
|
|
526
|
+
return mergeRequest(made) ?? { number: 0, title, body: spec.body, head: spec.head, base };
|
|
527
|
+
},
|
|
528
|
+
async findPullRequest(head) {
|
|
529
|
+
const open = await api.list(`${notes}?state=opened&source_branch=${encodeURIComponent(head)}`, pageParams, 100);
|
|
530
|
+
return open
|
|
531
|
+
// A fork's merge request into this project has another source project.
|
|
532
|
+
.filter((m) => isObject(m) && m.source_branch === head && (m.source_project_id === undefined || m.source_project_id === m.project_id))
|
|
533
|
+
.map(mergeRequest)
|
|
534
|
+
.filter((m) => m !== undefined)
|
|
535
|
+
.sort((a, b) => a.number - b.number)[0];
|
|
536
|
+
},
|
|
537
|
+
async editPullRequest(mr, change) {
|
|
538
|
+
return mergeRequest(await api.call("PUT", `${notes}/${mr}`, { ...(change.title !== undefined ? { title: change.title } : {}), ...(change.body !== undefined ? { description: change.body } : {}) }));
|
|
539
|
+
},
|
|
540
|
+
async addLabels(mr, labels) {
|
|
541
|
+
if (labels.length === 0)
|
|
542
|
+
return;
|
|
543
|
+
await api.call("PUT", `${notes}/${mr}`, { add_labels: labels.join(",") });
|
|
544
|
+
},
|
|
545
|
+
async mergePullRequest(mr, m) {
|
|
546
|
+
const method = m.method ?? "merge";
|
|
547
|
+
if (method === "rebase")
|
|
548
|
+
throw new Error("GitLab has no one-call rebase merge; use method merge or squash");
|
|
549
|
+
const text = m.title !== undefined ? (m.message ? `${m.title}\n\n${m.message}` : m.title) : m.message;
|
|
550
|
+
let res;
|
|
551
|
+
try {
|
|
552
|
+
res = await api.call("PUT", `${notes}/${mr}/merge`, {
|
|
553
|
+
sha: m.sha,
|
|
554
|
+
...(method === "squash" ? { squash: true, ...(text !== undefined ? { squash_commit_message: text } : {}) } : {}),
|
|
555
|
+
...(text !== undefined ? { merge_commit_message: text } : {}),
|
|
556
|
+
...(m.deleteBranch ? { should_remove_source_branch: true } : {}),
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
return refusedMerge(err);
|
|
561
|
+
}
|
|
562
|
+
const sha = isObject(res) ? (str(res.merge_commit_sha) ?? str(res.squash_commit_sha)) : undefined;
|
|
563
|
+
if (isObject(res) && res.state !== undefined && res.state !== "merged")
|
|
564
|
+
return { merged: false, reason: `the merge request is ${String(res.state)}` };
|
|
565
|
+
return { merged: true, ...(sha ? { sha } : {}) };
|
|
566
|
+
},
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
/** Thrown when the environment lacks what a forge client needs. */
|
|
570
|
+
export class ForgeEnvironmentError extends Error {
|
|
571
|
+
/**
|
|
572
|
+
* @param kind The forge, or undefined when the environment does not say which.
|
|
573
|
+
* @param missing What is missing, each naming the variable to set.
|
|
574
|
+
*/
|
|
575
|
+
constructor(kind, missing) {
|
|
576
|
+
super(kind
|
|
577
|
+
? `--forge ${kind} needs ${missing.join(", ")} in the environment`
|
|
578
|
+
: "the forge is not known: this is not a GitHub Actions, GitLab CI or Forgejo Actions job, so name the forge");
|
|
579
|
+
this.kind = kind;
|
|
580
|
+
this.missing = missing;
|
|
581
|
+
this.name = "ForgeEnvironmentError";
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
const hostOf = (url) => {
|
|
585
|
+
if (!url)
|
|
586
|
+
return undefined;
|
|
587
|
+
try {
|
|
588
|
+
return new URL(url).host.toLowerCase();
|
|
589
|
+
}
|
|
590
|
+
catch {
|
|
591
|
+
return undefined;
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
/**
|
|
595
|
+
* A client for `kind` from the CI job's environment, as the pull-request
|
|
596
|
+
* loop reads it. The token is `CHANT_FORGE_TOKEN` when set, else the forge's
|
|
597
|
+
* own: `GITHUB_TOKEN` (also set on Forgejo Actions) or `GITLAB_TOKEN`.
|
|
598
|
+
* GitLab's `CI_JOB_TOKEN` cannot write notes, so a GitLab pipeline names a
|
|
599
|
+
* project access token. {@link forgeTargetFromEnv} is the general reading,
|
|
600
|
+
* with the finding modes' token order.
|
|
601
|
+
*/
|
|
602
|
+
export function forgeFromEnv(kind, env = process.env, fetchImpl) {
|
|
603
|
+
const f = fetchImpl ? { fetch: fetchImpl } : {};
|
|
604
|
+
if (kind === "gitlab") {
|
|
605
|
+
const token = env.CHANT_FORGE_TOKEN ?? env.GITLAB_TOKEN;
|
|
606
|
+
const missing = [
|
|
607
|
+
...(env.CI_API_V4_URL ? [] : ["CI_API_V4_URL"]),
|
|
608
|
+
...(env.CI_PROJECT_ID ? [] : ["CI_PROJECT_ID"]),
|
|
609
|
+
...(token ? [] : ["CHANT_FORGE_TOKEN (a token with the api scope)"]),
|
|
610
|
+
];
|
|
611
|
+
if (missing.length > 0)
|
|
612
|
+
throw new ForgeEnvironmentError(kind, missing);
|
|
613
|
+
return gitlabForge({
|
|
614
|
+
apiBase: env.CI_API_V4_URL,
|
|
615
|
+
project: env.CI_PROJECT_ID,
|
|
616
|
+
token: token,
|
|
617
|
+
host: env.CI_SERVER_HOST ?? hostOf(env.CI_SERVER_URL) ?? "gitlab.com",
|
|
618
|
+
...(env.CI_PIPELINE_URL ? { runUrl: env.CI_PIPELINE_URL } : {}),
|
|
619
|
+
...f,
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
const token = env.CHANT_FORGE_TOKEN ?? env.GITHUB_TOKEN ?? env.GH_TOKEN;
|
|
623
|
+
const host = hostOf(env.GITHUB_SERVER_URL);
|
|
624
|
+
const missing = [
|
|
625
|
+
...(env.GITHUB_REPOSITORY ? [] : ["GITHUB_REPOSITORY"]),
|
|
626
|
+
...(token ? [] : ["GITHUB_TOKEN or CHANT_FORGE_TOKEN"]),
|
|
627
|
+
...(kind === "forgejo" && !host ? ["GITHUB_SERVER_URL"] : []),
|
|
628
|
+
...(kind === "forgejo" && !env.GITHUB_API_URL ? ["GITHUB_API_URL"] : []),
|
|
629
|
+
];
|
|
630
|
+
if (missing.length > 0)
|
|
631
|
+
throw new ForgeEnvironmentError(kind, missing);
|
|
632
|
+
const runUrl = env.GITHUB_SERVER_URL && env.GITHUB_RUN_ID
|
|
633
|
+
? `${env.GITHUB_SERVER_URL.replace(/\/+$/, "")}/${env.GITHUB_REPOSITORY}/actions/runs/${env.GITHUB_RUN_ID}`
|
|
634
|
+
: undefined;
|
|
635
|
+
const opts = {
|
|
636
|
+
apiBase: env.GITHUB_API_URL ?? "https://api.github.com",
|
|
637
|
+
repo: env.GITHUB_REPOSITORY,
|
|
638
|
+
token: token,
|
|
639
|
+
...(runUrl ? { runUrl } : {}),
|
|
640
|
+
...f,
|
|
641
|
+
};
|
|
642
|
+
return kind === "forgejo" ? forgejoForge({ ...opts, host: host }) : githubForge({ ...opts, host: host ?? "github.com" });
|
|
643
|
+
}
|
|
644
|
+
const truthy = (v) => v === "true" || v === "1";
|
|
645
|
+
/**
|
|
646
|
+
* The forge a CI job runs on, from its environment, or undefined outside a
|
|
647
|
+
* GitHub Actions, GitLab CI or Forgejo Actions job. Forgejo is told apart by
|
|
648
|
+
* `FORGEJO_ACTIONS` or `GITEA_ACTIONS`, or by a GitHub-style job whose
|
|
649
|
+
* `GITHUB_API_URL` ends in `/api/v1`, which GitHub never serves.
|
|
650
|
+
*/
|
|
651
|
+
export function detectForge(env = process.env) {
|
|
652
|
+
if (truthy(env.GITLAB_CI))
|
|
653
|
+
return "gitlab";
|
|
654
|
+
if (truthy(env.FORGEJO_ACTIONS) || truthy(env.GITEA_ACTIONS))
|
|
655
|
+
return "forgejo";
|
|
656
|
+
if (truthy(env.GITHUB_ACTIONS))
|
|
657
|
+
return /\/api\/v1\/?$/.test(env.GITHUB_API_URL ?? "") ? "forgejo" : "github";
|
|
658
|
+
return undefined;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* The token order {@link forgeTargetFromEnv} reads, as guide/ops documents
|
|
662
|
+
* it: a chant-specific variable first, for posting to an instance other than
|
|
663
|
+
* the one the job runs on, then what the job already carries (#3802). A
|
|
664
|
+
* Forgejo job reads `FORGEJO_TOKEN` before the `GITHUB_*` names, and the
|
|
665
|
+
* GitHub row has its own chant variable rather than the Forgejo one.
|
|
666
|
+
*/
|
|
667
|
+
export const FORGE_TOKEN_ORDER = {
|
|
668
|
+
github: ["CHANT_GITHUB_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"],
|
|
669
|
+
forgejo: ["CHANT_FORGEJO_TOKEN", "FORGEJO_TOKEN", "GH_TOKEN", "GITHUB_TOKEN"],
|
|
670
|
+
gitlab: ["CHANT_GITLAB_TOKEN", "GITLAB_TOKEN", "CI_JOB_TOKEN"],
|
|
671
|
+
};
|
|
672
|
+
/** The pull request and its head from a GitHub-style event payload, or from the ref. */
|
|
673
|
+
function prFromEvent(payload, ref) {
|
|
674
|
+
const out = {};
|
|
675
|
+
if (isObject(payload)) {
|
|
676
|
+
const pr = isObject(payload.pull_request) ? payload.pull_request : undefined;
|
|
677
|
+
const issue = isObject(payload.issue) ? payload.issue : undefined;
|
|
678
|
+
const n = num(pr?.number) ?? (issue && isObject(issue.pull_request) ? num(issue.number) : undefined) ?? (pr ? num(payload.number) : undefined);
|
|
679
|
+
if (n !== undefined && n > 0)
|
|
680
|
+
out.pr = n;
|
|
681
|
+
const head = pr && isObject(pr.head) ? str(pr.head.sha) : undefined;
|
|
682
|
+
if (head)
|
|
683
|
+
out.sha = head;
|
|
684
|
+
}
|
|
685
|
+
if (out.pr === undefined) {
|
|
686
|
+
const m = /^refs\/pull\/(\d+)\/(?:merge|head)$/.exec(ref ?? "");
|
|
687
|
+
if (m)
|
|
688
|
+
out.pr = Number(m[1]);
|
|
689
|
+
}
|
|
690
|
+
return out;
|
|
691
|
+
}
|
|
692
|
+
/**
|
|
693
|
+
* Where a CI job posts, read from its environment: the forge
|
|
694
|
+
* ({@link detectForge} unless `kind` is given), the repository, the REST
|
|
695
|
+
* base, the host, the token, and the pull request and its head commit when
|
|
696
|
+
* the run has them. Throws {@link ForgeEnvironmentError} naming every
|
|
697
|
+
* missing piece.
|
|
698
|
+
*
|
|
699
|
+
* - GitHub Actions: `GITHUB_REPOSITORY`, `GITHUB_API_URL` (default
|
|
700
|
+
* `https://api.github.com`), `GITHUB_SERVER_URL`; the pull request from
|
|
701
|
+
* the event payload at `GITHUB_EVENT_PATH` or `refs/pull/<n>/` in
|
|
702
|
+
* `GITHUB_REF`, its head from the payload, else `GITHUB_SHA`.
|
|
703
|
+
* - Forgejo Actions: the same, with `FORGEJO_*` read before `GITHUB_*`,
|
|
704
|
+
* and the REST base `<server>/api/v1` when no API URL is set.
|
|
705
|
+
* - GitLab CI: `CI_API_V4_URL` (or `CI_SERVER_URL/api/v4`), the merge
|
|
706
|
+
* request's project before the pipeline's (a fork's merge request runs in
|
|
707
|
+
* the fork), `CI_MERGE_REQUEST_IID`, `CI_COMMIT_SHA`, `CI_PIPELINE_URL`.
|
|
708
|
+
*
|
|
709
|
+
* The token is read in {@link FORGE_TOKEN_ORDER}, or from `tokenEnv` alone.
|
|
710
|
+
*/
|
|
711
|
+
export function forgeTargetFromEnv(env = process.env, opts = {}) {
|
|
712
|
+
const kind = opts.kind ?? detectForge(env);
|
|
713
|
+
if (!kind)
|
|
714
|
+
throw new ForgeEnvironmentError(undefined, []);
|
|
715
|
+
const pick = (...names) => names.map((n) => env[n]?.trim()).find((v) => v !== undefined && v !== "");
|
|
716
|
+
const names = opts.tokenEnv ? [opts.tokenEnv] : FORGE_TOKEN_ORDER[kind];
|
|
717
|
+
const tokenSource = names.find((n) => env[n]?.trim());
|
|
718
|
+
const token = tokenSource ? env[tokenSource].trim() : undefined;
|
|
719
|
+
const missing = [];
|
|
720
|
+
const tokenMissing = `a token (${names.join(", ")})`;
|
|
721
|
+
if (kind === "gitlab") {
|
|
722
|
+
const server = pick("CI_SERVER_URL")?.replace(/\/+$/, "");
|
|
723
|
+
const apiBase = pick("CI_API_V4_URL")?.replace(/\/+$/, "") ?? (server ? `${server}/api/v4` : undefined);
|
|
724
|
+
const repo = pick("CI_MERGE_REQUEST_PROJECT_ID", "CI_PROJECT_ID", "CI_MERGE_REQUEST_PROJECT_PATH", "CI_PROJECT_PATH");
|
|
725
|
+
const iid = num(pick("CI_MERGE_REQUEST_IID"));
|
|
726
|
+
if (!apiBase)
|
|
727
|
+
missing.push("CI_API_V4_URL");
|
|
728
|
+
if (!repo)
|
|
729
|
+
missing.push("CI_PROJECT_ID");
|
|
730
|
+
if (opts.requirePr && !iid)
|
|
731
|
+
missing.push("CI_MERGE_REQUEST_IID (a merge request pipeline)");
|
|
732
|
+
if (!token)
|
|
733
|
+
missing.push(tokenMissing);
|
|
734
|
+
if (missing.length > 0)
|
|
735
|
+
throw new ForgeEnvironmentError(kind, missing);
|
|
736
|
+
const sha = pick("CI_MERGE_REQUEST_SOURCE_BRANCH_SHA", "CI_COMMIT_SHA");
|
|
737
|
+
const runUrl = pick("CI_PIPELINE_URL");
|
|
738
|
+
return {
|
|
739
|
+
kind,
|
|
740
|
+
apiBase: apiBase,
|
|
741
|
+
repo: repo,
|
|
742
|
+
host: pick("CI_SERVER_HOST")?.toLowerCase() ?? hostOf(server) ?? hostOf(apiBase) ?? "gitlab.com",
|
|
743
|
+
token: token,
|
|
744
|
+
tokenSource: tokenSource,
|
|
745
|
+
tokenHeader: tokenSource === "CI_JOB_TOKEN" ? "JOB-TOKEN" : "PRIVATE-TOKEN",
|
|
746
|
+
...(iid ? { pr: iid } : {}),
|
|
747
|
+
...(sha ? { sha } : {}),
|
|
748
|
+
...(runUrl ? { runUrl } : {}),
|
|
749
|
+
};
|
|
750
|
+
}
|
|
751
|
+
const fj = kind === "forgejo";
|
|
752
|
+
const read = (name) => (fj ? pick(`FORGEJO_${name}`, `GITHUB_${name}`) : pick(`GITHUB_${name}`));
|
|
753
|
+
const repo = read("REPOSITORY");
|
|
754
|
+
const server = read("SERVER_URL")?.replace(/\/+$/, "");
|
|
755
|
+
const apiBase = read("API_URL")?.replace(/\/+$/, "") ?? (fj ? (server ? `${server}/api/v1` : undefined) : "https://api.github.com");
|
|
756
|
+
let event;
|
|
757
|
+
const eventPath = read("EVENT_PATH");
|
|
758
|
+
if (eventPath) {
|
|
759
|
+
try {
|
|
760
|
+
event = JSON.parse((opts.readFile ?? ((p) => readFileSync(p, "utf8")))(eventPath));
|
|
761
|
+
}
|
|
762
|
+
catch {
|
|
763
|
+
// An unreadable payload is not fatal: the ref may still name the pull request.
|
|
764
|
+
event = undefined;
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
const { pr, sha: head } = prFromEvent(event, read("REF"));
|
|
768
|
+
if (!repo)
|
|
769
|
+
missing.push(fj ? "FORGEJO_REPOSITORY or GITHUB_REPOSITORY" : "GITHUB_REPOSITORY");
|
|
770
|
+
if (!apiBase)
|
|
771
|
+
missing.push("GITHUB_SERVER_URL or GITHUB_API_URL");
|
|
772
|
+
if (opts.requirePr && !pr)
|
|
773
|
+
missing.push("a pull request (a pull_request event, or refs/pull/<n>/ in GITHUB_REF)");
|
|
774
|
+
if (!token)
|
|
775
|
+
missing.push(tokenMissing);
|
|
776
|
+
if (missing.length > 0)
|
|
777
|
+
throw new ForgeEnvironmentError(kind, missing);
|
|
778
|
+
const sha = head ?? read("SHA");
|
|
779
|
+
const runId = read("RUN_ID");
|
|
780
|
+
const runUrl = server && runId ? `${server}/${repo}/actions/runs/${runId}` : undefined;
|
|
781
|
+
return {
|
|
782
|
+
kind,
|
|
783
|
+
apiBase: apiBase,
|
|
784
|
+
repo: repo,
|
|
785
|
+
host: hostOf(server) ?? (fj ? hostOf(apiBase) : "github.com"),
|
|
786
|
+
token: token,
|
|
787
|
+
tokenSource: tokenSource,
|
|
788
|
+
...(pr ? { pr } : {}),
|
|
789
|
+
...(sha ? { sha } : {}),
|
|
790
|
+
...(runUrl ? { runUrl } : {}),
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
/** The client for a {@link ForgeTarget}, from {@link forgeTargetFromEnv} or built by hand. */
|
|
794
|
+
export function forgeClient(target, fetchImpl) {
|
|
795
|
+
const f = fetchImpl ? { fetch: fetchImpl } : {};
|
|
796
|
+
const run = target.runUrl ? { runUrl: target.runUrl } : {};
|
|
797
|
+
if (target.kind === "gitlab") {
|
|
798
|
+
return gitlabForge({
|
|
799
|
+
apiBase: target.apiBase,
|
|
800
|
+
project: target.repo,
|
|
801
|
+
token: target.token,
|
|
802
|
+
host: target.host,
|
|
803
|
+
...(target.tokenHeader ? { tokenHeader: target.tokenHeader } : {}),
|
|
804
|
+
...run,
|
|
805
|
+
...f,
|
|
806
|
+
});
|
|
807
|
+
}
|
|
808
|
+
const opts = { apiBase: target.apiBase, repo: target.repo, token: target.token, host: target.host, ...run, ...f };
|
|
809
|
+
return target.kind === "forgejo" ? forgejoForge(opts) : githubForge(opts);
|
|
810
|
+
}
|