@intentius/chant 0.102.0 → 0.104.1
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/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/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/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/fan-out.d.ts +33 -0
- package/dist/cli/handlers/fan-out.d.ts.map +1 -1
- package/dist/cli/handlers/operator.d.ts +7 -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/main.d.ts.map +1 -1
- package/dist/cli/mcp/op-tools.d.ts.map +1 -1
- package/dist/cli/mcp/workspace-tools.d.ts +3 -2
- package/dist/cli/mcp/workspace-tools.d.ts.map +1 -1
- package/dist/cli/registry.d.ts +63 -1
- package/dist/cli/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.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/verbs/shell.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/gated-waves.d.ts +147 -0
- package/dist/gated-waves.d.ts.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/lexicon.d.ts +48 -0
- package/dist/lexicon.d.ts.map +1 -1
- package/dist/lifecycle/gate-ledger.d.ts +7 -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/lint/post-synth.d.ts +18 -0
- package/dist/lint/post-synth.d.ts.map +1 -1
- package/dist/op/activities/activity-contracts.d.ts +126 -0
- package/dist/op/activities/activity-contracts.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 +4 -0
- package/dist/op/activities/index.d.ts.map +1 -1
- package/dist/op/activity-contract.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/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/factory.d.ts +83 -0
- package/dist/op/factory.d.ts.map +1 -0
- package/dist/op/index.d.ts +4 -1
- package/dist/op/index.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/types.d.ts +8 -0
- package/dist/op/types.d.ts.map +1 -1
- 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/telemetry-attribution.d.ts +31 -0
- package/dist/telemetry-attribution.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/vendor/js-yaml-load.d.ts +56 -0
- package/dist/vendor/js-yaml-load.d.ts.map +1 -0
- 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 +27 -3
- package/dist/workspace/box-factory.d.ts.map +1 -1
- 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/checks.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 +2 -1
- package/dist/workspace/conformance/index.d.ts.map +1 -1
- package/dist/workspace/conformance/vitest.d.ts +9 -2
- package/dist/workspace/conformance/vitest.d.ts.map +1 -1
- package/dist/workspace/conformance/writer.d.ts +108 -14
- package/dist/workspace/conformance/writer.d.ts.map +1 -1
- 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 +65 -0
- package/dist/workspace/declaration.d.ts.map +1 -1
- package/dist/workspace/declaration.schema.json +153 -4
- 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/init.d.ts +21 -0
- package/dist/workspace/init.d.ts.map +1 -1
- package/dist/workspace/intent-cli.d.ts +1 -1
- package/dist/workspace/intent-cli.d.ts.map +1 -1
- package/dist/workspace/intent-record.d.ts +28 -1
- package/dist/workspace/intent-record.d.ts.map +1 -1
- package/dist/workspace/intent.d.ts +102 -5
- 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 +48 -0
- 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-upgrade.d.ts +31 -2
- package/dist/workspace/lineage-upgrade.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/reason-codes.d.ts +33 -4
- package/dist/workspace/reason-codes.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-cli.d.ts +7 -0
- 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-write.d.ts +66 -6
- package/dist/workspace/records-write.d.ts.map +1 -1
- package/dist/workspace/records.d.ts +28 -9
- package/dist/workspace/records.d.ts.map +1 -1
- package/dist/workspace/runs-cli.d.ts +138 -6
- package/dist/workspace/runs-cli.d.ts.map +1 -1
- package/dist/workspace/runs.d.ts +132 -11
- package/dist/workspace/runs.d.ts.map +1 -1
- package/dist/workspace/session-kinds.d.ts +1 -1
- package/dist/workspace/session-kinds.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 +2 -0
- package/dist/workspace/status-gates.d.ts.map +1 -1
- package/dist/workspace/status.d.ts +54 -0
- package/dist/workspace/status.d.ts.map +1 -1
- package/dist/workspace/symbols.d.ts +16 -5
- package/dist/workspace/symbols.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 +6 -1
- package/dist/workspace/trust/seal.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.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/workspace-kinds.schema.json +122 -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 +6 -2
- package/dist/workspace/write-scope.d.ts.map +1 -1
- package/dist/yaml.d.ts +1 -1
- package/dist/yaml.d.ts.map +1 -1
- package/package.json +6 -1
- 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/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/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/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/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/operator.test.ts +21 -0
- package/src/cli/handlers/operator.ts +34 -3
- package/src/cli/handlers/pr.ts +373 -0
- package/src/cli/handlers/run.ts +1 -0
- package/src/cli/main.test.ts +20 -0
- package/src/cli/main.ts +185 -23
- 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 +1 -1
- package/src/cli/mcp/workspace-tools.ts +34 -6
- package/src/cli/registry.ts +63 -1
- 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/discovery/sandbox/bundle.ts +1 -1
- 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/index.ts +1 -0
- package/src/lexicon.ts +51 -0
- package/src/lifecycle/gate-ledger.ts +7 -0
- package/src/lifecycle/git.ts +102 -16
- 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/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 +6 -0
- 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/decide-backend.ts +5 -1
- package/src/op/decide-read-inputs.ts +33 -5
- package/src/op/factory.e2e.test.ts +232 -0
- package/src/op/factory.ts +118 -0
- package/src/op/index.ts +9 -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/types.ts +8 -0
- package/src/op/work-lease-run.ts +3 -0
- 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/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/vendor/js-yaml-load.test.ts +115 -0
- package/src/vendor/js-yaml-load.ts +1939 -0
- package/src/workspace/__fixtures__/studio-template-84c8b21.json +1 -1
- package/src/workspace/app-kind.test.ts +196 -0
- package/src/workspace/box-cli.ts +113 -0
- package/src/workspace/box-factory.test.ts +4 -1
- package/src/workspace/box-factory.ts +37 -4
- 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/chant-migrations.e2e.test.ts +17 -5
- package/src/workspace/checks/boxes.test.ts +3 -0
- package/src/workspace/checks.ts +10 -3
- package/src/workspace/component-environments.test.ts +105 -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 +7 -2
- package/src/workspace/conformance/__writer_fixture__/answers/answer.schema.json +42 -2
- 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 +96 -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 +14 -8
- package/src/workspace/conformance/__writer_fixture__/sessions/session.schema.json +187 -6
- package/src/workspace/conformance/__writer_fixture__/work/work.schema.json +25 -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 +2 -1
- package/src/workspace/conformance/index.mjs +22 -1
- package/src/workspace/conformance/index.ts +5 -1
- package/src/workspace/conformance/vitest.ts +33 -1
- package/src/workspace/conformance/writer-conformance.e2e.test.ts +49 -3
- package/src/workspace/conformance/writer.test.ts +32 -2
- package/src/workspace/conformance/writer.ts +339 -28
- package/src/workspace/decide.test.ts +208 -4
- package/src/workspace/decide.ts +427 -73
- package/src/workspace/decision-points.schema.json +11 -4
- package/src/workspace/declaration.schema.json +153 -4
- package/src/workspace/declaration.ts +141 -0
- 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 +2 -2
- package/src/workspace/graph.schema.json +67 -0
- package/src/workspace/identity.test.ts +23 -0
- package/src/workspace/init.ts +82 -2
- package/src/workspace/intent-cli.ts +26 -9
- package/src/workspace/intent-patch-id.test.ts +162 -0
- package/src/workspace/intent-record.schema.json +130 -3
- package/src/workspace/intent-record.ts +74 -28
- 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 +5 -5
- package/src/workspace/intent.schema.json +234 -4
- package/src/workspace/intent.ts +260 -66
- 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 +157 -2
- 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 +162 -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/profiles.test.ts +159 -0
- package/src/workspace/read-contract.test.ts +2 -2
- package/src/workspace/reason-codes.test.ts +13 -1
- package/src/workspace/reason-codes.ts +38 -4
- package/src/workspace/record-sessions.ts +9 -8
- package/src/workspace/records-amend.schema.json +78 -0
- package/src/workspace/records-cli.ts +20 -6
- package/src/workspace/records-close.schema.json +78 -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 +7 -0
- package/src/workspace/records-review.schema.json +78 -0
- package/src/workspace/records-sessions-write.test.ts +69 -0
- package/src/workspace/records-sessions.test.ts +22 -0
- package/src/workspace/records-write.ts +192 -25
- package/src/workspace/records.schema.json +16 -0
- package/src/workspace/records.ts +50 -9
- 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 +343 -14
- package/src/workspace/runs-statement.test.ts +239 -0
- package/src/workspace/runs-write.schema.json +416 -5
- package/src/workspace/runs.schema.json +451 -4
- package/src/workspace/runs.test.ts +39 -0
- package/src/workspace/runs.ts +296 -35
- package/src/workspace/session-kinds.ts +3 -3
- package/src/workspace/squash.ts +198 -0
- package/src/workspace/status-contract.test.ts +5 -2
- package/src/workspace/status-gates.ts +3 -1
- package/src/workspace/status.schema.json +126 -3
- package/src/workspace/status.ts +90 -1
- package/src/workspace/symbols.ts +20 -9
- package/src/workspace/trust/run-commits.ts +115 -0
- package/src/workspace/trust/run-statement.ts +226 -0
- package/src/workspace/trust/seal.ts +8 -2
- 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.ts +3 -0
- package/src/workspace/work-evidence.schema.json +3 -0
- package/src/workspace/work-size.test.ts +77 -0
- package/src/workspace/work-size.ts +93 -0
- package/src/workspace/workspace-kinds.schema.json +122 -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 +16 -1
- package/src/workspace/write-scope.ts +33 -11
- package/src/yaml.ts +31 -21
package/src/workspace/runs.ts
CHANGED
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
* the source of its prices, the transcript pinned by hash, and the commits
|
|
24
24
|
* the run made, each with its `git patch-id --stable` (#3036) and, when
|
|
25
25
|
* the writer knows them, the hunks of it the run wrote (#3034).
|
|
26
|
+
* - `statement`: after the end, a DSSE envelope a runner or steward key
|
|
27
|
+
* signed over the run (#3192, ./trust/run-statement.ts). A run may have
|
|
28
|
+
* several, such as one per signer; none changes the record they sign.
|
|
26
29
|
*
|
|
27
30
|
* The file name is `_agent-runs`, not `runs`, because an Op run already has
|
|
28
31
|
* `<env>/runs__<op>.jsonl` (`../lifecycle/run-ledger.ts`).
|
|
@@ -33,6 +36,18 @@
|
|
|
33
36
|
* run's end can also list commits, which joins a commit that carries no
|
|
34
37
|
* trailer. `workspace runs` reports both, and `graph --intent` links each
|
|
35
38
|
* commit to its run.
|
|
39
|
+
*
|
|
40
|
+
* When neither holds, as after a rebase or a cherry-pick that dropped the
|
|
41
|
+
* trailer, a commit whose `git patch-id --stable` equals one the run's end
|
|
42
|
+
* recorded joins the run by content (#3036), marked `patch-id`. A content join
|
|
43
|
+
* never overrides a trailer or a record join: it is tried only for a commit
|
|
44
|
+
* that has neither. A squash of several commits has a patch-id of its own, so
|
|
45
|
+
* it never joins this way.
|
|
46
|
+
*
|
|
47
|
+
* A squash merge's commit carries none of its pull request's trailers or
|
|
48
|
+
* SHAs. When a read is asked to follow squashes (#3035, `squash.ts`), the
|
|
49
|
+
* squash commit joins every run its pull request's original commits join,
|
|
50
|
+
* marked `squash` with the originals in `via`.
|
|
36
51
|
*/
|
|
37
52
|
|
|
38
53
|
import { execFileSync } from "node:child_process";
|
|
@@ -40,10 +55,13 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
40
55
|
import { readFileSync, statSync } from "node:fs";
|
|
41
56
|
import { resolve } from "node:path";
|
|
42
57
|
import { z } from "zod";
|
|
43
|
-
import { fetchLifecycleStatus,
|
|
58
|
+
import { describeLifecyclePush, fetchLifecycleStatus, type LifecyclePushStatus, pushLifecycleStatus, readBlobBySha, RefCASConflictError, writeLedgerFiles } from "../lifecycle/git";
|
|
44
59
|
import { resolveMemberLedger } from "../lifecycle/member-ledger";
|
|
45
60
|
import { sortedJsonReplacer } from "../utils";
|
|
61
|
+
import { followSquashes, type SquashFollow } from "./squash";
|
|
46
62
|
import { RUN_TRAILER, parseRecordRef, type RecordRef } from "./trailers";
|
|
63
|
+
import type { DsseEnvelope } from "./trust/dsse";
|
|
64
|
+
import { runRecordDigest, type RunAttestation } from "./trust/run-statement";
|
|
47
65
|
|
|
48
66
|
/** The directory on `chant/lifecycle` that holds the agent runs, under the workspace root's ledger prefix. */
|
|
49
67
|
export const AGENT_RUNS_DIR = "_agent-runs";
|
|
@@ -162,7 +180,16 @@ export interface RunEndLine {
|
|
|
162
180
|
commits: RunCommit[];
|
|
163
181
|
}
|
|
164
182
|
|
|
165
|
-
|
|
183
|
+
/** A `statement` line of `_agent-runs/<id>.jsonl`: a signed statement over the run (#3192). */
|
|
184
|
+
export interface RunStatementLine {
|
|
185
|
+
version: 1;
|
|
186
|
+
event: "statement";
|
|
187
|
+
run: string;
|
|
188
|
+
at: string;
|
|
189
|
+
envelope: DsseEnvelope;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export type RunLine = RunStartLine | RunEndLine | RunStatementLine;
|
|
166
193
|
|
|
167
194
|
// ── The caller's fields ──────────────────────────────────────────────────────
|
|
168
195
|
|
|
@@ -231,7 +258,7 @@ export type RunRecordInput = z.infer<typeof runRecordInputSchema>;
|
|
|
231
258
|
// ── Errors ───────────────────────────────────────────────────────────────────
|
|
232
259
|
|
|
233
260
|
/** Why a run write was refused. */
|
|
234
|
-
export type RunWriteRefusal = "run-exists" | "run-unknown" | "run-ended" | "write-input-invalid" | "not-a-git-repository";
|
|
261
|
+
export type RunWriteRefusal = "run-exists" | "run-unknown" | "run-ended" | "run-not-ended" | "run-statement-mismatch" | "write-input-invalid" | "not-a-git-repository";
|
|
235
262
|
|
|
236
263
|
export class RunWriteError extends Error {
|
|
237
264
|
constructor(
|
|
@@ -266,6 +293,40 @@ export function patchIdOf(top: string, sha: string): string | null {
|
|
|
266
293
|
return out?.trim().split(/\s+/)[0] || null;
|
|
267
294
|
}
|
|
268
295
|
|
|
296
|
+
/** Parse `git patch-id` output, `<patch-id> <commit>` per line, into commit to patch-id. */
|
|
297
|
+
function parsePatchIds(out: string | undefined): Map<string, string> {
|
|
298
|
+
const ids = new Map<string, string>();
|
|
299
|
+
for (const line of (out ?? "").split("\n")) {
|
|
300
|
+
const [patchId, sha] = line.trim().split(/\s+/);
|
|
301
|
+
if (patchId && sha && !ids.has(sha)) ids.set(sha, patchId);
|
|
302
|
+
}
|
|
303
|
+
return ids;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* `git patch-id --stable` of each commit, in two git calls however many there
|
|
308
|
+
* are (#3036). A commit with no patch, such as a merge, is left out.
|
|
309
|
+
*/
|
|
310
|
+
export function patchIdsOf(top: string, shas: string[]): Map<string, string> {
|
|
311
|
+
if (shas.length === 0) return new Map();
|
|
312
|
+
const patches = git(top, ["log", "--no-walk=unsorted", "--stdin", "--no-merges", "--format=commit %H", "--patch", "--no-color", "--no-ext-diff"], `${shas.join("\n")}\n`);
|
|
313
|
+
if (!patches?.trim()) return new Map();
|
|
314
|
+
return parsePatchIds(git(top, ["patch-id", "--stable"], patches));
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* `git patch-id --stable` of each commit reachable from `rev` and committed
|
|
319
|
+
* after `since` (ISO 8601), merges left out (#3036). A rebase or a
|
|
320
|
+
* cherry-pick commits anew, so a rewritten commit is never older than the
|
|
321
|
+
* one it was rewritten from.
|
|
322
|
+
*/
|
|
323
|
+
export function patchIdsSince(top: string, rev: string, since: string): Map<string, string> {
|
|
324
|
+
if (!commitId(top, rev)) return new Map();
|
|
325
|
+
const patches = git(top, ["log", rev, `--since=${since}`, "--no-merges", "--format=commit %H", "--patch", "--no-color", "--no-ext-diff"]);
|
|
326
|
+
if (!patches?.trim()) return new Map();
|
|
327
|
+
return parsePatchIds(git(top, ["patch-id", "--stable"], patches));
|
|
328
|
+
}
|
|
329
|
+
|
|
269
330
|
function hashFile(path: string): RunPin {
|
|
270
331
|
const bytes = readFileSync(path);
|
|
271
332
|
return { sha256: createHash("sha256").update(bytes).digest("hex"), bytes: statSync(path).size, ref: null };
|
|
@@ -366,7 +427,8 @@ export function parseRunFile(content: string, id: string): { lines: RunLine[]; m
|
|
|
366
427
|
for (const raw of content.split("\n").map((l) => l.trim()).filter(Boolean)) {
|
|
367
428
|
try {
|
|
368
429
|
const v = JSON.parse(raw) as Partial<RunLine>;
|
|
369
|
-
const
|
|
430
|
+
const statement = v.event === "statement" && typeof (v as Partial<RunStatementLine>).envelope === "object" && (v as Partial<RunStatementLine>).envelope !== null;
|
|
431
|
+
const ok = v.version === 1 && (v.event === "start" || v.event === "end" || statement) && v.run === id && typeof v.at === "string";
|
|
370
432
|
if (ok) lines.push(v as RunLine);
|
|
371
433
|
else malformed++;
|
|
372
434
|
} catch {
|
|
@@ -382,10 +444,10 @@ export async function runsDir(rootOnDisk: string): Promise<string> {
|
|
|
382
444
|
return `${prefix}${AGENT_RUNS_DIR}`;
|
|
383
445
|
}
|
|
384
446
|
|
|
385
|
-
/** Every run file in `dir` on the local branch, by run id, and the branch tip read. Never fetches. */
|
|
386
|
-
export function readRunFiles(top: string, dir: string): { tip: string | null; files: Map<string, { path: string; content: string }> } {
|
|
447
|
+
/** Every run file in `dir` on the local branch, or on `ref` when given, by run id, and the branch tip read. Never fetches. */
|
|
448
|
+
export function readRunFiles(top: string, dir: string, ref = `refs/heads/${LEDGER_BRANCH}`): { tip: string | null; files: Map<string, { path: string; content: string }> } {
|
|
387
449
|
const files = new Map<string, { path: string; content: string }>();
|
|
388
|
-
const tip = commitId(top,
|
|
450
|
+
const tip = commitId(top, ref) ?? null;
|
|
389
451
|
if (!tip) return { tip, files };
|
|
390
452
|
const listing = git(top, ["ls-tree", "-z", `${tip}:${dir}`]);
|
|
391
453
|
if (!listing) return { tip, files };
|
|
@@ -422,6 +484,8 @@ export interface RunLedgerWrite {
|
|
|
422
484
|
commit: string;
|
|
423
485
|
/** Whether chant/lifecycle reached the remote; false with no remote too. */
|
|
424
486
|
pushed: boolean;
|
|
487
|
+
/** Why it did not, when `pushed` is false (#3391): no remote, a remote that moved on, or git's refusal. */
|
|
488
|
+
notPushed?: string;
|
|
425
489
|
}
|
|
426
490
|
|
|
427
491
|
export interface RunWriteResult {
|
|
@@ -459,8 +523,9 @@ async function appendRun(top: string, rootOnDisk: string, id: string, make: (exi
|
|
|
459
523
|
}
|
|
460
524
|
}
|
|
461
525
|
if (commit === undefined) throw lastErr;
|
|
462
|
-
const
|
|
463
|
-
|
|
526
|
+
const push: LifecyclePushStatus = await pushLifecycleStatus({ cwd: top }).catch((err) => ({ status: "failed" as const, remote: "(unknown)", stderr: err instanceof Error ? err.message : String(err) }));
|
|
527
|
+
const notPushed = describeLifecyclePush(push);
|
|
528
|
+
return { id, lines: written, ledger: { branch: LEDGER_BRANCH, path, commit, pushed: push.status === "pushed", ...(notPushed ? { notPushed } : {}) } };
|
|
464
529
|
}
|
|
465
530
|
|
|
466
531
|
export interface RunWriteContext {
|
|
@@ -534,16 +599,57 @@ export async function recordRun(fields: unknown, ctx: RunWriteContext): Promise<
|
|
|
534
599
|
);
|
|
535
600
|
}
|
|
536
601
|
|
|
602
|
+
/**
|
|
603
|
+
* `runs sign <id>`: append a statement over an ended run (#3192). The caller
|
|
604
|
+
* has built or checked the envelope against the record whose hash is
|
|
605
|
+
* `recordSha256`; the append refuses if the ledger's record is not that one.
|
|
606
|
+
*/
|
|
607
|
+
export async function appendRunStatement(id: string, envelope: DsseEnvelope, recordSha256: string, ctx: RunWriteContext): Promise<RunWriteResult> {
|
|
608
|
+
if (!RUN_ID_PATTERN.test(id)) throw new RunWriteError("run-unknown", `${JSON.stringify(id)} is not a run id`);
|
|
609
|
+
const at = (ctx.now?.() ?? new Date()).toISOString();
|
|
610
|
+
return appendRun(
|
|
611
|
+
ctx.top,
|
|
612
|
+
ctx.rootOnDisk,
|
|
613
|
+
id,
|
|
614
|
+
(existing) => {
|
|
615
|
+
const start = existing.find((l): l is RunStartLine => l.event === "start");
|
|
616
|
+
const end = existing.find((l): l is RunEndLine => l.event === "end");
|
|
617
|
+
if (!start) throw new RunWriteError("run-unknown", `the ledger has no agent run ${id}`);
|
|
618
|
+
if (!end) throw new RunWriteError("run-not-ended", `agent run ${id} has not ended; a statement is signed over a run's whole record, so record its end first`);
|
|
619
|
+
if (runRecordDigest(start, end) !== recordSha256) throw new RunWriteError("run-statement-mismatch", `agent run ${id}'s record changed while it was being signed; sign it again`);
|
|
620
|
+
return [{ version: 1, event: "statement", run: id, at, envelope }];
|
|
621
|
+
},
|
|
622
|
+
`Agent run statement: ${id}`,
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
|
|
537
626
|
// ── Folding a run ────────────────────────────────────────────────────────────
|
|
538
627
|
|
|
628
|
+
/**
|
|
629
|
+
* How a commit joins a run: `trailer` when it carries `Chant-Run` with the
|
|
630
|
+
* run's id, `record` when the run's end lists it, `patch-id` when it has
|
|
631
|
+
* neither and its `git patch-id --stable` equals a commit's the run's end
|
|
632
|
+
* recorded (#3036), `squash` when it squashes a pull request whose original
|
|
633
|
+
* commits join the run one of those ways, and the read was asked to follow
|
|
634
|
+
* squashes (#3035).
|
|
635
|
+
*/
|
|
636
|
+
export type RunJoin = "trailer" | "record" | "patch-id" | "squash";
|
|
637
|
+
|
|
638
|
+
/** The order a reader lists joins in: the commit's own trailer first, a squash's originals last. */
|
|
639
|
+
export const RUN_JOIN_ORDER: readonly RunJoin[] = ["trailer", "record", "patch-id", "squash"];
|
|
640
|
+
|
|
539
641
|
/** A commit a run made, as the read reports it. */
|
|
540
642
|
export interface RunCommitView {
|
|
541
643
|
sha: string;
|
|
542
644
|
patchId: string | null;
|
|
543
|
-
/** How the commit joins the run
|
|
544
|
-
joinedBy:
|
|
545
|
-
/** The hunks of the commit the run's end says it wrote, or null when it gives none (#3034). */
|
|
645
|
+
/** How the commit joins the run. */
|
|
646
|
+
joinedBy: RunJoin[];
|
|
647
|
+
/** The hunks of the commit the run's end says it wrote, or null when it gives none (#3034). Null for a commit joined by patch-id, whose lines may have moved. */
|
|
546
648
|
hunks: RunHunk[] | null;
|
|
649
|
+
/** For a commit joined by patch-id (#3036): the commit the run's end recorded with the same patch-id, which this one rewrites. */
|
|
650
|
+
recordedAs?: string;
|
|
651
|
+
/** For a squash joined to the run (#3035): the pull request's original commits through which it joins. */
|
|
652
|
+
via?: string[];
|
|
547
653
|
}
|
|
548
654
|
|
|
549
655
|
/** One run, its start and end folded together, as `runs --json` and `graph --intent` report it. */
|
|
@@ -572,6 +678,12 @@ export interface RunView {
|
|
|
572
678
|
decisions: string[];
|
|
573
679
|
/** Its file on the branch. */
|
|
574
680
|
ledger: string;
|
|
681
|
+
/** The SHA-256 a statement signs: of the start and end lines (#3192). Null until the run ends. */
|
|
682
|
+
record: { sha256: string } | null;
|
|
683
|
+
/** The signed statements the ledger holds for the run, oldest first (#3192). */
|
|
684
|
+
statements: { at: string; envelope: DsseEnvelope }[];
|
|
685
|
+
/** The statements judged against the runner keys at base. Set by the `runs` read and `runs verify`, never by a write. */
|
|
686
|
+
attestation?: RunAttestation;
|
|
575
687
|
}
|
|
576
688
|
|
|
577
689
|
/** Fold a run's lines into one view, or undefined when it has no start. */
|
|
@@ -601,6 +713,8 @@ export function foldRun(id: string, path: string, lines: RunLine[]): RunView | u
|
|
|
601
713
|
commits: (end?.commits ?? []).map((c) => ({ sha: c.sha, patchId: c.patchId, joinedBy: ["record" as const], hunks: Array.isArray(c.hunks) && c.hunks.length > 0 ? c.hunks : null })),
|
|
602
714
|
decisions: [],
|
|
603
715
|
ledger: path,
|
|
716
|
+
record: end ? { sha256: runRecordDigest(start, end) } : null,
|
|
717
|
+
statements: lines.filter((l): l is RunStatementLine => l.event === "statement").map((l) => ({ at: l.at, envelope: l.envelope })),
|
|
604
718
|
};
|
|
605
719
|
}
|
|
606
720
|
|
|
@@ -650,6 +764,45 @@ export function joinTrailerCommits(runs: Map<string, RunView>, byTrailer: Map<st
|
|
|
650
764
|
}
|
|
651
765
|
}
|
|
652
766
|
|
|
767
|
+
/** A day, the slack {@link joinPatchIdCommits} gives a run's start against clocks that disagree. */
|
|
768
|
+
const CLOCK_SLACK_MS = 24 * 60 * 60 * 1000;
|
|
769
|
+
|
|
770
|
+
/** Each recorded patch-id, to the runs whose end listed a commit with it and that commit. */
|
|
771
|
+
export function recordedPatchIds(runs: Iterable<RunView>): Map<string, { run: string; sha: string }[]> {
|
|
772
|
+
const out = new Map<string, { run: string; sha: string }[]>();
|
|
773
|
+
for (const r of runs) {
|
|
774
|
+
for (const c of r.commits) {
|
|
775
|
+
if (!c.patchId || !c.joinedBy.includes("record")) continue;
|
|
776
|
+
const list = out.get(c.patchId) ?? out.set(c.patchId, []).get(c.patchId)!;
|
|
777
|
+
if (!list.some((x) => x.run === r.id && x.sha === c.sha)) list.push({ run: r.id, sha: c.sha });
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return out;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
/**
|
|
784
|
+
* Add to each run the commits on `rev`'s history that join it by content
|
|
785
|
+
* (#3036): a commit that no run lists, that carries no `Chant-Run`, and whose
|
|
786
|
+
* patch-id equals one the run's end recorded. Only commits made since the
|
|
787
|
+
* earliest such run started are read, less a day for clocks.
|
|
788
|
+
*/
|
|
789
|
+
export function joinPatchIdCommits(runs: Map<string, RunView>, byTrailer: Map<string, string[]>, top: string, rev = "HEAD"): void {
|
|
790
|
+
const recorded = recordedPatchIds(runs.values());
|
|
791
|
+
if (recorded.size === 0) return;
|
|
792
|
+
const starts = [...new Set([...recorded.values()].flat().map((x) => x.run))].map((id) => Date.parse(runs.get(id)!.startedAt)).filter((t) => !Number.isNaN(t));
|
|
793
|
+
if (starts.length === 0) return;
|
|
794
|
+
const since = new Date(Math.min(...starts) - CLOCK_SLACK_MS).toISOString();
|
|
795
|
+
const joined = new Set<string>([...byTrailer.values()].flat());
|
|
796
|
+
for (const r of runs.values()) for (const c of r.commits) joined.add(c.sha);
|
|
797
|
+
for (const [sha, patchId] of patchIdsSince(top, rev, since)) {
|
|
798
|
+
if (joined.has(sha)) continue;
|
|
799
|
+
for (const hit of recorded.get(patchId) ?? []) {
|
|
800
|
+
const run = runs.get(hit.run)!;
|
|
801
|
+
if (!run.commits.some((c) => c.sha === sha)) run.commits.push({ sha, patchId, joinedBy: ["patch-id"], hunks: null, recordedAs: hit.sha });
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
|
|
653
806
|
// ── Joining commits to runs, for the intent walks ────────────────────────────
|
|
654
807
|
|
|
655
808
|
/** A run as a commit in the intent walks names it: enough to say which model and harness made the change, and for whom. */
|
|
@@ -664,16 +817,39 @@ export interface RunRef {
|
|
|
664
817
|
by: string | null;
|
|
665
818
|
agent: string | null;
|
|
666
819
|
unit: string | null;
|
|
667
|
-
/** `trailer`: the commit carries `Chant-Run` with the id. `record`: the run's end lists the commit. */
|
|
668
|
-
joinedBy:
|
|
820
|
+
/** `trailer`: the commit carries `Chant-Run` with the id. `record`: the run's end lists the commit. `patch-id`: neither, and the commit's patch-id equals one the run recorded (#3036). */
|
|
821
|
+
joinedBy: RunJoin[];
|
|
822
|
+
/** For a `patch-id` join: the commit the run's end recorded with the same patch-id (#3036). */
|
|
823
|
+
recordedAs?: string;
|
|
824
|
+
/** For a `squash` join: the pull request's original commits that join the run (#3035). */
|
|
825
|
+
via?: string[];
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
/**
|
|
829
|
+
* A commit joined to one run by its trailer or the run's record whose content
|
|
830
|
+
* matches a commit another run recorded (#3036). The content join is not made,
|
|
831
|
+
* since a patch-id join never overrides the others; the intent walk reports it
|
|
832
|
+
* as a finding.
|
|
833
|
+
*/
|
|
834
|
+
export interface RunJoinConflict {
|
|
835
|
+
sha: string;
|
|
836
|
+
/** The runs the commit's trailer or the runs' records join it to. */
|
|
837
|
+
joined: string[];
|
|
838
|
+
/** The other runs whose end recorded a commit with the same patch-id, and that commit. */
|
|
839
|
+
content: { run: string; sha: string }[];
|
|
669
840
|
}
|
|
670
841
|
|
|
671
842
|
/**
|
|
672
843
|
* For each commit, the runs that made it: the run its `Chant-Run` trailer
|
|
673
|
-
* names, and every run whose end lists it.
|
|
674
|
-
*
|
|
844
|
+
* names, and every run whose end lists it. A commit with neither joins every
|
|
845
|
+
* run whose end recorded its patch-id (#3036). Reads the run ledger once from
|
|
846
|
+
* the local branch; never fetches.
|
|
675
847
|
*/
|
|
676
|
-
export async function runsForCommits(
|
|
848
|
+
export async function runsForCommits(
|
|
849
|
+
top: string,
|
|
850
|
+
rootOnDisk: string,
|
|
851
|
+
commits: { sha: string; run: string | null }[],
|
|
852
|
+
): Promise<{ refs: Map<string, RunRef[]>; runs: Map<string, RunView>; conflicts: RunJoinConflict[] }> {
|
|
677
853
|
let runs = new Map<string, RunView>();
|
|
678
854
|
try {
|
|
679
855
|
runs = (await readRuns(top, rootOnDisk)).runs;
|
|
@@ -682,28 +858,113 @@ export async function runsForCommits(top: string, rootOnDisk: string, commits: {
|
|
|
682
858
|
}
|
|
683
859
|
const listing = new Map<string, string[]>();
|
|
684
860
|
for (const r of runs.values()) for (const c of r.commits) (listing.get(c.sha) ?? listing.set(c.sha, []).get(c.sha)!).push(r.id);
|
|
861
|
+
// The content join (#3036): only when some run recorded a patch-id, and only for the commits read.
|
|
862
|
+
const recorded = recordedPatchIds(runs.values());
|
|
863
|
+
const patchIds = recorded.size > 0 ? patchIdsOf(top, commits.map((c) => c.sha)) : new Map<string, string>();
|
|
685
864
|
const refs = new Map<string, RunRef[]>();
|
|
865
|
+
const conflicts: RunJoinConflict[] = [];
|
|
866
|
+
const refOf = (id: string, joinedBy: RunJoin[], recordedAs?: string): RunRef => {
|
|
867
|
+
const r = runs.get(id);
|
|
868
|
+
return {
|
|
869
|
+
id,
|
|
870
|
+
recorded: r !== undefined,
|
|
871
|
+
state: r?.state ?? null,
|
|
872
|
+
harness: r?.harness.name ?? null,
|
|
873
|
+
model: r?.model ?? null,
|
|
874
|
+
provider: r?.provider ?? null,
|
|
875
|
+
by: r?.by ?? null,
|
|
876
|
+
agent: r?.agent ?? null,
|
|
877
|
+
unit: r?.unit?.id ?? null,
|
|
878
|
+
joinedBy,
|
|
879
|
+
...(recordedAs ? { recordedAs } : {}),
|
|
880
|
+
};
|
|
881
|
+
};
|
|
686
882
|
for (const c of commits) {
|
|
687
|
-
const
|
|
883
|
+
const listed = listing.get(c.sha) ?? [];
|
|
884
|
+
const ids = [...new Set([...(c.run ? [c.run] : []), ...listed])];
|
|
885
|
+
const matches = (recorded.get(patchIds.get(c.sha) ?? "") ?? []).filter((m) => m.sha !== c.sha);
|
|
886
|
+
if (ids.length > 0) {
|
|
887
|
+
const others = matches.filter((m) => !ids.includes(m.run));
|
|
888
|
+
if (others.length > 0) conflicts.push({ sha: c.sha, joined: ids, content: others });
|
|
889
|
+
refs.set(
|
|
890
|
+
c.sha,
|
|
891
|
+
ids.map((id) => refOf(id, [...(c.run === id ? ["trailer" as const] : []), ...(listed.includes(id) ? ["record" as const] : [])])),
|
|
892
|
+
);
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
const byRun = new Map<string, string>();
|
|
896
|
+
for (const m of matches) if (!byRun.has(m.run)) byRun.set(m.run, m.sha);
|
|
688
897
|
refs.set(
|
|
689
898
|
c.sha,
|
|
690
|
-
|
|
691
|
-
const r = runs.get(id);
|
|
692
|
-
const joinedBy: ("trailer" | "record")[] = [...(c.run === id ? ["trailer" as const] : []), ...((listing.get(c.sha) ?? []).includes(id) ? ["record" as const] : [])];
|
|
693
|
-
return {
|
|
694
|
-
id,
|
|
695
|
-
recorded: r !== undefined,
|
|
696
|
-
state: r?.state ?? null,
|
|
697
|
-
harness: r?.harness.name ?? null,
|
|
698
|
-
model: r?.model ?? null,
|
|
699
|
-
provider: r?.provider ?? null,
|
|
700
|
-
by: r?.by ?? null,
|
|
701
|
-
agent: r?.agent ?? null,
|
|
702
|
-
unit: r?.unit?.id ?? null,
|
|
703
|
-
joinedBy,
|
|
704
|
-
};
|
|
705
|
-
}),
|
|
899
|
+
[...byRun].map(([id, recordedAs]) => refOf(id, ["patch-id"], recordedAs)),
|
|
706
900
|
);
|
|
707
901
|
}
|
|
708
|
-
return { refs, runs };
|
|
902
|
+
return { refs, runs, conflicts };
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
/**
|
|
906
|
+
* Give each followed squash commit the runs its original commits join
|
|
907
|
+
* (#3035): `refs` must hold the originals' runs. A run the squash already
|
|
908
|
+
* joins gets `squash` added; another is added with `joinedBy: ["squash"]`.
|
|
909
|
+
* `via` lists the originals that join it.
|
|
910
|
+
*/
|
|
911
|
+
export function addSquashRuns(refs: Map<string, RunRef[]>, follows: Map<string, SquashFollow>): void {
|
|
912
|
+
for (const f of follows.values()) {
|
|
913
|
+
if (!f.followed) continue;
|
|
914
|
+
const list = refs.get(f.sha) ?? refs.set(f.sha, []).get(f.sha)!;
|
|
915
|
+
for (const o of f.commits) {
|
|
916
|
+
for (const r of refs.get(o) ?? []) {
|
|
917
|
+
const have = list.find((x) => x.id === r.id);
|
|
918
|
+
if (have) {
|
|
919
|
+
if (!have.joinedBy.includes("squash")) have.joinedBy.push("squash");
|
|
920
|
+
have.via = [...new Set([...(have.via ?? []), o])];
|
|
921
|
+
continue;
|
|
922
|
+
}
|
|
923
|
+
const { recordedAs: _r, via: _v, ...rest } = r;
|
|
924
|
+
list.push({ ...rest, joinedBy: ["squash"], via: [o] });
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
/**
|
|
931
|
+
* Follow the squash merges on `rev`'s history made since the earliest run
|
|
932
|
+
* started (#3035), and add each to the runs its pull request's original
|
|
933
|
+
* commits join: a commit a run's end lists, or one whose `Chant-Run` names
|
|
934
|
+
* the run. Missing pull request refs are fetched from `origin`. Returns what
|
|
935
|
+
* each squash's follow found, for the read's reasons.
|
|
936
|
+
*/
|
|
937
|
+
export function joinSquashCommits(runs: Map<string, RunView>, top: string, rev = "HEAD"): SquashFollow[] {
|
|
938
|
+
const starts = [...runs.values()].map((r) => Date.parse(r.startedAt)).filter((t) => !Number.isNaN(t));
|
|
939
|
+
if (starts.length === 0 || !commitId(top, rev)) return [];
|
|
940
|
+
const since = new Date(Math.min(...starts) - CLOCK_SLACK_MS).toISOString();
|
|
941
|
+
const candidates: { sha: string; subject: string }[] = [];
|
|
942
|
+
for (const line of (git(top, ["log", rev, `--since=${since}`, "--no-merges", "--format=%H%x1f%s"]) ?? "").split("\n")) {
|
|
943
|
+
const [sha, subject] = line.split("\x1f");
|
|
944
|
+
if (sha && subject !== undefined) candidates.push({ sha: sha.trim(), subject });
|
|
945
|
+
}
|
|
946
|
+
const follows = followSquashes(top, candidates, { fetchMissing: true });
|
|
947
|
+
const originals = [...new Set([...follows.values()].flatMap((f) => f.commits))];
|
|
948
|
+
const trailerRun = new Map<string, string[]>();
|
|
949
|
+
if (originals.length > 0) {
|
|
950
|
+
const text = git(top, ["log", "--no-walk=unsorted", "--stdin", `--format=%x00%H%x1f%(trailers:key=${RUN_TRAILER},valueonly,separator=%x1e)`], `${originals.join("\n")}\n`) ?? "";
|
|
951
|
+
for (const record of text.split("\0")) {
|
|
952
|
+
if (!record.trim()) continue;
|
|
953
|
+
const [sha, values] = record.split("\x1f");
|
|
954
|
+
trailerRun.set(sha.trim(), (values ?? "").split("\x1e").map((x) => x.trim()).filter(Boolean));
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
for (const f of follows.values()) {
|
|
958
|
+
if (!f.followed) continue;
|
|
959
|
+
for (const r of runs.values()) {
|
|
960
|
+
const via = f.commits.filter((o) => r.commits.some((c) => c.sha === o && c.joinedBy.some((j) => j !== "squash")) || (trailerRun.get(o) ?? []).includes(r.id));
|
|
961
|
+
if (via.length === 0) continue;
|
|
962
|
+
const listed = r.commits.find((c) => c.sha === f.sha);
|
|
963
|
+
if (listed) {
|
|
964
|
+
if (!listed.joinedBy.includes("squash")) listed.joinedBy.push("squash");
|
|
965
|
+
listed.via = [...new Set([...(listed.via ?? []), ...via])];
|
|
966
|
+
} else r.commits.push({ sha: f.sha, patchId: patchIdOf(top, f.sha), joinedBy: ["squash"], hunks: null, via });
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
return [...follows.values()];
|
|
709
970
|
}
|
|
@@ -11,7 +11,7 @@ import { execFileSync } from "node:child_process";
|
|
|
11
11
|
import { dirname, resolve } from "node:path";
|
|
12
12
|
import { WorkspaceReadError } from "./declaration";
|
|
13
13
|
import { gitRoot, resolveRevision } from "./record-source";
|
|
14
|
-
import { loadRecordKind, RecordReadError, type LoadedRecordKind } from "./records";
|
|
14
|
+
import { loadRecordKind, RecordReadError, sessionSubjectKinds, type LoadedRecordKind } from "./records";
|
|
15
15
|
import { declaredKindFiles, realpathOr } from "./records-cli";
|
|
16
16
|
|
|
17
17
|
/** The shape of an id `records --since` looks up as a session before reading it as a revision: `S-0002`, `ws-052`. */
|
|
@@ -46,10 +46,10 @@ export async function findSessionKinds(cwd: string, extra: string[] = []): Promi
|
|
|
46
46
|
return out;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/** The session kinds whose `session.subjects.kind` is the kind file `subjectFile`. */
|
|
49
|
+
/** The session kinds one of whose subject kinds (`session.subjects.kind` or `.kinds`) is the kind file `subjectFile`. */
|
|
50
50
|
export async function sessionKindsFor(subjectFile: string, cwd: string): Promise<LoadedRecordKind[]> {
|
|
51
51
|
const target = realpathOr(resolve(cwd, subjectFile));
|
|
52
|
-
return (await findSessionKinds(cwd)).filter((k) => realpathOr(resolve(dirname(k.file),
|
|
52
|
+
return (await findSessionKinds(cwd)).filter((k) => sessionSubjectKinds(k.kind.session!).some((f) => realpathOr(resolve(dirname(k.file), f)) === target));
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/** The full commit id HEAD names in the repository holding `dir`, or null outside git or before the first commit. */
|