@intentius/chant 0.101.0 → 0.104.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/checks.d.ts.map +1 -1
- package/dist/attrref.d.ts.map +1 -1
- package/dist/audit/core.d.ts +2 -0
- package/dist/audit/core.d.ts.map +1 -1
- package/dist/audit/discover.d.ts.map +1 -1
- package/dist/audit/nginx.d.ts.map +1 -1
- package/dist/audit/prior-art.d.ts +48 -0
- package/dist/audit/prior-art.d.ts.map +1 -1
- package/dist/behaviour-kinds.d.ts.map +1 -1
- package/dist/builder.d.ts.map +1 -1
- package/dist/change-set.d.ts +232 -0
- package/dist/change-set.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +7 -0
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/carve-emit.d.ts.map +1 -1
- package/dist/cli/commands/check-lexicon.d.ts +16 -0
- package/dist/cli/commands/check-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/import.d.ts +8 -0
- package/dist/cli/commands/import.d.ts.map +1 -1
- package/dist/cli/commands/init-lexicon.d.ts.map +1 -1
- package/dist/cli/commands/init.d.ts +19 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/onboard.d.ts +9 -0
- package/dist/cli/commands/onboard.d.ts.map +1 -1
- package/dist/cli/commands/pinned-upgrade.d.ts +19 -5
- package/dist/cli/commands/pinned-upgrade.d.ts.map +1 -1
- package/dist/cli/handlers/build.d.ts.map +1 -1
- package/dist/cli/handlers/change-set.d.ts +11 -0
- package/dist/cli/handlers/change-set.d.ts.map +1 -0
- package/dist/cli/handlers/dev.d.ts.map +1 -1
- package/dist/cli/handlers/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/lifecycle.d.ts.map +1 -1
- package/dist/cli/handlers/misc.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +16 -0
- package/dist/cli/handlers/operator.d.ts.map +1 -1
- package/dist/cli/handlers/pr.d.ts +31 -0
- package/dist/cli/handlers/pr.d.ts.map +1 -0
- package/dist/cli/handlers/run.d.ts.map +1 -1
- package/dist/cli/lsp/server.d.ts.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/server.d.ts.map +1 -1
- package/dist/cli/mcp/tools/build.d.ts.map +1 -1
- package/dist/cli/mcp/tools/composites.d.ts.map +1 -1
- package/dist/cli/mcp/tools/explain.d.ts.map +1 -1
- package/dist/cli/mcp/tools/import.d.ts.map +1 -1
- package/dist/cli/mcp/tools/lint.d.ts.map +1 -1
- package/dist/cli/mcp/tools/scaffold.d.ts.map +1 -1
- package/dist/cli/mcp/tools/search.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +4 -3
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +74 -3
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/codegen/fetch.d.ts.map +1 -1
- package/dist/codegen/naming.d.ts.map +1 -1
- package/dist/codegen/pinned-upgrade.d.ts +67 -3
- package/dist/codegen/pinned-upgrade.d.ts.map +1 -1
- package/dist/codegen/registry.d.ts.map +1 -1
- package/dist/components/auto-release.d.ts +16 -0
- package/dist/components/auto-release.d.ts.map +1 -1
- package/dist/components/capability-plugin-loader.d.ts.map +1 -1
- package/dist/components/capability.d.ts +53 -0
- package/dist/components/capability.d.ts.map +1 -1
- package/dist/components/changed-files.d.ts +31 -0
- package/dist/components/changed-files.d.ts.map +1 -0
- package/dist/components/cli-support.d.ts +9 -1
- package/dist/components/cli-support.d.ts.map +1 -1
- package/dist/components/component.d.ts +24 -0
- package/dist/components/component.d.ts.map +1 -1
- package/dist/components/deploy-units.d.ts.map +1 -1
- package/dist/components/driver.d.ts +13 -0
- package/dist/components/driver.d.ts.map +1 -1
- package/dist/components/fan-out-output.d.ts +6 -0
- package/dist/components/fan-out-output.d.ts.map +1 -1
- package/dist/components/fan-out-record.d.ts +41 -0
- package/dist/components/fan-out-record.d.ts.map +1 -0
- package/dist/components/fan-out-run.d.ts +65 -0
- package/dist/components/fan-out-run.d.ts.map +1 -1
- package/dist/components/fan-out-support.d.ts +2 -0
- package/dist/components/fan-out-support.d.ts.map +1 -1
- package/dist/components/fan-out.d.ts +6 -0
- package/dist/components/fan-out.d.ts.map +1 -1
- package/dist/components/gated-wave-pipeline.d.ts +50 -0
- package/dist/components/gated-wave-pipeline.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/layers.d.ts +25 -0
- package/dist/components/layers.d.ts.map +1 -0
- package/dist/components/pr-pipeline.d.ts +61 -0
- package/dist/components/pr-pipeline.d.ts.map +1 -0
- package/dist/components/pr-run.d.ts +119 -0
- package/dist/components/pr-run.d.ts.map +1 -0
- package/dist/components/promote.d.ts.map +1 -1
- package/dist/components/starter-plugin.d.ts.map +1 -1
- package/dist/components/verbs/process-runner.d.ts.map +1 -1
- package/dist/components/verbs/r2-sync.d.ts.map +1 -1
- package/dist/components/verbs/run-agent.d.ts.map +1 -1
- package/dist/components/verbs/sbom-generator.d.ts.map +1 -1
- package/dist/components/verbs/shell.d.ts.map +1 -1
- package/dist/components/verbs/sign.d.ts.map +1 -1
- package/dist/components/verbs/verify.d.ts.map +1 -1
- package/dist/components/verbs/vuln-gate.d.ts.map +1 -1
- package/dist/components/verbs/vuln-scan.d.ts.map +1 -1
- package/dist/components/verbs/wrangler.d.ts.map +1 -1
- package/dist/components/wave-plan.d.ts +49 -0
- package/dist/components/wave-plan.d.ts.map +1 -0
- package/dist/composite.d.ts.map +1 -1
- package/dist/config.d.ts +19 -7
- package/dist/config.d.ts.map +1 -1
- package/dist/declarable.d.ts +16 -0
- package/dist/declarable.d.ts.map +1 -1
- package/dist/discovery/cache.d.ts.map +1 -1
- package/dist/discovery/fold-import.d.ts +15 -5
- package/dist/discovery/fold-import.d.ts.map +1 -1
- package/dist/discovery/param-deps.d.ts +16 -0
- package/dist/discovery/param-deps.d.ts.map +1 -1
- package/dist/discovery/sandbox/policy-wire.d.ts.map +1 -1
- package/dist/discovery/specifier-resolve.d.ts +37 -0
- package/dist/discovery/specifier-resolve.d.ts.map +1 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/fold/fold.d.ts +3 -1
- package/dist/fold/fold.d.ts.map +1 -1
- package/dist/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/graph-detail.d.ts.map +1 -1
- package/dist/graph-ir.d.ts.map +1 -1
- package/dist/graph-layout.d.ts.map +1 -1
- package/dist/import/base-parser.d.ts.map +1 -1
- package/dist/import/embedded.d.ts +7 -0
- package/dist/import/embedded.d.ts.map +1 -1
- package/dist/import/parser-options.d.ts +14 -0
- package/dist/import/parser-options.d.ts.map +1 -0
- package/dist/import/parser.d.ts +17 -0
- package/dist/import/parser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/kubectl-context.d.ts.map +1 -1
- package/dist/lexicon-output.d.ts.map +1 -1
- package/dist/lexicon-schema.d.ts +3 -3
- package/dist/lexicon.d.ts +103 -3
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/assert-live.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +22 -0
- package/dist/lifecycle/gate-ledger.d.ts.map +1 -1
- package/dist/lifecycle/git.d.ts +46 -1
- package/dist/lifecycle/git.d.ts.map +1 -1
- package/dist/lifecycle/member-ledger.d.ts.map +1 -1
- package/dist/lifecycle/observe.d.ts.map +1 -1
- package/dist/lifecycle/plan-ledger.d.ts.map +1 -1
- package/dist/lifecycle/release-ledger.d.ts.map +1 -1
- package/dist/lifecycle/scenario.d.ts.map +1 -1
- package/dist/lifecycle/status.d.ts.map +1 -1
- package/dist/lifecycle/work-lease.d.ts +61 -2
- package/dist/lifecycle/work-lease.d.ts.map +1 -1
- package/dist/lint/config.d.ts +8 -8
- package/dist/lint/engine.d.ts +6 -0
- package/dist/lint/engine.d.ts.map +1 -1
- package/dist/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/lsp/lexicon-providers.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +137 -11
- package/dist/op/activities/activity-contracts.d.ts.map +1 -1
- package/dist/op/activities/apply.d.ts +79 -9
- package/dist/op/activities/apply.d.ts.map +1 -1
- package/dist/op/activities/change-set.d.ts +62 -0
- package/dist/op/activities/change-set.d.ts.map +1 -0
- package/dist/op/activities/decide.d.ts +2 -0
- package/dist/op/activities/decide.d.ts.map +1 -1
- package/dist/op/activities/factory.d.ts +137 -0
- package/dist/op/activities/factory.d.ts.map +1 -0
- package/dist/op/activities/index.d.ts +5 -1
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activities/lexicon-upgrade.d.ts +44 -12
- package/dist/op/activities/lexicon-upgrade.d.ts.map +1 -1
- package/dist/op/activity-contract.d.ts +1 -1
- package/dist/op/activity-contract.d.ts.map +1 -1
- package/dist/op/activity-failure.d.ts.map +1 -1
- package/dist/op/activity-profiles.d.ts.map +1 -1
- package/dist/op/builders.d.ts +11 -0
- package/dist/op/builders.d.ts.map +1 -1
- package/dist/op/composites/apply-op.d.ts +12 -5
- package/dist/op/composites/apply-op.d.ts.map +1 -1
- package/dist/op/composites/lexicon-upgrade-op.d.ts +22 -6
- package/dist/op/composites/lexicon-upgrade-op.d.ts.map +1 -1
- package/dist/op/decide-backend.d.ts +5 -1
- package/dist/op/decide-backend.d.ts.map +1 -1
- package/dist/op/decide-read-inputs.d.ts +4 -2
- package/dist/op/decide-read-inputs.d.ts.map +1 -1
- package/dist/op/emulator-lifecycle.d.ts +21 -2
- package/dist/op/emulator-lifecycle.d.ts.map +1 -1
- package/dist/op/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/gate-approval.d.ts +5 -1
- package/dist/op/gate-approval.d.ts.map +1 -1
- package/dist/op/gate-wait.d.ts.map +1 -1
- package/dist/op/gate.d.ts +19 -3
- package/dist/op/gate.d.ts.map +1 -1
- package/dist/op/index.d.ts +6 -1
- package/dist/op/index.d.ts.map +1 -1
- package/dist/op/local-executor.d.ts +6 -0
- package/dist/op/local-executor.d.ts.map +1 -1
- package/dist/op/op-ir.d.ts +2 -0
- package/dist/op/op-ir.d.ts.map +1 -1
- package/dist/op/op-verb-class.d.ts.map +1 -1
- package/dist/op/operator.d.ts.map +1 -1
- package/dist/op/run-context.d.ts +39 -0
- package/dist/op/run-context.d.ts.map +1 -0
- package/dist/op/run-live.d.ts.map +1 -1
- package/dist/op/runtimes/local.d.ts.map +1 -1
- package/dist/op/source-archive.d.ts.map +1 -1
- package/dist/op/steward-beside.d.ts.map +1 -1
- package/dist/op/steward-points.d.ts.map +1 -1
- package/dist/op/steward.d.ts.map +1 -1
- package/dist/op/types.d.ts +16 -3
- package/dist/op/types.d.ts.map +1 -1
- package/dist/op/work-lease-run.d.ts +24 -4
- package/dist/op/work-lease-run.d.ts.map +1 -1
- package/dist/plan-summary.d.ts +207 -0
- package/dist/plan-summary.d.ts.map +1 -0
- package/dist/pr-forge.d.ts +105 -0
- package/dist/pr-forge.d.ts.map +1 -0
- package/dist/pr-loop.d.ts +178 -0
- package/dist/pr-loop.d.ts.map +1 -0
- package/dist/project-root.d.ts.map +1 -1
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -1
- package/dist/pseudo-parameter.d.ts.map +1 -1
- package/dist/reconcile.d.ts.map +1 -1
- package/dist/secret-materialization.d.ts.map +1 -1
- package/dist/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.d.ts.map +1 -1
- package/dist/terraform/emit-source.d.ts.map +1 -1
- package/dist/terraform/hcl2json.d.ts +45 -0
- package/dist/terraform/hcl2json.d.ts.map +1 -0
- package/dist/terraform/parse.d.ts +4 -40
- package/dist/terraform/parse.d.ts.map +1 -1
- package/dist/testing.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/contract-repo.d.ts.map +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts +1 -1
- package/dist/workspace/__fixtures__/decide-workspace.d.ts.map +1 -1
- package/dist/workspace/agent-cli.d.ts +5 -0
- package/dist/workspace/agent-cli.d.ts.map +1 -1
- package/dist/workspace/box-cli.d.ts +12 -0
- package/dist/workspace/box-cli.d.ts.map +1 -0
- package/dist/workspace/box-factory.d.ts +97 -0
- package/dist/workspace/box-factory.d.ts.map +1 -0
- package/dist/workspace/box-listing.d.ts +85 -0
- package/dist/workspace/box-listing.d.ts.map +1 -0
- package/dist/workspace/box-publish.d.ts +147 -0
- package/dist/workspace/box-publish.d.ts.map +1 -0
- package/dist/workspace/broker-protocol.d.ts +190 -0
- package/dist/workspace/broker-protocol.d.ts.map +1 -0
- package/dist/workspace/changes.d.ts.map +1 -1
- package/dist/workspace/chant-migrations/chud-lexicon-exit.d.ts.map +1 -1
- package/dist/workspace/checks/boxes.d.ts.map +1 -1
- package/dist/workspace/checks.d.ts +5 -0
- package/dist/workspace/checks.d.ts.map +1 -1
- package/dist/workspace/compose-graph.d.ts +10 -0
- package/dist/workspace/compose-graph.d.ts.map +1 -1
- package/dist/workspace/composites.d.ts +2 -2
- package/dist/workspace/composites.d.ts.map +1 -1
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts +17 -0
- package/dist/workspace/conformance/__fixtures__/reference-broker.d.ts.map +1 -0
- package/dist/workspace/conformance/broker.d.ts +202 -0
- package/dist/workspace/conformance/broker.d.ts.map +1 -0
- package/dist/workspace/conformance/index.d.ts +68 -6
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +19 -3
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +462 -0
- package/dist/workspace/conformance/writer.d.ts.map +1 -0
- package/dist/workspace/decide.d.ts +126 -12
- package/dist/workspace/decide.d.ts.map +1 -1
- package/dist/workspace/decision-points.schema.json +11 -4
- package/dist/workspace/declaration.d.ts +156 -4
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +383 -5
- package/dist/workspace/environments.d.ts +36 -10
- package/dist/workspace/environments.d.ts.map +1 -1
- package/dist/workspace/factory-rules.d.ts +180 -0
- package/dist/workspace/factory-rules.d.ts.map +1 -0
- package/dist/workspace/generated-files.d.ts.map +1 -1
- package/dist/workspace/graph-cache.d.ts.map +1 -1
- package/dist/workspace/graph-cli.d.ts +2 -0
- package/dist/workspace/graph-cli.d.ts.map +1 -1
- package/dist/workspace/identity.d.ts +111 -0
- package/dist/workspace/identity.d.ts.map +1 -0
- package/dist/workspace/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +7 -4
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +36 -2
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +249 -8
- package/dist/workspace/intent.d.ts.map +1 -1
- package/dist/workspace/json-edit.d.ts +24 -0
- package/dist/workspace/json-edit.d.ts.map +1 -0
- package/dist/workspace/jsonc.d.ts +11 -0
- package/dist/workspace/jsonc.d.ts.map +1 -1
- package/dist/workspace/kinds.d.ts +66 -4
- package/dist/workspace/kinds.d.ts.map +1 -1
- package/dist/workspace/lexicon-symbols.d.ts +29 -0
- package/dist/workspace/lexicon-symbols.d.ts.map +1 -0
- package/dist/workspace/lineage-hash-index.d.ts.map +1 -1
- package/dist/workspace/lineage-lock.d.ts +2 -2
- package/dist/workspace/lineage-lock.d.ts.map +1 -1
- package/dist/workspace/lineage-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.d.ts.map +1 -1
- package/dist/workspace/links.d.ts.map +1 -1
- package/dist/workspace/point-answer.schema.json +42 -2
- package/dist/workspace/points-cli.d.ts +10 -3
- package/dist/workspace/points-cli.d.ts.map +1 -1
- package/dist/workspace/points.d.ts +66 -5
- package/dist/workspace/points.d.ts.map +1 -1
- package/dist/workspace/principal-classes.d.ts +114 -0
- package/dist/workspace/principal-classes.d.ts.map +1 -0
- package/dist/workspace/reason-codes.d.ts +53 -4
- package/dist/workspace/reason-codes.d.ts.map +1 -1
- package/dist/workspace/record-assets.d.ts.map +1 -1
- package/dist/workspace/record-sessions.d.ts +5 -7
- package/dist/workspace/record-sessions.d.ts.map +1 -1
- package/dist/workspace/records-checkout.d.ts +54 -0
- package/dist/workspace/records-checkout.d.ts.map +1 -0
- package/dist/workspace/records-cli.d.ts +34 -1
- package/dist/workspace/records-cli.d.ts.map +1 -1
- package/dist/workspace/records-close.d.ts +7 -3
- package/dist/workspace/records-close.d.ts.map +1 -1
- package/dist/workspace/records-since.d.ts.map +1 -1
- package/dist/workspace/records-write.d.ts +68 -7
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +43 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +296 -0
- package/dist/workspace/runs-cli.d.ts.map +1 -0
- package/dist/workspace/runs.d.ts +544 -0
- package/dist/workspace/runs.d.ts.map +1 -0
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.d.ts.map +1 -1
- package/dist/workspace/source-block.d.ts +1 -1
- package/dist/workspace/source-block.d.ts.map +1 -1
- package/dist/workspace/squash.d.ts +80 -0
- package/dist/workspace/squash.d.ts.map +1 -0
- package/dist/workspace/status-gates.d.ts +17 -3
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +64 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +63 -0
- package/dist/workspace/symbols.d.ts.map +1 -0
- package/dist/workspace/trailer-joins.d.ts +46 -0
- package/dist/workspace/trailer-joins.d.ts.map +1 -0
- package/dist/workspace/trailers.d.ts +89 -0
- package/dist/workspace/trailers.d.ts.map +1 -0
- package/dist/workspace/trust/attestor.d.ts.map +1 -1
- package/dist/workspace/trust/rotation.d.ts.map +1 -1
- package/dist/workspace/trust/run-commits.d.ts +46 -0
- package/dist/workspace/trust/run-commits.d.ts.map +1 -0
- package/dist/workspace/trust/run-statement.d.ts +128 -0
- package/dist/workspace/trust/run-statement.d.ts.map +1 -0
- package/dist/workspace/trust/seal.d.ts +38 -0
- package/dist/workspace/trust/seal.d.ts.map +1 -1
- package/dist/workspace/trust/test-repo.d.ts.map +1 -1
- package/dist/workspace/trust/verify-cli.d.ts +1 -1
- package/dist/workspace/trust/verify.d.ts +16 -2
- package/dist/workspace/trust/verify.d.ts.map +1 -1
- package/dist/workspace/wip-cli.d.ts +21 -0
- package/dist/workspace/wip-cli.d.ts.map +1 -0
- package/dist/workspace/wip.d.ts +268 -0
- package/dist/workspace/wip.d.ts.map +1 -0
- package/dist/workspace/work-cli.d.ts +39 -3
- package/dist/workspace/work-cli.d.ts.map +1 -1
- package/dist/workspace/work-evidence.d.ts +1 -1
- package/dist/workspace/work-evidence.d.ts.map +1 -1
- package/dist/workspace/work-size.d.ts +55 -0
- package/dist/workspace/work-size.d.ts.map +1 -0
- package/dist/workspace/work.d.ts +26 -1
- package/dist/workspace/work.d.ts.map +1 -1
- package/dist/workspace/workspace-kinds.schema.json +122 -0
- package/dist/workspace/workspace-principals.schema.json +60 -0
- package/dist/workspace/write-lock-cli.d.ts +60 -0
- package/dist/workspace/write-lock-cli.d.ts.map +1 -0
- package/dist/workspace/write-lock.d.ts +152 -0
- package/dist/workspace/write-lock.d.ts.map +1 -0
- package/dist/workspace/write-scope.d.ts +83 -19
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +21 -39
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +7 -2
- package/src/__fixtures__/change-set/lifecycle-plan.floci.json +59 -0
- package/src/__fixtures__/change-set/lifecycle-v1.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle-v2.ts.txt +4 -0
- package/src/__fixtures__/change-set/lifecycle.change-set.golden.json +95 -0
- package/src/__fixtures__/change-set/warden.change-set.golden.json +106 -0
- package/src/__fixtures__/change-set/warden.plan.json +44 -0
- package/src/__fixtures__/plan-summary/normalization-vectors.json +1593 -0
- package/src/__fixtures__/pr-loop/pr-apply-applied.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-apply-refused.note.golden.md +31 -0
- package/src/__fixtures__/pr-loop/pr-plan.golden.json +127 -0
- package/src/__fixtures__/pr-loop/pr-plan.note.golden.md +37 -0
- package/src/audit/core.test.ts +15 -0
- package/src/audit/core.ts +8 -2
- package/src/audit/discover.test.ts +11 -0
- package/src/audit/discover.ts +7 -2
- package/src/audit/prior-art.ts +15 -0
- package/src/change-set-bundle.test.ts +57 -0
- package/src/change-set.test.ts +215 -0
- package/src/change-set.ts +445 -0
- package/src/cli/commands/__fixtures__/init-lexicon-output/package.json +1 -1
- package/src/cli/commands/audit-opt-in.test.ts +54 -0
- package/src/cli/commands/audit.ts +29 -2
- package/src/cli/commands/build.test.ts +19 -0
- package/src/cli/commands/build.ts +3 -2
- package/src/cli/commands/carve-emit-state.test.ts +4 -0
- package/src/cli/commands/carve-emit.ts +5 -19
- package/src/cli/commands/check-lexicon.test.ts +62 -1
- package/src/cli/commands/check-lexicon.ts +36 -6
- package/src/cli/commands/import-live.test.ts +18 -0
- package/src/cli/commands/import-parser-options.test.ts +133 -0
- package/src/cli/commands/import.ts +21 -3
- package/src/cli/commands/init-lexicon/templates/project.ts +1 -1
- package/src/cli/commands/init.test.ts +8 -1
- package/src/cli/commands/init.ts +23 -8
- package/src/cli/commands/lint.test.ts +37 -0
- package/src/cli/commands/onboard.test.ts +53 -3
- package/src/cli/commands/onboard.ts +52 -4
- package/src/cli/commands/pinned-upgrade.ts +73 -33
- package/src/cli/handlers/__snapshots__/build-member.test.ts.snap +2 -2
- package/src/cli/handlers/build.ts +13 -1
- package/src/cli/handlers/change-set.test.ts +56 -0
- package/src/cli/handlers/change-set.ts +44 -0
- package/src/cli/handlers/components.ts +2 -2
- package/src/cli/handlers/dev.ts +8 -6
- package/src/cli/handlers/fan-out.test.ts +221 -2
- package/src/cli/handlers/fan-out.ts +165 -75
- package/src/cli/handlers/graph.ts +3 -0
- package/src/cli/handlers/lifecycle.test.ts +67 -0
- package/src/cli/handlers/lifecycle.ts +6 -5
- package/src/cli/handlers/misc.ts +2 -0
- package/src/cli/handlers/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +121 -6
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.test.ts +111 -0
- package/src/cli/handlers/run.ts +86 -24
- package/src/cli/handlers/scenario.ts +2 -2
- package/src/cli/main.test.ts +21 -0
- package/src/cli/main.ts +246 -30
- package/src/cli/mcp/never-over-mcp.test.ts +101 -0
- package/src/cli/mcp/op-tools.ts +24 -2
- package/src/cli/mcp/workspace-tools.test.ts +5 -2
- package/src/cli/mcp/workspace-tools.ts +62 -7
- package/src/cli/registry.ts +74 -3
- package/src/codegen/pinned-upgrade-multi.test.ts +157 -0
- package/src/codegen/pinned-upgrade-tags.test.ts +112 -0
- package/src/codegen/pinned-upgrade.test.ts +104 -0
- package/src/codegen/pinned-upgrade.ts +250 -56
- package/src/codegen/testdata/postgres-tags.json +242 -0
- package/src/components/auto-release.ts +1 -1
- package/src/components/capability.ts +55 -0
- package/src/components/changed-files.ts +66 -0
- package/src/components/cli-support.ts +28 -5
- package/src/components/component.schema.json +17 -0
- package/src/components/component.ts +25 -0
- package/src/components/deploy-units.ts +3 -0
- package/src/components/driver.test.ts +52 -0
- package/src/components/driver.ts +31 -13
- package/src/components/fan-out-output.ts +42 -1
- package/src/components/fan-out-record.ts +69 -0
- package/src/components/fan-out-run.test.ts +17 -0
- package/src/components/fan-out-run.ts +304 -1
- package/src/components/fan-out-support.ts +3 -0
- package/src/components/fan-out-waves.test.ts +375 -0
- package/src/components/fan-out.ts +18 -17
- package/src/components/gated-wave-pipeline.ts +82 -0
- package/src/components/index.ts +1 -0
- package/src/components/layers.ts +30 -0
- package/src/components/pr-pipeline.ts +91 -0
- package/src/components/pr-run.test.ts +205 -0
- package/src/components/pr-run.ts +280 -0
- package/src/components/promote.ts +5 -0
- package/src/components/verbs/shell.test.ts +11 -0
- package/src/components/verbs/shell.ts +7 -3
- package/src/components/wave-plan.ts +124 -0
- package/src/config.test.ts +21 -0
- package/src/config.ts +15 -0
- package/src/declarable.test.ts +21 -0
- package/src/declarable.ts +19 -0
- package/src/discovery/fold-composite.test.ts +41 -5
- package/src/discovery/fold-import.test.ts +129 -0
- package/src/discovery/fold-import.ts +643 -131
- package/src/discovery/fold-package-composite.test.ts +264 -0
- package/src/discovery/fold-specifiers.test.ts +191 -0
- package/src/discovery/param-deps.test.ts +66 -1
- package/src/discovery/param-deps.ts +45 -0
- package/src/discovery/sandbox/bundle.ts +1 -1
- package/src/discovery/specifier-resolve.ts +344 -0
- package/src/fold/fold.test.ts +39 -1
- package/src/fold/fold.ts +83 -9
- package/src/fold-provenance.test.ts +140 -0
- package/src/gated-waves-bundle.test.ts +62 -0
- package/src/gated-waves.test.ts +118 -0
- package/src/gated-waves.ts +240 -0
- package/src/graph-ir.test.ts +83 -0
- package/src/graph-ir.ts +29 -0
- package/src/import/embedded.test.ts +20 -0
- package/src/import/embedded.ts +13 -0
- package/src/import/parser-options.ts +46 -0
- package/src/import/parser.ts +20 -0
- package/src/index.ts +1 -0
- package/src/lexicon.ts +106 -3
- package/src/lifecycle/gate-ledger.ts +23 -0
- package/src/lifecycle/git.ts +102 -16
- package/src/lifecycle/observe.test.ts +18 -0
- package/src/lifecycle/observe.ts +6 -4
- package/src/lifecycle/snapshot.ts +2 -2
- package/src/lifecycle/work-lease.test.ts +1 -1
- package/src/lifecycle/work-lease.ts +93 -2
- package/src/lint/engine.test.ts +55 -0
- package/src/lint/engine.ts +30 -4
- package/src/lint/output-docs.test.ts +59 -56
- package/src/lint/post-synth.test.ts +19 -0
- package/src/lint/post-synth.ts +19 -1
- package/src/meta/declared-imports.test.ts +1 -1
- package/src/op/activities/activity-contracts.ts +84 -0
- package/src/op/activities/apply.test.ts +189 -5
- package/src/op/activities/apply.ts +230 -8
- package/src/op/activities/change-set.ts +114 -0
- package/src/op/activities/decide.ts +3 -0
- package/src/op/activities/factory.ts +675 -0
- package/src/op/activities/index.ts +9 -0
- package/src/op/activities/lexicon-upgrade.test.ts +160 -6
- package/src/op/activities/lexicon-upgrade.ts +154 -51
- package/src/op/activity-contract.test.ts +21 -1
- package/src/op/activity-contract.ts +19 -9
- package/src/op/builders.ts +23 -0
- package/src/op/composites/apply-op.ts +12 -5
- package/src/op/composites/composites.test.ts +30 -3
- package/src/op/composites/lexicon-upgrade-op.test.ts +7 -2
- package/src/op/composites/lexicon-upgrade-op.ts +29 -8
- package/src/op/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/emulator-lifecycle.test.ts +23 -0
- package/src/op/emulator-lifecycle.ts +52 -14
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/gate-approval.test.ts +74 -0
- package/src/op/gate-approval.ts +5 -1
- package/src/op/gate.ts +31 -5
- package/src/op/index.ts +11 -1
- package/src/op/local-executor.test.ts +15 -0
- package/src/op/local-executor.ts +40 -12
- package/src/op/local-output.ts +1 -1
- package/src/op/op-ir.test.ts +9 -0
- package/src/op/op-ir.ts +4 -0
- package/src/op/op-verb-class.ts +3 -0
- package/src/op/operator.ts +4 -0
- package/src/op/run-context.test.ts +141 -0
- package/src/op/run-context.ts +51 -0
- package/src/op/runtimes/local.test.ts +14 -0
- package/src/op/runtimes/local.ts +2 -0
- package/src/op/steward-beside.ts +2 -0
- package/src/op/types.ts +16 -3
- package/src/op/work-lease-run.test.ts +47 -0
- package/src/op/work-lease-run.ts +76 -11
- package/src/plan-summary.test.ts +263 -0
- package/src/plan-summary.ts +845 -0
- package/src/pr-forge.test.ts +237 -0
- package/src/pr-forge.ts +332 -0
- package/src/pr-loop-bundle.test.ts +46 -0
- package/src/pr-loop.test.ts +171 -0
- package/src/pr-loop.ts +324 -0
- package/src/provenance.ts +35 -0
- package/src/telemetry-attribution.test.ts +23 -1
- package/src/telemetry-attribution.ts +51 -0
- package/src/terraform/hcl2json.test.ts +21 -0
- package/src/terraform/hcl2json.ts +81 -0
- package/src/terraform/parse.ts +11 -74
- package/src/workspace/agent-cli.ts +7 -3
- package/src/workspace/agent.schema.json +22 -0
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +323 -0
- package/src/workspace/box-factory.ts +136 -0
- package/src/workspace/box-listing-write.schema.json +204 -0
- package/src/workspace/box-listing.test.ts +234 -0
- package/src/workspace/box-listing.ts +324 -0
- package/src/workspace/box-publish.schema.json +498 -0
- package/src/workspace/box-publish.test.ts +204 -0
- package/src/workspace/box-publish.ts +420 -0
- package/src/workspace/box-ship.test.ts +96 -0
- package/src/workspace/broker-protocol.schema.json +186 -0
- package/src/workspace/broker-protocol.test.ts +122 -0
- package/src/workspace/broker-protocol.ts +317 -0
- package/src/workspace/builder-tiers.test.ts +146 -0
- package/src/workspace/change-set.schema.json +460 -0
- package/src/workspace/changes.schema.json +12 -20
- package/src/workspace/changes.ts +4 -1
- package/src/workspace/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +5 -0
- package/src/workspace/checks.ts +39 -8
- package/src/workspace/component-environments.test.ts +105 -0
- package/src/workspace/compose-graph.ts +7 -0
- package/src/workspace/composites.schema.json +23 -4
- package/src/workspace/composites.test.ts +8 -8
- package/src/workspace/composites.ts +13 -2
- package/src/workspace/conformance/__fixture__/decisions/decision.schema.json +2 -2
- package/src/workspace/conformance/__fixtures__/reference-broker.ts +207 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.kind.mjs +32 -0
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +135 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.kind.mjs +37 -0
- package/src/workspace/conformance/__writer_fixture__/contracts/contract.schema.json +213 -0
- package/src/workspace/conformance/__writer_fixture__/decisions/points.json +228 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.kind.mjs +15 -0
- package/src/workspace/conformance/__writer_fixture__/drivers/driver.schema.json +38 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.kind.mjs +54 -0
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +289 -0
- package/src/workspace/conformance/__writer_fixture__/work/W-001-the-writer-suite-works-this-item.md +25 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.kind.mjs +60 -0
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +603 -0
- package/src/workspace/conformance/broker.test.ts +122 -0
- package/src/workspace/conformance/broker.ts +792 -0
- package/src/workspace/conformance/conformance.e2e.test.ts +36 -3
- package/src/workspace/conformance/index.mjs +51 -3
- package/src/workspace/conformance/index.ts +107 -15
- package/src/workspace/conformance/vitest.ts +76 -2
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +177 -0
- package/src/workspace/conformance/writer.test.ts +186 -0
- package/src/workspace/conformance/writer.ts +1191 -0
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +433 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +383 -5
- package/src/workspace/declaration.ts +315 -10
- package/src/workspace/environments.ts +66 -14
- package/src/workspace/factory-rules.test.ts +62 -0
- package/src/workspace/factory-rules.ts +218 -0
- package/src/workspace/graph-cli.ts +6 -3
- package/src/workspace/graph.schema.json +314 -0
- package/src/workspace/identity.test.ts +219 -0
- package/src/workspace/identity.ts +186 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +84 -13
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +336 -1
- package/src/workspace/intent-record.ts +96 -16
- package/src/workspace/intent-reviews.test.ts +76 -0
- package/src/workspace/intent-squash.test.ts +213 -0
- package/src/workspace/intent-why.test.ts +274 -0
- package/src/workspace/intent.schema.json +950 -9
- package/src/workspace/intent.test.ts +11 -2
- package/src/workspace/intent.ts +722 -65
- package/src/workspace/json-edit.test.ts +121 -0
- package/src/workspace/json-edit.ts +142 -0
- package/src/workspace/jsonc.ts +20 -0
- package/src/workspace/kinds.ts +201 -39
- package/src/workspace/lexicon-symbols.test.ts +148 -0
- package/src/workspace/lexicon-symbols.ts +125 -0
- package/src/workspace/lineage-upgrade.test.ts +63 -0
- package/src/workspace/lineage-upgrade.ts +146 -5
- package/src/workspace/plan-summary.schema.json +155 -0
- package/src/workspace/point-answer.schema.json +42 -2
- package/src/workspace/points-cli.ts +42 -16
- package/src/workspace/points-write.schema.json +163 -4
- package/src/workspace/points.schema.json +157 -2
- package/src/workspace/points.test.ts +13 -1
- package/src/workspace/points.ts +118 -12
- package/src/workspace/pr-report.schema.json +95 -0
- package/src/workspace/principal-classes.test.ts +175 -0
- package/src/workspace/principal-classes.ts +307 -0
- package/src/workspace/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +23 -3
- package/src/workspace/reason-codes.ts +61 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +80 -0
- package/src/workspace/records-checkout.ts +106 -0
- package/src/workspace/records-cli.ts +123 -17
- package/src/workspace/records-close.schema.json +79 -0
- package/src/workspace/records-close.ts +31 -7
- package/src/workspace/records-concurrent.e2e.test.ts +135 -0
- package/src/workspace/records-concurrent.test.ts +145 -0
- package/src/workspace/records-formats.test.ts +46 -10
- package/src/workspace/records-new.schema.json +9 -0
- package/src/workspace/records-review.schema.json +80 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-uncommitted.test.ts +171 -0
- package/src/workspace/records-write.ts +219 -30
- package/src/workspace/records.schema.json +88 -1
- package/src/workspace/records.ts +76 -8
- package/src/workspace/reference-kinds/app/package.json +10 -0
- package/src/workspace/reference-kinds/app/workspace-kinds.json +45 -0
- package/src/workspace/run-statement.schema.json +622 -0
- package/src/workspace/runs-cli.ts +710 -0
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +994 -0
- package/src/workspace/runs.schema.json +1257 -0
- package/src/workspace/runs.test.ts +281 -0
- package/src/workspace/runs.ts +970 -0
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +10 -2
- package/src/workspace/status-gates.ts +25 -9
- package/src/workspace/status.schema.json +252 -4
- package/src/workspace/status.ts +110 -1
- package/src/workspace/symbols.ts +191 -0
- package/src/workspace/trailer-joins.test.ts +171 -0
- package/src/workspace/trailer-joins.ts +82 -0
- package/src/workspace/trailers.ts +148 -0
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +58 -1
- package/src/workspace/trust/verify-cli.ts +6 -5
- package/src/workspace/trust/verify.ts +39 -6
- package/src/workspace/wip-cli.ts +97 -0
- package/src/workspace/wip-write.schema.json +504 -0
- package/src/workspace/wip.schema.json +334 -0
- package/src/workspace/wip.test.ts +294 -0
- package/src/workspace/wip.ts +753 -0
- package/src/workspace/work-cli.e2e.test.ts +28 -1
- package/src/workspace/work-cli.ts +136 -8
- package/src/workspace/work-evidence.schema.json +5 -0
- package/src/workspace/work-history.schema.json +73 -1
- package/src/workspace/work-history.test.ts +48 -5
- package/src/workspace/work-kind-fields.test.ts +154 -0
- package/src/workspace/work-lease.schema.json +14 -1
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/work.ts +82 -0
- package/src/workspace/workspace-kinds.schema.json +122 -0
- package/src/workspace/workspace-principals.schema.json +60 -0
- package/src/workspace/write-lock-cli.ts +131 -0
- package/src/workspace/write-lock.schema.json +172 -0
- package/src/workspace/write-lock.test.ts +189 -0
- package/src/workspace/write-lock.ts +474 -0
- package/src/workspace/write-scope.test.ts +144 -3
- package/src/workspace/write-scope.ts +192 -45
- package/src/yaml.test.ts +111 -1
- package/src/yaml.ts +141 -549
package/src/workspace/intent.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The intent graph over one region: `chant workspace graph --intent
|
|
3
|
-
* <path[:start-end]>` (#2651; #2650 sections B and C1; #2524 D8,
|
|
3
|
+
* <path[:start-end]|path#symbol>` (#2651; #2650 sections B and C1; #2524 D8,
|
|
4
|
+
* D15; #3034).
|
|
4
5
|
*
|
|
5
6
|
* A person points at some code and asks how it got this way and who decided
|
|
6
7
|
* it should be this way. This module gathers what the workspace records about
|
|
@@ -30,7 +31,30 @@
|
|
|
30
31
|
* record kind the declaration names (#2680), and each one's `commitJoins`
|
|
31
32
|
* runs for every commit in that order. chant emits the
|
|
32
33
|
* graph and hud renders it (#2524 D8, D15). Git is read through a local
|
|
33
|
-
* `git` subprocess only: no fetch, no network
|
|
34
|
+
* `git` subprocess only: no fetch, no network, except to follow a squash
|
|
35
|
+
* when asked (below).
|
|
36
|
+
*
|
|
37
|
+
* A region can name a symbol, `path#symbol`, which `symbols.ts` resolves to
|
|
38
|
+
* its current lines (#3034). For a file region the document also carries
|
|
39
|
+
* `why`: who made the region's current lines, from `git blame`, the agent run
|
|
40
|
+
* behind each (narrowed by the hunks a run recorded when several share a
|
|
41
|
+
* commit), and the decisions governing the region, most relevant first, with
|
|
42
|
+
* `explained: false` and closed gap codes when nothing accounts for it.
|
|
43
|
+
*
|
|
44
|
+
* A commit joins an agent run by its `Chant-Run` trailer or the run's own
|
|
45
|
+
* list of commits, and, failing both, by content (#3036): a commit whose
|
|
46
|
+
* `git patch-id --stable` equals one the run recorded, as after a rebase or a
|
|
47
|
+
* cherry-pick that dropped the trailer. Its `made-by` edge says `patch-id`,
|
|
48
|
+
* and a commit joined one way whose content matches another run's recorded
|
|
49
|
+
* commit is `intent-commit-join-conflict`.
|
|
50
|
+
*
|
|
51
|
+
* Asked to (`followSquash`, #3035), the walk follows a squash merge to its
|
|
52
|
+
* pull request's original commits (`squash.ts`): the squash commit node lists
|
|
53
|
+
* them with their trailers, joins and signatures, carries what their trailers
|
|
54
|
+
* and plugin joins carry, and joins their runs, marked `squash`. That is the
|
|
55
|
+
* one part of the walk that may reach the network, to fetch a pull request
|
|
56
|
+
* ref the clone lacks; a ref that can't be read is `squash-unfollowed` in
|
|
57
|
+
* `reasons`, and the walk keeps its answer without it.
|
|
34
58
|
*/
|
|
35
59
|
|
|
36
60
|
import { execFileSync } from "node:child_process";
|
|
@@ -48,6 +72,11 @@ import type { DecidedIn } from "./record-decided";
|
|
|
48
72
|
import { importKindModule, loadRecordKind, parseFrontMatter, RecordReadError, supersedesTargets, type LoadedRecordKind } from "./records";
|
|
49
73
|
import { queryRecords, type RecordView } from "./records-cli";
|
|
50
74
|
import { isPluginCode, type PluginCode, type ReasonCode } from "./reason-codes";
|
|
75
|
+
import { addSquashRuns, RUN_JOIN_ORDER, runsForCommits, type RunCost, type RunJoin, type RunPin, type RunUsage, type RunView } from "./runs";
|
|
76
|
+
import { followSquashes, squashLineOrigins, type Forge, type SquashFollow } from "./squash";
|
|
77
|
+
import { memberDirOnDisk, memberSymbolResolvers, type SymbolPluginLoader } from "./lexicon-symbols";
|
|
78
|
+
import { resolveSymbol, symbolResolverFor, type SymbolResolver } from "./symbols";
|
|
79
|
+
import { readTrailerJoins, type CommitTrailerJoins } from "./trailer-joins";
|
|
51
80
|
import { joinPath, skippedDir, type WorkspaceTree } from "./tree";
|
|
52
81
|
import { activeAttestors, type ProvenanceLevel } from "./trust/attestor";
|
|
53
82
|
import { commitProvenance, policyAtBase, resolveBase } from "./trust/provenance";
|
|
@@ -66,7 +95,7 @@ export const INTENT_OUTPUT_SCHEMA_ID = "https://intentius.io/chant/schemas/works
|
|
|
66
95
|
export const INTENT_FINDING_CODES = [
|
|
67
96
|
/** A commit touched the region when no decision constrained it at path granularity. */
|
|
68
97
|
"intent-commit-undecided",
|
|
69
|
-
/** A commit has no unit, no pull request reference and no decision covering the region at its time. */
|
|
98
|
+
/** A commit has no unit, carries no record through chant's trailers, has no pull request reference and no decision covering the region at its time. */
|
|
70
99
|
"intent-commit-bare",
|
|
71
100
|
/** A pinned artifact's bytes no longer hash to the pin. */
|
|
72
101
|
"intent-pin-drifted",
|
|
@@ -98,6 +127,8 @@ export const INTENT_FINDING_CODES = [
|
|
|
98
127
|
"intent-work-blocked",
|
|
99
128
|
/** Commits in the region are a decision's own work while the work item implementing it is still open: the code says done and the queue says not (#2683). */
|
|
100
129
|
"intent-work-open-decided-code",
|
|
130
|
+
/** A commit joined to an agent run by its trailer or the run's record has the patch-id of a commit another run recorded; the content join is not made (#3036). */
|
|
131
|
+
"intent-commit-join-conflict",
|
|
101
132
|
] as const satisfies readonly ReasonCode[];
|
|
102
133
|
export type IntentFindingCode = (typeof INTENT_FINDING_CODES)[number];
|
|
103
134
|
|
|
@@ -107,6 +138,8 @@ export const INTENT_REASON_CODES = [
|
|
|
107
138
|
"intent-history-shallow",
|
|
108
139
|
/** A plugin's commitJoins failed for a commit. */
|
|
109
140
|
"intent-plugin-failed",
|
|
141
|
+
/** A squash commit's pull request ref could not be read or fetched, so its original commits are not followed (#3035). */
|
|
142
|
+
"squash-unfollowed",
|
|
110
143
|
] as const satisfies readonly ReasonCode[];
|
|
111
144
|
export type IntentReasonCode = (typeof INTENT_REASON_CODES)[number];
|
|
112
145
|
|
|
@@ -123,9 +156,28 @@ export const INTENT_ERROR_CODES = [
|
|
|
123
156
|
"intent-region-invalid",
|
|
124
157
|
/** --record names an id no record of a decision kind read has. */
|
|
125
158
|
"intent-record-unknown",
|
|
159
|
+
/** The region names a symbol in a file no resolver reads (#3034). */
|
|
160
|
+
"intent-symbol-unsupported",
|
|
161
|
+
/** The region names a symbol the file does not declare (#3034). */
|
|
162
|
+
"intent-symbol-unknown",
|
|
163
|
+
/** The region names a symbol that matches more than one declaration (#3034). */
|
|
164
|
+
"intent-symbol-ambiguous",
|
|
126
165
|
] as const satisfies readonly ReasonCode[];
|
|
127
166
|
export type IntentErrorCode = (typeof INTENT_ERROR_CODES)[number];
|
|
128
167
|
|
|
168
|
+
/** Why `why` can't account for some or all of a region (#3034). Closed. */
|
|
169
|
+
export const INTENT_WHY_CODES = [
|
|
170
|
+
/** No current decision governs the region, at any granularity, and none is carried out by the commits or runs that made its lines. */
|
|
171
|
+
"intent-why-no-decision",
|
|
172
|
+
/** None of the region's current lines was made by a commit an agent run is joined to. */
|
|
173
|
+
"intent-why-no-run",
|
|
174
|
+
/** Some of the region's lines are not committed, so nothing made them yet. */
|
|
175
|
+
"intent-why-uncommitted",
|
|
176
|
+
/** Some lines come from a commit that several runs made, and no run's recorded hunks say which wrote them. */
|
|
177
|
+
"intent-why-run-ambiguous",
|
|
178
|
+
] as const satisfies readonly ReasonCode[];
|
|
179
|
+
export type IntentWhyCode = (typeof INTENT_WHY_CODES)[number];
|
|
180
|
+
|
|
129
181
|
export class IntentError extends Error {
|
|
130
182
|
constructor(
|
|
131
183
|
readonly code: IntentErrorCode,
|
|
@@ -157,6 +209,8 @@ export interface RegionNode {
|
|
|
157
209
|
generated: boolean | null;
|
|
158
210
|
/** Set when the region was given as a graph node id. */
|
|
159
211
|
node: string | null;
|
|
212
|
+
/** Set when the region was given as `path#symbol` (#3034): the symbol as given, the declaration it resolved to, and its kind. `lines` holds its current lines. */
|
|
213
|
+
symbol?: { name: string; qualified: string; kind: string } | null;
|
|
160
214
|
}
|
|
161
215
|
|
|
162
216
|
export interface FileNode {
|
|
@@ -196,6 +250,46 @@ export interface CommitNode {
|
|
|
196
250
|
* null when no record kind was read.
|
|
197
251
|
*/
|
|
198
252
|
state: CommitState | null;
|
|
253
|
+
/**
|
|
254
|
+
* What chant's own trailers join the commit to (#3149, ws-075): the agent
|
|
255
|
+
* session, the work lease and the item it was taken on, the agent run, the
|
|
256
|
+
* records it names and the apply it records. A record or a lease item that
|
|
257
|
+
* a kind read has is linked by a `carries` edge.
|
|
258
|
+
*/
|
|
259
|
+
joins: CommitTrailerJoins;
|
|
260
|
+
/**
|
|
261
|
+
* Set only when the walk follows squashes (#3035) and the commit squashes
|
|
262
|
+
* a pull request: its original commits, read from the forge's pull request
|
|
263
|
+
* ref. The commit carries what they carry and joins their runs.
|
|
264
|
+
*/
|
|
265
|
+
squash?: SquashNode;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** A squash commit's pull request, followed to its original commits (#3035). */
|
|
269
|
+
export interface SquashNode {
|
|
270
|
+
pullRequest: number;
|
|
271
|
+
/** The forge `origin` points at, or null for one chant doesn't know. */
|
|
272
|
+
forge: Forge | null;
|
|
273
|
+
/** The local ref the pull request's head was read from, or null. */
|
|
274
|
+
ref: string | null;
|
|
275
|
+
/** The pull request's head commit, or null. */
|
|
276
|
+
head: string | null;
|
|
277
|
+
/** Whether this read fetched the ref. */
|
|
278
|
+
fetched: boolean;
|
|
279
|
+
/** Whether the original commits were read; when false, `squash-unfollowed` in `reasons` says why. */
|
|
280
|
+
followed: boolean;
|
|
281
|
+
/** The original commits, oldest first, each with what its own trailers join and its provenance level. */
|
|
282
|
+
commits: SquashedCommit[];
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export interface SquashedCommit {
|
|
286
|
+
sha: string;
|
|
287
|
+
subject: string;
|
|
288
|
+
author: { name: string; email: string };
|
|
289
|
+
date: string;
|
|
290
|
+
trailers: Record<string, string[]>;
|
|
291
|
+
signature: { level: ProvenanceLevel; reason: string; principal?: string };
|
|
292
|
+
joins: CommitTrailerJoins;
|
|
199
293
|
}
|
|
200
294
|
|
|
201
295
|
export type CommitState = "decided" | "decided-by-window" | "undecided";
|
|
@@ -299,6 +393,18 @@ export interface WorkGapSource {
|
|
|
299
393
|
artifact?: string;
|
|
300
394
|
}
|
|
301
395
|
|
|
396
|
+
/** A review session that led to a work item (#3154, E21). */
|
|
397
|
+
export interface WorkReview {
|
|
398
|
+
/** The session record's node-style id, `record:<kind>/<id>`. */
|
|
399
|
+
id: string;
|
|
400
|
+
recordKind: string;
|
|
401
|
+
record: string;
|
|
402
|
+
path: string;
|
|
403
|
+
state: string | null;
|
|
404
|
+
/** The comments whose follow_ups name the item, numbered from 1; empty when only the session's own follow_ups do. */
|
|
405
|
+
comments: number[];
|
|
406
|
+
}
|
|
407
|
+
|
|
302
408
|
export interface WorkNode {
|
|
303
409
|
id: string;
|
|
304
410
|
kind: "work";
|
|
@@ -329,9 +435,47 @@ export interface WorkNode {
|
|
|
329
435
|
constrains: { entry: string; granularity: Granularity }[];
|
|
330
436
|
/** The item's work warnings, as records reports them, and work-done-gap-open. */
|
|
331
437
|
warnings: { code: WorkWarningCode; message: string }[];
|
|
438
|
+
/**
|
|
439
|
+
* The review sessions whose comments led to this item (#3154, E21 in
|
|
440
|
+
* arugula-salad/hud#823): each session record of a session kind read whose
|
|
441
|
+
* `comments[].follow_ups` (or its own `follow_ups`) names the item as
|
|
442
|
+
* `<kind>:<id>`, with the 1-based numbers of those comments. A commit that
|
|
443
|
+
* carries the item, by its `Chant-Record: work:<id>` trailer, joins back
|
|
444
|
+
* to the review through it. Empty when none does. Added within contract 1.
|
|
445
|
+
*/
|
|
446
|
+
reviews?: WorkReview[];
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* An agent run that made a commit in the walk (#3033): from the run ledger on
|
|
451
|
+
* the local `chant/lifecycle` branch. A run a `Chant-Run` trailer names and
|
|
452
|
+
* the ledger lacks is listed with `recorded: false` and nothing else known.
|
|
453
|
+
*/
|
|
454
|
+
export interface RunNode {
|
|
455
|
+
id: string;
|
|
456
|
+
kind: "run";
|
|
457
|
+
run: string;
|
|
458
|
+
recorded: boolean;
|
|
459
|
+
state: "running" | "ended" | null;
|
|
460
|
+
harness: { name: string; version: string | null } | null;
|
|
461
|
+
model: string | null;
|
|
462
|
+
provider: string | null;
|
|
463
|
+
by: string | null;
|
|
464
|
+
agent: string | null;
|
|
465
|
+
unit: string | null;
|
|
466
|
+
startedAt: string | null;
|
|
467
|
+
endedAt: string | null;
|
|
468
|
+
outcome: string | null;
|
|
469
|
+
usage: RunUsage | null;
|
|
470
|
+
cost: RunCost | null;
|
|
471
|
+
transcript: RunPin | null;
|
|
472
|
+
/** The instruction the run was given, pinned by hash, with the writer's excerpt when it gave one (#3034). */
|
|
473
|
+
instruction?: RunPin | null;
|
|
474
|
+
/** The fencing token of the work lease it worked under (#3034). */
|
|
475
|
+
lease?: string | null;
|
|
332
476
|
}
|
|
333
477
|
|
|
334
|
-
export type IntentNode = RegionNode | FileNode | MemberNode | CommitNode | JoinedNode | EvidenceEntryNode | DecisionNode | WorkNode | ArtifactNode | LinkNode | FindingNode;
|
|
478
|
+
export type IntentNode = RegionNode | FileNode | MemberNode | CommitNode | JoinedNode | EvidenceEntryNode | DecisionNode | WorkNode | ArtifactNode | LinkNode | FindingNode | RunNode;
|
|
335
479
|
|
|
336
480
|
export type Granularity = "path" | "member" | "contract" | "issue";
|
|
337
481
|
|
|
@@ -340,7 +484,87 @@ export type IntentEdge =
|
|
|
340
484
|
| { kind: "pins"; from: string; to: string; pinnedSha256: string | null; pinState: PinState }
|
|
341
485
|
| { kind: "touched-by"; from: string; to: string; lines: LineRange[] | null }
|
|
342
486
|
| { kind: "within"; from: string; to: string; state: "decided" | "decided-by-window" | "worked" }
|
|
343
|
-
| { kind: "
|
|
487
|
+
| { kind: "made-by"; from: string; to: string; joinedBy: RunJoin[]; recordedAs?: string; via?: string[] }
|
|
488
|
+
| { kind: "produced-by" | "serves" | "cites-evidence" | "supersedes" | "links" | "implements" | "needs" | "addressed-by" | "carries" | "worked-on"; from: string; to: string };
|
|
489
|
+
|
|
490
|
+
/** Lines of the region that one commit, and the same runs, last wrote (#3034). */
|
|
491
|
+
export interface WhySpan {
|
|
492
|
+
start: number;
|
|
493
|
+
end: number;
|
|
494
|
+
/** The commit node, or null for lines not committed yet. */
|
|
495
|
+
commit: string | null;
|
|
496
|
+
sha: string | null;
|
|
497
|
+
/** The run nodes behind these lines: the run the commit's Chant-Run names first, then those whose record lists it. */
|
|
498
|
+
runs: string[];
|
|
499
|
+
/** `hunks` when a run's recorded hunks chose among the commit's runs; null when every run that made the commit is listed. */
|
|
500
|
+
narrowedBy: "hunks" | null;
|
|
501
|
+
/** How the runs in `runs` join the commit, as their `made-by` edges say, without repeats (#3036). Empty with no runs. */
|
|
502
|
+
joinedBy: RunJoin[];
|
|
503
|
+
/**
|
|
504
|
+
* For lines of a followed squash (#3035): the sha of the original commit
|
|
505
|
+
* that last wrote them, one of the commit node's `squash.commits`, by blame
|
|
506
|
+
* at the pull request's head; `runs` keeps that commit's runs and the
|
|
507
|
+
* squash's own. Empty when the file at the head is not the squash's, so
|
|
508
|
+
* blame there can't say. Absent for any other commit.
|
|
509
|
+
*/
|
|
510
|
+
via?: string[];
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Why a decision is in `why`, most relevant first (#3034). */
|
|
514
|
+
export type WhyRelevance = "carried" | "path" | "contract" | "issue" | "member" | "related";
|
|
515
|
+
|
|
516
|
+
export interface WhyDecision {
|
|
517
|
+
decision: string;
|
|
518
|
+
/**
|
|
519
|
+
* carried: a commit or run that made the region's current lines carries it
|
|
520
|
+
* out. path, contract, issue, member: it constrains the region that way.
|
|
521
|
+
* related: it is in the graph only through supersession, or because a
|
|
522
|
+
* commit that no longer made any current line carried it out.
|
|
523
|
+
*/
|
|
524
|
+
relevance: WhyRelevance;
|
|
525
|
+
/** Not superseded. */
|
|
526
|
+
current: boolean;
|
|
527
|
+
/** Its state is one its kind closes, such as ratified. */
|
|
528
|
+
closed: boolean;
|
|
529
|
+
/** How many of the region's current lines were made as its own work. */
|
|
530
|
+
lines: number;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
export interface WhyRun {
|
|
534
|
+
run: string;
|
|
535
|
+
/** How many of the region's current lines it wrote. */
|
|
536
|
+
lines: number;
|
|
537
|
+
/** The commit nodes through which it made them. */
|
|
538
|
+
commits: string[];
|
|
539
|
+
/** The work item it worked on, as the run record names it, and its node when a work kind read has it. */
|
|
540
|
+
unit: { id: string; kind: string | null; node: string | null } | null;
|
|
541
|
+
/** The decision nodes it carried out: through its work item's implements, and the decision records it names. */
|
|
542
|
+
decisions: string[];
|
|
543
|
+
/** How it joins the commits in `commits`, as their `made-by` edges say, without repeats (#3036). */
|
|
544
|
+
joinedBy: RunJoin[];
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export interface WhyGap {
|
|
548
|
+
code: IntentWhyCode;
|
|
549
|
+
message: string;
|
|
550
|
+
/** The lines the gap is about, when it is about some of them. */
|
|
551
|
+
lines?: LineRange[];
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
/** The answer to "why is it like this" over the region (#3034, hud#700). */
|
|
555
|
+
export interface WhyAnswer {
|
|
556
|
+
/** The lines accounted for: the region's range, the whole file, or null for a directory, which is not blamed. */
|
|
557
|
+
lines: LineRange | null;
|
|
558
|
+
/** The current lines, top to bottom, each span with the commit and runs that last wrote it. Empty for a directory. */
|
|
559
|
+
blame: WhySpan[];
|
|
560
|
+
/** The decisions governing the region, most relevant first. */
|
|
561
|
+
decisions: WhyDecision[];
|
|
562
|
+
/** The runs that wrote the current lines, most lines first; for a directory, every run in the walk, newest first. */
|
|
563
|
+
runs: WhyRun[];
|
|
564
|
+
/** Whether a current decision governs the region or is carried out by what made its lines. */
|
|
565
|
+
explained: boolean;
|
|
566
|
+
gaps: WhyGap[];
|
|
567
|
+
}
|
|
344
568
|
|
|
345
569
|
export interface IntentReason {
|
|
346
570
|
code: IntentReasonCode;
|
|
@@ -364,15 +588,18 @@ export type IntentDocument =
|
|
|
364
588
|
edges: IntentEdge[];
|
|
365
589
|
reasons: IntentReason[];
|
|
366
590
|
summary: { commits: number; decisions: number; artifacts: number; findings: number };
|
|
591
|
+
why: WhyAnswer;
|
|
367
592
|
})
|
|
368
593
|
| (Head & { error: { code: IntentErrorCode; message: string } });
|
|
369
594
|
|
|
370
595
|
export interface IntentQuery {
|
|
371
596
|
/** Where the walk up to the declaration starts, and what the region path is relative to. */
|
|
372
597
|
cwd: string;
|
|
373
|
-
/** `path`, `path:line
|
|
598
|
+
/** `path`, `path:line`, `path:start-end` or `path#symbol`, or a graph node id `<member>/<id>`. */
|
|
374
599
|
region: string;
|
|
375
600
|
at?: string;
|
|
601
|
+
/** Follow squash merges to their pull requests' original commits, fetching a missing pull request ref from `origin` (#3035). */
|
|
602
|
+
followSquash?: boolean;
|
|
376
603
|
/**
|
|
377
604
|
* Kind files: record kinds, plugins with `commitJoins`, or both. Relative to
|
|
378
605
|
* `cwd`. Left out, every record kind the declaration names, in its order
|
|
@@ -385,6 +612,11 @@ export interface IntentQuery {
|
|
|
385
612
|
* --member` does.
|
|
386
613
|
*/
|
|
387
614
|
resolveNode?: (cwd: string, at: string | undefined, member: string, id: string) => Promise<{ file: string; line: number | null } | null | undefined>;
|
|
615
|
+
/**
|
|
616
|
+
* Load a lexicon plugin by name, for the symbol resolvers a member's
|
|
617
|
+
* lexicons contribute (#3313). The default is the CLI's `loadPlugin`.
|
|
618
|
+
*/
|
|
619
|
+
loadLexicon?: SymbolPluginLoader;
|
|
388
620
|
}
|
|
389
621
|
|
|
390
622
|
export interface IntentResult {
|
|
@@ -442,6 +674,45 @@ export function regionHistory(top: string, rev: string, gitPath: string, type: "
|
|
|
442
674
|
.map((sha) => ({ sha, lines: null }));
|
|
443
675
|
}
|
|
444
676
|
|
|
677
|
+
/** One current line of a file, and the commit that last wrote it. */
|
|
678
|
+
export interface BlamedLine {
|
|
679
|
+
line: number;
|
|
680
|
+
/** Null for a line not committed yet. */
|
|
681
|
+
sha: string | null;
|
|
682
|
+
/** The file's path in that commit, from the repository root. */
|
|
683
|
+
origPath: string;
|
|
684
|
+
/** The line's number in that commit's version of the file. */
|
|
685
|
+
origLine: number;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const ZERO_SHA = /^0+$/;
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* `git blame` over a file's lines (#3034): at `rev`, or in the working tree
|
|
692
|
+
* when `rev` is null, where a line not committed yet has no commit. Undefined
|
|
693
|
+
* when git can't blame the file, such as one never committed.
|
|
694
|
+
*/
|
|
695
|
+
export function blameLines(top: string, rev: string | null, gitPath: string, lines: LineRange | null): BlamedLine[] | undefined {
|
|
696
|
+
const out = tryGit(top, ["blame", "--line-porcelain", ...(lines ? [`-L${lines.start},${lines.end}`] : []), ...(rev ? [rev] : []), "--", gitPath]);
|
|
697
|
+
if (out === undefined) return undefined;
|
|
698
|
+
const result: BlamedLine[] = [];
|
|
699
|
+
let current: { sha: string; origLine: number; line: number; origPath: string } | undefined;
|
|
700
|
+
for (const l of out.split("\n")) {
|
|
701
|
+
if (l.startsWith("\t")) {
|
|
702
|
+
if (current) result.push({ line: current.line, sha: ZERO_SHA.test(current.sha) ? null : current.sha, origPath: current.origPath, origLine: current.origLine });
|
|
703
|
+
current = undefined;
|
|
704
|
+
continue;
|
|
705
|
+
}
|
|
706
|
+
const head = l.match(/^([0-9a-f]{40,64}) (\d+) (\d+)(?: \d+)?$/);
|
|
707
|
+
if (head) {
|
|
708
|
+
current = { sha: head[1], origLine: Number(head[2]), line: Number(head[3]), origPath: gitPath };
|
|
709
|
+
continue;
|
|
710
|
+
}
|
|
711
|
+
if (current && l.startsWith("filename ")) current.origPath = l.slice("filename ".length);
|
|
712
|
+
}
|
|
713
|
+
return result;
|
|
714
|
+
}
|
|
715
|
+
|
|
445
716
|
/** Subject, body, author, date and trailers of each commit. */
|
|
446
717
|
export function commitDetails(top: string, shas: string[]): Map<string, IntentCommit> {
|
|
447
718
|
const out = new Map<string, IntentCommit>();
|
|
@@ -538,7 +809,8 @@ export function parseRegion(arg: string): { path: string; lines: LineRange | nul
|
|
|
538
809
|
return { path: m[1], lines: { start, end } };
|
|
539
810
|
}
|
|
540
811
|
|
|
541
|
-
function regionId(path: string, lines: LineRange | null): string {
|
|
812
|
+
function regionId(path: string, lines: LineRange | null, symbol?: string): string {
|
|
813
|
+
if (symbol !== undefined) return `region:${path}#${symbol}`;
|
|
542
814
|
return `region:${path}${lines ? `:${lines.start}${lines.end === lines.start ? "" : `-${lines.end}`}` : ""}`;
|
|
543
815
|
}
|
|
544
816
|
|
|
@@ -649,13 +921,46 @@ export async function loadKinds(query: IntentQuery, top: string): Promise<Loaded
|
|
|
649
921
|
return out;
|
|
650
922
|
}
|
|
651
923
|
|
|
652
|
-
|
|
924
|
+
interface ResolvedRegion {
|
|
925
|
+
path: string;
|
|
926
|
+
lines: LineRange | null;
|
|
927
|
+
node: string | null;
|
|
928
|
+
symbol: { name: string; qualified: string; kind: string } | null;
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
async function resolveRegion(query: IntentQuery, located: LocatedWorkspace, declaration: Declaration): Promise<ResolvedRegion> {
|
|
653
932
|
const parsed = parseRegion(query.region);
|
|
654
933
|
if ("error" in parsed) throw new IntentError("intent-region-invalid", parsed.error);
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
return
|
|
934
|
+
const inWorkspace = (p: string): string | undefined => {
|
|
935
|
+
const rel = toPosix(relative(realpathOr(located.rootOnDisk), resolve(realpathOr(query.cwd), p)));
|
|
936
|
+
const path = rel === "" ? "." : rel;
|
|
937
|
+
return path === "." || (isWorkspacePath(path) && !path.startsWith("../") && located.tree.stat(path) !== undefined) ? path : undefined;
|
|
938
|
+
};
|
|
939
|
+
const path = inWorkspace(parsed.path);
|
|
940
|
+
if (path !== undefined) return { path, lines: parsed.lines, node: null, symbol: null };
|
|
941
|
+
// path#symbol (#3034): the symbol's current lines in the tree read.
|
|
942
|
+
const hash = parsed.lines ? -1 : query.region.lastIndexOf("#");
|
|
943
|
+
if (hash > 0) {
|
|
944
|
+
const name = query.region.slice(hash + 1);
|
|
945
|
+
const file = inWorkspace(query.region.slice(0, hash));
|
|
946
|
+
if (file !== undefined && name !== "") {
|
|
947
|
+
if (file === "." || located.tree.stat(file) !== "file") throw new IntentError("intent-region-invalid", `${file} is a directory, and a symbol needs a file`);
|
|
948
|
+
// A file core's resolver doesn't read may have one from its member's lexicons (#3313).
|
|
949
|
+
let extra: SymbolResolver[] = [];
|
|
950
|
+
let why = "";
|
|
951
|
+
if (!symbolResolverFor(file)) {
|
|
952
|
+
const holder = memberHolding(file, declaration.members);
|
|
953
|
+
const m = holder ? declaration.members.find((x) => x.name === holder) : undefined;
|
|
954
|
+
if (m && m.kind === "chant") {
|
|
955
|
+
const got = await memberSymbolResolvers(memberDirOnDisk(located.rootOnDisk, m.dir), query.loadLexicon);
|
|
956
|
+
extra = got.resolvers;
|
|
957
|
+
if (got.problems.length > 0) why = `; member ${m.name}: ${got.problems.join("; ")}`;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
const r = resolveSymbol(file, located.tree.read(file), name, extra);
|
|
961
|
+
if (!r.ok) throw new IntentError(r.reason === "unsupported" ? "intent-symbol-unsupported" : r.reason === "ambiguous" ? "intent-symbol-ambiguous" : "intent-symbol-unknown", `${r.message}${r.reason === "unsupported" ? why : ""}${located.tree.label}`);
|
|
962
|
+
return { path: file, lines: r.declaration.lines, node: null, symbol: { name, qualified: r.declaration.qualified, kind: r.declaration.kind } };
|
|
963
|
+
}
|
|
659
964
|
}
|
|
660
965
|
// A graph node id, <member>/<id>, when no such path exists (#2650 B1).
|
|
661
966
|
const slash = query.region.indexOf("/");
|
|
@@ -664,10 +969,10 @@ async function resolveRegion(query: IntentQuery, located: LocatedWorkspace, decl
|
|
|
664
969
|
const loc = await (query.resolveNode ?? resolveNodeFromGraph)(query.cwd, query.at, member.name, query.region);
|
|
665
970
|
if (loc) {
|
|
666
971
|
const file = joinPath(member.dir, loc.file);
|
|
667
|
-
return { path: file === "" ? "." : file, lines: loc.line ? { start: loc.line, end: loc.line } : null, node: query.region };
|
|
972
|
+
return { path: file === "" ? "." : file, lines: loc.line ? { start: loc.line, end: loc.line } : null, node: query.region, symbol: null };
|
|
668
973
|
}
|
|
669
974
|
}
|
|
670
|
-
throw new IntentError("intent-region-invalid", `${query.region} is not a path in the workspace${located.tree.label}, or a graph node id`);
|
|
975
|
+
throw new IntentError("intent-region-invalid", `${query.region} is not a path in the workspace${located.tree.label}, a path#symbol, or a graph node id`);
|
|
671
976
|
}
|
|
672
977
|
|
|
673
978
|
/** Build the intent document. Never throws an {@link IntentError}, {@link WorkspaceReadError} or {@link RecordReadError}. */
|
|
@@ -714,8 +1019,19 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
714
1019
|
|
|
715
1020
|
// The region, its files and its member.
|
|
716
1021
|
const member = region.path === "." ? (declaration.members.find((m) => m.dir === ".")?.name ?? null) : memberHolding(region.path, declaration.members);
|
|
717
|
-
const rid = regionId(region.path, region.lines);
|
|
718
|
-
add<RegionNode>({
|
|
1022
|
+
const rid = regionId(region.path, region.lines, region.symbol?.name);
|
|
1023
|
+
add<RegionNode>({
|
|
1024
|
+
id: rid,
|
|
1025
|
+
kind: "region",
|
|
1026
|
+
path: region.path,
|
|
1027
|
+
lines: region.lines,
|
|
1028
|
+
member,
|
|
1029
|
+
at: located.at,
|
|
1030
|
+
type,
|
|
1031
|
+
generated: type === "file" ? isGeneratedPath(declaration, region.path) : null,
|
|
1032
|
+
node: region.node,
|
|
1033
|
+
symbol: region.symbol,
|
|
1034
|
+
});
|
|
719
1035
|
const files = type === "dir" ? filesUnder(located.tree, region.path) : [];
|
|
720
1036
|
for (const f of files) add<FileNode>({ id: `file:${f}`, kind: "file", path: f, member: memberHolding(f, declaration.members), generated: isGeneratedPath(declaration, f) });
|
|
721
1037
|
const memberNode = (name: string) => {
|
|
@@ -731,7 +1047,27 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
731
1047
|
const workspacePrefix = located.root === "." ? "" : located.root;
|
|
732
1048
|
const gitPath = joinPath(workspacePrefix, region.path);
|
|
733
1049
|
const touched = rev ? regionHistory(top, rev, gitPath, type, region.lines) : [];
|
|
1050
|
+
// Who last wrote each current line of a file region (#3034). A commit blame
|
|
1051
|
+
// names and the history walk missed, as when a move confuses git log -L,
|
|
1052
|
+
// joins the commits that touched the region.
|
|
1053
|
+
const fileLines = type === "file" ? (region.lines ?? { start: 1, end: Math.max(1, located.tree.read(region.path).replace(/\n$/, "").split("\n").length) }) : null;
|
|
1054
|
+
const blamed: BlamedLine[] =
|
|
1055
|
+
fileLines === null
|
|
1056
|
+
? []
|
|
1057
|
+
: ((rev ? blameLines(top, located.at, gitPath, region.lines) : undefined) ??
|
|
1058
|
+
// A file git can't blame in the working tree has never been committed: every line is new.
|
|
1059
|
+
(located.at === null ? Array.from({ length: fileLines.end - fileLines.start + 1 }, (_, i) => ({ line: fileLines.start + i, sha: null, origPath: gitPath, origLine: fileLines.start + i })) : []));
|
|
1060
|
+
for (const sha of new Set(blamed.map((b) => b.sha).filter((x): x is string => x !== null))) {
|
|
1061
|
+
if (!touched.some((t) => t.sha === sha)) touched.push({ sha, lines: null });
|
|
1062
|
+
}
|
|
734
1063
|
const details = commitDetails(top, touched.map((t) => t.sha));
|
|
1064
|
+
// Squash merges, followed to the pull request's original commits when asked (#3035).
|
|
1065
|
+
const follows = query.followSquash ? followSquashes(top, [...details.values()], { fetchMissing: true }) : new Map<string, SquashFollow>();
|
|
1066
|
+
for (const f of follows.values()) {
|
|
1067
|
+
if (f.problem) reasons.push({ code: "squash-unfollowed", message: `${f.sha.slice(0, 8)} squashes pull request #${f.pullRequest}, and ${f.problem}, so its original commits are not followed` });
|
|
1068
|
+
}
|
|
1069
|
+
const originalDetails = commitDetails(top, [...new Set([...follows.values()].flatMap((f) => f.commits))]);
|
|
1070
|
+
const originalsOf = (sha: string): IntentCommit[] => (follows.get(sha)?.commits ?? []).map((o) => originalDetails.get(o)).filter((x): x is IntentCommit => x !== undefined);
|
|
735
1071
|
|
|
736
1072
|
// Each commit's provenance, judged by the policy at base as records judges a record's (#2547).
|
|
737
1073
|
const policy = policyAtBase(top, resolveBase(top));
|
|
@@ -752,60 +1088,128 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
752
1088
|
unit?: string;
|
|
753
1089
|
contracts: string[];
|
|
754
1090
|
authorship: string[];
|
|
755
|
-
/** The record ids the commit's units and contracts say they carry out. */
|
|
1091
|
+
/** The record ids the commit's units and contracts say they carry out, and the ones its Chant-Record and Chant-Lease trailers name or implement. */
|
|
756
1092
|
decisions: string[];
|
|
1093
|
+
/** The nodes of the records the commit's own trailers name (#3149). */
|
|
1094
|
+
carries: string[];
|
|
757
1095
|
}
|
|
758
1096
|
const joined = new Map<string, Joined>();
|
|
1097
|
+
// chant's own trailers on each commit (#3149), with the items their lease tokens name.
|
|
1098
|
+
const trailerJoins = readTrailerJoins(top, [...details.values(), ...originalDetails.values()]);
|
|
759
1099
|
const pluginFindings: { commit: string; plugin: string; finding: PluginFinding }[] = [];
|
|
1100
|
+
const signatureOf = (sha: string): CommitNode["signature"] => {
|
|
1101
|
+
if (!policy.active) return { level: "unattested", reason: policy.problems.length ? policy.problems.join("; ") : `no signers file (${policy.signersPath}) at base; attestation is off` };
|
|
1102
|
+
const p = commitProvenance(top, policy, sha, attestors);
|
|
1103
|
+
return { level: p.level, reason: p.reason, ...(p.principal ? { principal: p.principal } : {}) };
|
|
1104
|
+
};
|
|
760
1105
|
const failedPlugins = new Set<string>();
|
|
761
1106
|
for (const t of touched) {
|
|
762
1107
|
const c = details.get(t.sha);
|
|
763
1108
|
if (!c) continue;
|
|
764
|
-
const signature =
|
|
765
|
-
? (() => {
|
|
766
|
-
const p = commitProvenance(top, policy, c.sha, attestors);
|
|
767
|
-
return { level: p.level, reason: p.reason, ...(p.principal ? { principal: p.principal } : {}) };
|
|
768
|
-
})()
|
|
769
|
-
: { level: "unattested" as const, reason: policy.problems.length ? policy.problems.join("; ") : `no signers file (${policy.signersPath}) at base; attestation is off` };
|
|
1109
|
+
const signature = signatureOf(c.sha);
|
|
770
1110
|
const pr = c.subject.match(/\(#([0-9]+)\)\s*$/);
|
|
771
1111
|
const cid = `commit:${c.sha}`;
|
|
772
|
-
|
|
1112
|
+
const f = follows.get(c.sha);
|
|
1113
|
+
const squash: SquashNode | undefined = f
|
|
1114
|
+
? {
|
|
1115
|
+
pullRequest: f.pullRequest,
|
|
1116
|
+
forge: f.forge,
|
|
1117
|
+
ref: f.ref,
|
|
1118
|
+
head: f.head,
|
|
1119
|
+
fetched: f.fetched,
|
|
1120
|
+
followed: f.followed,
|
|
1121
|
+
commits: originalsOf(c.sha).map((o) => ({ sha: o.sha, subject: o.subject, author: o.author, date: o.date, trailers: o.trailers, signature: signatureOf(o.sha), joins: trailerJoins.get(o.sha)!.joins })),
|
|
1122
|
+
}
|
|
1123
|
+
: undefined;
|
|
1124
|
+
add<CommitNode>({ id: cid, kind: "commit", sha: c.sha, subject: c.subject, author: c.author, date: c.date, trailers: c.trailers, pullRequest: pr ? Number(pr[1]) : null, signature, lines: t.lines, state: null, joins: trailerJoins.get(c.sha)!.joins, ...(squash ? { squash } : {}) });
|
|
773
1125
|
edges.push({ kind: "touched-by", from: rid, to: cid, lines: t.lines });
|
|
774
1126
|
|
|
775
|
-
// 2. Each commit's origin, from the plugins.
|
|
776
|
-
const entry: Joined = { contracts: [], authorship: [], decisions: [] };
|
|
1127
|
+
// 2. Each commit's origin, from the plugins. A followed squash also takes its original commits' (#3035).
|
|
1128
|
+
const entry: Joined = { contracts: [], authorship: [], decisions: [], carries: [] };
|
|
777
1129
|
joined.set(c.sha, entry);
|
|
1130
|
+
const pushEdge = (e: IntentEdge) => {
|
|
1131
|
+
if (!edges.some((x) => x.kind === e.kind && x.from === e.from && x.to === e.to)) edges.push(e);
|
|
1132
|
+
};
|
|
1133
|
+
const subjects: IntentCommit[] = [c, ...originalsOf(c.sha)];
|
|
778
1134
|
for (const k of kinds) {
|
|
779
1135
|
if (!k.joins) continue;
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
result
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
1136
|
+
for (const subject of subjects) {
|
|
1137
|
+
const original = subject !== c;
|
|
1138
|
+
let result;
|
|
1139
|
+
try {
|
|
1140
|
+
result = await runCommitJoins(k.joins, subject, { read: readAt, list: listAt, at: located.at }, k.name);
|
|
1141
|
+
} catch (err) {
|
|
1142
|
+
const message = `${k.display}: commitJoins failed for ${subject.sha.slice(0, 8)}: ${err instanceof Error ? err.message : String(err)}`;
|
|
1143
|
+
if (!failedPlugins.has(message)) reasons.push({ code: "intent-plugin-failed", message });
|
|
1144
|
+
failedPlugins.add(message);
|
|
1145
|
+
continue;
|
|
1146
|
+
}
|
|
1147
|
+
const joinedNode = (kind: JoinedNode["kind"], e: JoinedEntity): string => {
|
|
1148
|
+
const { id, ...data } = e;
|
|
1149
|
+
return add<JoinedNode>({ id: `${kind}:${id}`, kind, ref: id, plugin: k.display, data }).id;
|
|
1150
|
+
};
|
|
1151
|
+
const unitId = result.unit ? joinedNode("unit", result.unit) : undefined;
|
|
1152
|
+
const contractId = result.contract ? joinedNode("contract", result.contract) : undefined;
|
|
1153
|
+
if (unitId) {
|
|
1154
|
+
if (original) entry.unit ??= unitId;
|
|
1155
|
+
else entry.unit = unitId;
|
|
1156
|
+
pushEdge({ kind: "produced-by", from: cid, to: unitId });
|
|
1157
|
+
if (contractId) pushEdge({ kind: "serves", from: unitId, to: contractId });
|
|
1158
|
+
}
|
|
1159
|
+
if (contractId) entry.contracts.push(result.contract!.id);
|
|
1160
|
+
if (unitId) entry.decisions.push(...entityDecisions(result.unit), ...entityDecisions(result.contract));
|
|
1161
|
+
for (const f of result.findings ?? []) pluginFindings.push({ commit: cid, plugin: k.display, finding: f });
|
|
1162
|
+
const evidence = result.evidence === undefined ? [] : Array.isArray(result.evidence) ? result.evidence : [result.evidence];
|
|
1163
|
+
for (const e of evidence) pushEdge({ kind: "cites-evidence", from: unitId ?? contractId ?? cid, to: joinedNode("evidence", e) });
|
|
1164
|
+
// Authorship is checked against the squash's own trailers, so only its own claims count.
|
|
1165
|
+
if (!original) entry.authorship.push(...(result.authorship ?? []));
|
|
799
1166
|
}
|
|
800
|
-
if (contractId) entry.contracts.push(result.contract!.id);
|
|
801
|
-
if (unitId) entry.decisions.push(...entityDecisions(result.unit), ...entityDecisions(result.contract));
|
|
802
|
-
for (const f of result.findings ?? []) pluginFindings.push({ commit: cid, plugin: k.display, finding: f });
|
|
803
|
-
const evidence = result.evidence === undefined ? [] : Array.isArray(result.evidence) ? result.evidence : [result.evidence];
|
|
804
|
-
for (const e of evidence) edges.push({ kind: "cites-evidence", from: unitId ?? contractId ?? cid, to: joinedNode("evidence", e) });
|
|
805
|
-
entry.authorship.push(...(result.authorship ?? []));
|
|
806
1167
|
}
|
|
807
1168
|
}
|
|
808
1169
|
|
|
1170
|
+
// The agent runs that made each commit (#3033): the one its Chant-Run names, and any whose record lists it.
|
|
1171
|
+
const runJoins = await runsForCommits(
|
|
1172
|
+
top,
|
|
1173
|
+
located.rootOnDisk,
|
|
1174
|
+
[...new Set([...touched.map((t) => t.sha), ...originalDetails.keys()])].map((sha) => ({ sha, run: trailerJoins.get(sha)?.joins.run ?? null })),
|
|
1175
|
+
);
|
|
1176
|
+
// A followed squash joins its original commits' runs (#3035).
|
|
1177
|
+
addSquashRuns(runJoins.refs, follows);
|
|
1178
|
+
for (const t of touched) {
|
|
1179
|
+
if (!nodes.has(`commit:${t.sha}`)) continue;
|
|
1180
|
+
for (const ref of runJoins.refs.get(t.sha) ?? []) {
|
|
1181
|
+
const r = runJoins.runs.get(ref.id);
|
|
1182
|
+
const node = add<RunNode>({
|
|
1183
|
+
id: `run:${ref.id}`,
|
|
1184
|
+
kind: "run",
|
|
1185
|
+
run: ref.id,
|
|
1186
|
+
recorded: r !== undefined,
|
|
1187
|
+
state: r?.state ?? null,
|
|
1188
|
+
harness: r?.harness ?? null,
|
|
1189
|
+
model: r?.model ?? null,
|
|
1190
|
+
provider: r?.provider ?? null,
|
|
1191
|
+
by: r?.by ?? null,
|
|
1192
|
+
agent: r?.agent ?? null,
|
|
1193
|
+
unit: r?.unit?.id ?? null,
|
|
1194
|
+
startedAt: r?.startedAt ?? null,
|
|
1195
|
+
endedAt: r?.endedAt ?? null,
|
|
1196
|
+
outcome: r?.outcome ?? null,
|
|
1197
|
+
usage: r?.usage ?? null,
|
|
1198
|
+
cost: r?.cost ?? null,
|
|
1199
|
+
transcript: r?.transcript ?? null,
|
|
1200
|
+
instruction: r?.instruction ?? null,
|
|
1201
|
+
lease: r?.lease ?? null,
|
|
1202
|
+
});
|
|
1203
|
+
edges.push({ kind: "made-by", from: `commit:${t.sha}`, to: node.id, joinedBy: ref.joinedBy, ...(ref.recordedAs ? { recordedAs: ref.recordedAs } : {}), ...(ref.via ? { via: ref.via } : {}) });
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
// A commit a trailer or a record joins to one run, with the content of a commit another run recorded (#3036).
|
|
1207
|
+
for (const x of runJoins.conflicts) {
|
|
1208
|
+
if (!nodes.has(`commit:${x.sha}`)) continue;
|
|
1209
|
+
const others = x.content.map((m) => `${m.run} (${m.sha.slice(0, 8)})`).join(", ");
|
|
1210
|
+
find("intent-commit-join-conflict", `${x.sha.slice(0, 8)} joins ${x.joined.join(", ")} by its trailer or the run's record, and has the patch-id of a commit ${others} recorded; it is not joined to ${x.content.length === 1 ? "that run" : "those runs"}`, [`commit:${x.sha}`, ...x.joined.map((id) => `run:${id}`)]);
|
|
1211
|
+
}
|
|
1212
|
+
|
|
809
1213
|
// 3. The decisions whose constrains cover the region, and their chains.
|
|
810
1214
|
const regionFull = region.path === "." ? workspacePrefix : gitPath;
|
|
811
1215
|
const origin = originRepo(top);
|
|
@@ -1099,16 +1503,6 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1099
1503
|
}
|
|
1100
1504
|
if (node.constrains.length > 0) workCovering.push(h);
|
|
1101
1505
|
}
|
|
1102
|
-
for (const h of workAll.filter((x) => x.node)) {
|
|
1103
|
-
for (const id of implementedIds(h)) {
|
|
1104
|
-
const hit = decisionById.get(id.slice("record:".length))!;
|
|
1105
|
-
edges.push({ kind: "implements", from: h.node!.id, to: decisionNode(hit.kind, hit.view).id });
|
|
1106
|
-
}
|
|
1107
|
-
for (const n of idList(h.view.data, workSpec(h).needs)) {
|
|
1108
|
-
const hit = workByKey.get(`${h.kind.records!.loaded.kind.name}/${n}`);
|
|
1109
|
-
if (hit) edges.push({ kind: "needs", from: h.node!.id, to: workNode(hit).id });
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
1506
|
const workWindows = new Map<string, { from: Set<string>; until: Set<string> | null }>();
|
|
1113
1507
|
if (rev) {
|
|
1114
1508
|
for (const h of workCovering) {
|
|
@@ -1125,6 +1519,105 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1125
1519
|
return !!w && w.from.has(sha) && !w.until?.has(sha);
|
|
1126
1520
|
};
|
|
1127
1521
|
|
|
1522
|
+
// The records chant's own trailers name (#3149): a Chant-Record of a kind
|
|
1523
|
+
// read, and the work item a Chant-Lease was taken on. The commit carries
|
|
1524
|
+
// each, and is the own work of a decision it names or that a work item it
|
|
1525
|
+
// names implements.
|
|
1526
|
+
const recordKinds = new Map(kinds.filter((k) => k.records).map((k) => [k.records!.loaded.kind.name, k]));
|
|
1527
|
+
/** The work item a run worked on and the records it names, among the kinds read, deduplicated. */
|
|
1528
|
+
const runTargets = (r: RunView): { node: string; work?: WorkHit; decision?: string }[] => {
|
|
1529
|
+
const out: { node: string; work?: WorkHit; decision?: string }[] = [];
|
|
1530
|
+
const push = (x: { node: string; work?: WorkHit; decision?: string }) => {
|
|
1531
|
+
if (!out.some((o) => o.node === x.node)) out.push(x);
|
|
1532
|
+
};
|
|
1533
|
+
if (r.unit) {
|
|
1534
|
+
const named = r.unit.kind ? workKinds.filter((k) => k.records!.loaded.kind.name === r.unit!.kind) : workKinds;
|
|
1535
|
+
const hits = named.map((k) => workByKey.get(`${k.records!.loaded.kind.name}/${r.unit!.id}`)).filter((h): h is WorkHit => h !== undefined);
|
|
1536
|
+
if (hits.length === 1) push({ node: workNode(hits[0]).id, work: hits[0] });
|
|
1537
|
+
}
|
|
1538
|
+
for (const ref of r.records) {
|
|
1539
|
+
const k = recordKinds.get(ref.kind);
|
|
1540
|
+
if (!k) continue;
|
|
1541
|
+
if (k.records!.loaded.kind.work) {
|
|
1542
|
+
const h = workByKey.get(`${ref.kind}/${ref.id}`);
|
|
1543
|
+
if (h) push({ node: workNode(h).id, work: h });
|
|
1544
|
+
continue;
|
|
1545
|
+
}
|
|
1546
|
+
const hit = decisionById.get(`${ref.kind}/${ref.id}`);
|
|
1547
|
+
if (hit) push({ node: decisionNode(hit.kind, hit.view).id, decision: `${ref.kind}/${ref.id}` });
|
|
1548
|
+
}
|
|
1549
|
+
return out;
|
|
1550
|
+
};
|
|
1551
|
+
for (const t of touched) {
|
|
1552
|
+
const c = nodes.get(`commit:${t.sha}`) as CommitNode | undefined;
|
|
1553
|
+
const j = joined.get(t.sha);
|
|
1554
|
+
if (!c || !j) continue;
|
|
1555
|
+
const carry = (to: string) => {
|
|
1556
|
+
if (j.carries.includes(to)) return;
|
|
1557
|
+
j.carries.push(to);
|
|
1558
|
+
edges.push({ kind: "carries", from: c.id, to });
|
|
1559
|
+
};
|
|
1560
|
+
const carryWork = (h: WorkHit): string => {
|
|
1561
|
+
const node = workNode(h);
|
|
1562
|
+
carry(node.id);
|
|
1563
|
+
j.decisions.push(...implementedIds(h).map((id) => id.slice("record:".length)));
|
|
1564
|
+
return node.id;
|
|
1565
|
+
};
|
|
1566
|
+
// The commit's own trailers, and a followed squash's original commits' (#3035).
|
|
1567
|
+
for (const joins of [c.joins, ...(c.squash?.commits ?? []).map((o) => o.joins)]) {
|
|
1568
|
+
for (const r of joins.records) {
|
|
1569
|
+
const k = recordKinds.get(r.kind);
|
|
1570
|
+
if (!k) continue;
|
|
1571
|
+
if (k.records!.loaded.kind.work) {
|
|
1572
|
+
const h = workByKey.get(`${r.kind}/${r.id}`);
|
|
1573
|
+
if (h) r.node = carryWork(h);
|
|
1574
|
+
continue;
|
|
1575
|
+
}
|
|
1576
|
+
const hit = decisionById.get(`${r.kind}/${r.id}`);
|
|
1577
|
+
if (!hit) continue;
|
|
1578
|
+
r.node = decisionNode(hit.kind, hit.view).id;
|
|
1579
|
+
carry(r.node);
|
|
1580
|
+
j.decisions.push(`${r.kind}/${r.id}`);
|
|
1581
|
+
}
|
|
1582
|
+
const item = joins.lease?.item;
|
|
1583
|
+
if (item) {
|
|
1584
|
+
const hits = workKinds.map((k) => workByKey.get(`${k.records!.loaded.kind.name}/${item}`)).filter((h): h is WorkHit => h !== undefined);
|
|
1585
|
+
if (hits.length === 1) carryWork(hits[0]);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
// The runs that made the commit (#3034): its run's work item and the
|
|
1589
|
+
// records the run names are carried as a Chant-Lease and a Chant-Record are.
|
|
1590
|
+
for (const ref of runJoins.refs.get(t.sha) ?? []) {
|
|
1591
|
+
const r = runJoins.runs.get(ref.id);
|
|
1592
|
+
if (!r) continue;
|
|
1593
|
+
for (const target of runTargets(r)) {
|
|
1594
|
+
if (target.work) carryWork(target.work);
|
|
1595
|
+
else if (target.decision) {
|
|
1596
|
+
carry(target.node);
|
|
1597
|
+
j.decisions.push(target.decision);
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
// Each recorded run in the walk to the work item and records it worked on (#3034).
|
|
1603
|
+
for (const n of [...nodes.values()]) {
|
|
1604
|
+
if (n.kind !== "run") continue;
|
|
1605
|
+
const r = runJoins.runs.get(n.run);
|
|
1606
|
+
if (!r) continue;
|
|
1607
|
+
for (const target of runTargets(r)) edges.push({ kind: "worked-on", from: n.id, to: target.node });
|
|
1608
|
+
}
|
|
1609
|
+
// Each work item in the graph, those its commits and runs carry included, to the decisions it implements and the items it needs.
|
|
1610
|
+
for (const h of workAll.filter((x) => x.node)) {
|
|
1611
|
+
for (const id of implementedIds(h)) {
|
|
1612
|
+
const hit = decisionById.get(id.slice("record:".length))!;
|
|
1613
|
+
edges.push({ kind: "implements", from: h.node!.id, to: decisionNode(hit.kind, hit.view).id });
|
|
1614
|
+
}
|
|
1615
|
+
for (const n of idList(h.view.data, workSpec(h).needs)) {
|
|
1616
|
+
const hit = workByKey.get(`${h.kind.records!.loaded.kind.name}/${n}`);
|
|
1617
|
+
if (hit) edges.push({ kind: "needs", from: h.node!.id, to: workNode(hit).id });
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1128
1621
|
const coveredAt = (sha: string, granularities: Granularity[]) =>
|
|
1129
1622
|
covering.filter((c) => {
|
|
1130
1623
|
if (!c.node.constrains.some((x) => granularities.includes(x.granularity))) return false;
|
|
@@ -1133,9 +1626,10 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1133
1626
|
});
|
|
1134
1627
|
const readsRecords = kinds.some((k) => k.records);
|
|
1135
1628
|
// A decision's own work: a commit whose unit, or that unit's contract, names
|
|
1136
|
-
// the decision, or whose unit serves a contract the decision constrains
|
|
1629
|
+
// the decision, or whose unit serves a contract the decision constrains; or
|
|
1630
|
+
// a commit whose own trailers name the decision, or a work item implementing it.
|
|
1137
1631
|
const ownWork = (j: Joined, d: DecisionNode) =>
|
|
1138
|
-
!!j.unit && (j.decisions.some((x) => x === d.record || x === `${d.recordKind}/${d.record}`) || d.constrains.some((x) => x.granularity === "contract" && j.contracts.includes(x.entry)));
|
|
1632
|
+
(!!j.unit || j.carries.length > 0) && (j.decisions.some((x) => x === d.record || x === `${d.recordKind}/${d.record}`) || d.constrains.some((x) => x.granularity === "contract" && j.contracts.includes(x.entry)));
|
|
1139
1633
|
for (const t of touched) {
|
|
1140
1634
|
const c = nodes.get(`commit:${t.sha}`) as CommitNode | undefined;
|
|
1141
1635
|
if (!c) continue;
|
|
@@ -1152,8 +1646,8 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1152
1646
|
if (readsRecords && c.state === "undecided") {
|
|
1153
1647
|
find("intent-commit-undecided", `${t.sha.slice(0, 8)} changed the region when no decision constrained ${region.path} by path`, [c.id, rid]);
|
|
1154
1648
|
}
|
|
1155
|
-
if (readsRecords && !j.unit && c.pullRequest === null && coveredAt(t.sha, ["path", "member", "contract", "issue"]).length === 0) {
|
|
1156
|
-
find("intent-commit-bare", `${t.sha.slice(0, 8)} names no unit, no pull request and no decision`, [c.id]);
|
|
1649
|
+
if (readsRecords && !j.unit && j.carries.length === 0 && c.pullRequest === null && coveredAt(t.sha, ["path", "member", "contract", "issue"]).length === 0) {
|
|
1650
|
+
find("intent-commit-bare", `${t.sha.slice(0, 8)} names no unit, no record, no pull request and no decision`, [c.id]);
|
|
1157
1651
|
}
|
|
1158
1652
|
const claims = [...new Set(j.authorship)].filter((key) => hasTrailer(c.trailers, key));
|
|
1159
1653
|
if (claims.length > 0 && c.signature.level !== "attested") {
|
|
@@ -1303,7 +1797,37 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1303
1797
|
for (const h of by) edges.push({ kind: "addressed-by", from: f.id, to: workNode(h).id });
|
|
1304
1798
|
}
|
|
1305
1799
|
}
|
|
1800
|
+
// Reviews that led to a work item in the graph (#3154, E21): a session's comments[].follow_ups name it.
|
|
1801
|
+
const workNodes = [...nodes.values()].filter((n): n is WorkNode => n.kind === "work");
|
|
1802
|
+
if (workNodes.length > 0) {
|
|
1803
|
+
const byRef = new Map(workNodes.map((n) => [`${n.recordKind}:${n.record}`, n]));
|
|
1804
|
+
for (const k of kinds) {
|
|
1805
|
+
const loaded = k.records?.loaded.kind;
|
|
1806
|
+
if (!loaded?.session) continue;
|
|
1807
|
+
for (const v of k.records!.views) {
|
|
1808
|
+
if (v.id === null || !v.data) continue;
|
|
1809
|
+
const hits = new Map<WorkNode, number[]>();
|
|
1810
|
+
const note = (refs: unknown, comment: number | null) => {
|
|
1811
|
+
if (!Array.isArray(refs)) return;
|
|
1812
|
+
for (const ref of refs) {
|
|
1813
|
+
const n = typeof ref === "string" ? byRef.get(ref) : undefined;
|
|
1814
|
+
if (!n) continue;
|
|
1815
|
+
const list = hits.get(n) ?? [];
|
|
1816
|
+
if (comment !== null && !list.includes(comment)) list.push(comment);
|
|
1817
|
+
hits.set(n, list);
|
|
1818
|
+
}
|
|
1819
|
+
};
|
|
1820
|
+
note(v.data.follow_ups, null);
|
|
1821
|
+
const comments = Array.isArray(v.data.comments) ? v.data.comments : [];
|
|
1822
|
+
comments.forEach((c: unknown, i: number) => note((c as { follow_ups?: unknown } | null)?.follow_ups, i + 1));
|
|
1823
|
+
for (const [n, list] of hits) {
|
|
1824
|
+
(n.reviews ??= []).push({ id: `record:${loaded.name}/${v.id}`, recordKind: loaded.name, record: v.id, path: v.path, state: v.state, comments: list.sort((a, b) => a - b) });
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1306
1829
|
for (const f of findings) nodes.set(f.id, f);
|
|
1830
|
+
const why = explain();
|
|
1307
1831
|
const all = [...nodes.values()];
|
|
1308
1832
|
return {
|
|
1309
1833
|
doc: {
|
|
@@ -1322,7 +1846,140 @@ async function walk(query: IntentQuery, head: Head): Promise<IntentResult> {
|
|
|
1322
1846
|
artifacts: all.filter((n) => n.kind === "artifact").length,
|
|
1323
1847
|
findings: findings.length,
|
|
1324
1848
|
},
|
|
1849
|
+
why,
|
|
1325
1850
|
},
|
|
1326
1851
|
failed: reasons.some((r) => r.code === "intent-plugin-failed"),
|
|
1327
1852
|
};
|
|
1853
|
+
|
|
1854
|
+
/** "Why is it like this" over the region (#3034): who made its current lines, and the decisions governing it, most relevant first. */
|
|
1855
|
+
function explain(): WhyAnswer {
|
|
1856
|
+
const hunksOf = (run: string, sha: string) => runJoins.runs.get(run)?.commits.find((c) => c.sha === sha)?.hunks ?? null;
|
|
1857
|
+
const joinOf = (run: string, sha: string): RunJoin[] => (runJoins.refs.get(sha) ?? []).find((r) => r.id === run)?.joinedBy ?? [];
|
|
1858
|
+
const joinsOf = (runs: string[], shas: string[]): RunJoin[] => {
|
|
1859
|
+
const all = new Set(runs.flatMap((id) => shas.flatMap((sha) => joinOf(id, sha))));
|
|
1860
|
+
return RUN_JOIN_ORDER.filter((j) => all.has(j));
|
|
1861
|
+
};
|
|
1862
|
+
// For a followed squash (#3035), the original commit behind each of its lines, by blame at the pull request's head.
|
|
1863
|
+
const origins = new Map<string, Map<number, string> | undefined>();
|
|
1864
|
+
const originOf = (sha: string, path: string, line: number): { squash: boolean; origin: string | undefined } => {
|
|
1865
|
+
const f = follows.get(sha);
|
|
1866
|
+
if (!f?.followed || !f.head) return { squash: false, origin: undefined };
|
|
1867
|
+
const key = `${sha}\0${path}`;
|
|
1868
|
+
if (!origins.has(key)) origins.set(key, squashLineOrigins(top!, sha, f.head, path, new Set(f.commits)));
|
|
1869
|
+
return { squash: true, origin: origins.get(key)?.get(line) };
|
|
1870
|
+
};
|
|
1871
|
+
// Each current line: its commit, and the runs that wrote it.
|
|
1872
|
+
const who = blamed.map((b) => {
|
|
1873
|
+
if (b.sha === null) return { line: b.line, sha: null, runs: [] as string[], narrowedBy: null as "hunks" | null, via: undefined as string[] | undefined };
|
|
1874
|
+
const sha = b.sha;
|
|
1875
|
+
const { squash, origin } = originOf(sha, b.origPath, b.origLine);
|
|
1876
|
+
const via = squash ? (origin ? [origin] : []) : undefined;
|
|
1877
|
+
// On a squash line blame at the head traced to one original, a run joined only through the other originals didn't write it.
|
|
1878
|
+
const refs = (runJoins.refs.get(sha) ?? []).filter((r) => !origin || r.joinedBy.some((j) => j !== "squash") || (r.via ?? []).includes(origin)).map((r) => r.id);
|
|
1879
|
+
const withHunks = refs.filter((id) => hunksOf(id, sha) !== null);
|
|
1880
|
+
if (withHunks.length === 0) return { line: b.line, sha, runs: refs, narrowedBy: null, via };
|
|
1881
|
+
const wrote = withHunks.filter((id) => hunksOf(id, sha)!.some((h) => h.path === b.origPath && h.start <= b.origLine && b.origLine <= h.end));
|
|
1882
|
+
// A run that recorded its hunks and doesn't cover the line didn't write it; a run that recorded none may have.
|
|
1883
|
+
return { line: b.line, sha, runs: wrote.length > 0 ? wrote : refs.filter((id) => !withHunks.includes(id)), narrowedBy: "hunks" as const, via };
|
|
1884
|
+
});
|
|
1885
|
+
const spans: WhySpan[] = [];
|
|
1886
|
+
for (const w of who) {
|
|
1887
|
+
const last = spans[spans.length - 1];
|
|
1888
|
+
const via = w.via;
|
|
1889
|
+
if (last && last.end === w.line - 1 && last.sha === w.sha && last.narrowedBy === w.narrowedBy && last.runs.join("\0") === w.runs.map((r) => `run:${r}`).join("\0") && last.via?.join("\0") === via?.join("\0")) {
|
|
1890
|
+
last.end = w.line;
|
|
1891
|
+
continue;
|
|
1892
|
+
}
|
|
1893
|
+
spans.push({ start: w.line, end: w.line, commit: w.sha ? `commit:${w.sha}` : null, sha: w.sha, runs: w.runs.map((r) => `run:${r}`), narrowedBy: w.narrowedBy, joinedBy: w.sha ? joinsOf(w.runs, [w.sha]) : [], ...(via ? { via } : {}) });
|
|
1894
|
+
}
|
|
1895
|
+
const ranges = (lines: number[]): LineRange[] => {
|
|
1896
|
+
const out: LineRange[] = [];
|
|
1897
|
+
for (const l of lines) {
|
|
1898
|
+
const last = out[out.length - 1];
|
|
1899
|
+
if (last && last.end === l - 1) last.end = l;
|
|
1900
|
+
else out.push({ start: l, end: l });
|
|
1901
|
+
}
|
|
1902
|
+
return out;
|
|
1903
|
+
};
|
|
1904
|
+
|
|
1905
|
+
// The decisions, most relevant first.
|
|
1906
|
+
const decisionNodes = [...nodes.values()].filter((n): n is DecisionNode => n.kind === "decision");
|
|
1907
|
+
const ownLines = (d: DecisionNode) => who.filter((w) => w.sha !== null && ownWork(joined.get(w.sha) ?? { contracts: [], authorship: [], decisions: [], carries: [] }, d)).length;
|
|
1908
|
+
const ORDER: WhyRelevance[] = ["carried", "path", "contract", "issue", "member", "related"];
|
|
1909
|
+
const ranked = decisionNodes.map((d) => {
|
|
1910
|
+
const lines = ownLines(d);
|
|
1911
|
+
const carried = lines > 0 || (fileLines === null && touched.some((t) => ownWork(joined.get(t.sha) ?? { contracts: [], authorship: [], decisions: [], carries: [] }, d)));
|
|
1912
|
+
const granularities = new Set(d.constrains.map((c) => c.granularity));
|
|
1913
|
+
const relevance: WhyRelevance = carried ? "carried" : ((["path", "contract", "issue", "member"] as const).find((g) => granularities.has(g)) ?? "related");
|
|
1914
|
+
// A narrower path constraint is more specific to the region.
|
|
1915
|
+
const specificity = Math.max(0, ...d.constrains.filter((c) => c.granularity === "path").map((c) => c.entry.length));
|
|
1916
|
+
return { d, entry: { decision: d.id, relevance, current: d.supersededBy === null, closed: d.closed, lines } satisfies WhyDecision, specificity };
|
|
1917
|
+
});
|
|
1918
|
+
ranked.sort(
|
|
1919
|
+
(a, b) =>
|
|
1920
|
+
Number(b.entry.current) - Number(a.entry.current) ||
|
|
1921
|
+
ORDER.indexOf(a.entry.relevance) - ORDER.indexOf(b.entry.relevance) ||
|
|
1922
|
+
b.entry.lines - a.entry.lines ||
|
|
1923
|
+
Number(b.entry.closed) - Number(a.entry.closed) ||
|
|
1924
|
+
b.specificity - a.specificity ||
|
|
1925
|
+
(b.d.decidedIn?.date ?? "").localeCompare(a.d.decidedIn?.date ?? "") ||
|
|
1926
|
+
a.d.id.localeCompare(b.d.id),
|
|
1927
|
+
);
|
|
1928
|
+
const decisions = ranked.map((r) => r.entry);
|
|
1929
|
+
|
|
1930
|
+
// The runs that wrote the current lines, most lines first; for a directory, every run in the walk.
|
|
1931
|
+
const runNodes = [...nodes.values()].filter((n): n is RunNode => n.kind === "run");
|
|
1932
|
+
const runEntry = (n: RunNode, lines: number, commits: string[]): WhyRun => {
|
|
1933
|
+
const r = runJoins.runs.get(n.run);
|
|
1934
|
+
const targets = edges.filter((e) => e.kind === "worked-on" && e.from === n.id).map((e) => nodes.get(e.to));
|
|
1935
|
+
const work = r?.unit ? targets.find((t): t is WorkNode => t?.kind === "work" && t.record === r.unit!.id) : undefined;
|
|
1936
|
+
const carried = new Set<string>();
|
|
1937
|
+
for (const t of targets) {
|
|
1938
|
+
if (t?.kind === "decision") carried.add(t.id);
|
|
1939
|
+
if (t?.kind === "work") for (const e of edges) if (e.kind === "implements" && e.from === t.id) carried.add(e.to);
|
|
1940
|
+
}
|
|
1941
|
+
const shas = commits.map((c) => c.slice("commit:".length));
|
|
1942
|
+
return { run: n.id, lines, commits, unit: r?.unit ? { id: r.unit.id, kind: r.unit.kind, node: work?.id ?? null } : null, decisions: [...carried], joinedBy: joinsOf([n.run], shas) };
|
|
1943
|
+
};
|
|
1944
|
+
let runs: WhyRun[];
|
|
1945
|
+
if (fileLines !== null) {
|
|
1946
|
+
const tally = new Map<string, { lines: number; commits: Set<string> }>();
|
|
1947
|
+
for (const w of who) {
|
|
1948
|
+
for (const id of w.runs) {
|
|
1949
|
+
const t = tally.get(id) ?? tally.set(id, { lines: 0, commits: new Set() }).get(id)!;
|
|
1950
|
+
t.lines++;
|
|
1951
|
+
t.commits.add(`commit:${w.sha}`);
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
runs = [...tally]
|
|
1955
|
+
.map(([id, t]) => ({ n: nodes.get(`run:${id}`) as RunNode, t }))
|
|
1956
|
+
.filter((x) => x.n !== undefined)
|
|
1957
|
+
.sort((a, b) => b.t.lines - a.t.lines || (b.n.startedAt ?? "").localeCompare(a.n.startedAt ?? "") || a.n.run.localeCompare(b.n.run))
|
|
1958
|
+
.map((x) => runEntry(x.n, x.t.lines, [...x.t.commits]));
|
|
1959
|
+
} else {
|
|
1960
|
+
runs = runNodes
|
|
1961
|
+
.sort((a, b) => (b.startedAt ?? "").localeCompare(a.startedAt ?? "") || a.run.localeCompare(b.run))
|
|
1962
|
+
.map((n) => runEntry(n, 0, edges.filter((e) => e.kind === "made-by" && e.to === n.id).map((e) => e.from)));
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
const explained = decisions.some((d) => d.current && d.relevance !== "related");
|
|
1966
|
+
const gaps: WhyGap[] = [];
|
|
1967
|
+
if (!explained) {
|
|
1968
|
+
gaps.push({
|
|
1969
|
+
code: "intent-why-no-decision",
|
|
1970
|
+
message: readsRecords ? `no current decision governs ${region.path}, and none is carried out by what made its lines` : `no record kind was read, so no decision can account for ${region.path}`,
|
|
1971
|
+
});
|
|
1972
|
+
}
|
|
1973
|
+
const committed = who.filter((w) => w.sha !== null);
|
|
1974
|
+
if (fileLines !== null ? committed.length > 0 && committed.every((w) => w.runs.length === 0) : touched.length > 0 && runNodes.length === 0) {
|
|
1975
|
+
gaps.push({ code: "intent-why-no-run", message: `no agent run is joined to the commits that made ${fileLines !== null ? "the current lines of " : ""}${region.path}` });
|
|
1976
|
+
}
|
|
1977
|
+
const uncommitted = who.filter((w) => w.sha === null).map((w) => w.line);
|
|
1978
|
+
if (uncommitted.length > 0) gaps.push({ code: "intent-why-uncommitted", message: `${uncommitted.length} ${uncommitted.length === 1 ? "line is" : "lines are"} not committed yet`, lines: ranges(uncommitted) });
|
|
1979
|
+
const ambiguous = who.filter((w) => w.runs.length > 1).map((w) => w.line);
|
|
1980
|
+
if (ambiguous.length > 0) {
|
|
1981
|
+
gaps.push({ code: "intent-why-run-ambiguous", message: `${ambiguous.length} ${ambiguous.length === 1 ? "line comes" : "lines come"} from a commit several runs made, and no run's recorded hunks say which wrote ${ambiguous.length === 1 ? "it" : "them"}`, lines: ranges(ambiguous) });
|
|
1982
|
+
}
|
|
1983
|
+
return { lines: fileLines, blame: spans, decisions, runs, explained, gaps };
|
|
1984
|
+
}
|
|
1328
1985
|
}
|