@deksden-com/dd-flow-cli 0.9.0-beta.16 → 0.9.0-beta.161
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/CHANGELOG.md +965 -0
- package/README.md +139 -10
- package/dist/build-info.json +8 -8
- package/dist/cli/argument-values.js +38 -0
- package/dist/cli/command-inputs.js +417 -0
- package/dist/cli/command-metadata.js +303 -0
- package/dist/cli/command-option-descriptions.js +192 -0
- package/dist/cli/completion-cli.js +70 -0
- package/dist/cli/completion.js +57 -0
- package/dist/cli/delivery.js +108 -0
- package/dist/cli/diagnostic-invocation.js +62 -0
- package/dist/cli/diagnostic.js +131 -0
- package/dist/cli/error-output.js +62 -0
- package/dist/cli/executor-onboarding.js +76 -0
- package/dist/cli/flows.js +29 -0
- package/dist/cli/harnesses.js +84 -0
- package/dist/cli/help.js +521 -19
- package/dist/cli/hook-ingress.js +89 -0
- package/dist/cli/input-preparation.js +193 -0
- package/dist/cli/interactive-invocation.js +33 -0
- package/dist/cli/interactive.js +114 -0
- package/dist/cli/memory-fix-invocation.js +52 -0
- package/dist/cli/memory-fix.js +100 -0
- package/dist/cli/memory-flow-admission.js +54 -0
- package/dist/cli/memory-init-invocation.js +85 -0
- package/dist/cli/memory-init.js +250 -0
- package/dist/cli/memory-storage-admission.js +54 -0
- package/dist/cli/memory-storage-qualification.js +105 -0
- package/dist/cli/memory-storage-transition.js +123 -0
- package/dist/cli/memory-upgrade.js +189 -0
- package/dist/cli/models.js +39 -0
- package/dist/cli/native-hook-ingress.js +94 -0
- package/dist/cli/native-hook-preparation.js +82 -0
- package/dist/cli/operator-profiles.js +61 -0
- package/dist/cli/output-options.js +35 -0
- package/dist/cli/response-file.js +72 -0
- package/dist/cli/run-cli.js +2020 -555
- package/dist/cli/runtime-maintenance-diagnostics.js +46 -0
- package/dist/cli/runtime-maintenance-ingress.js +52 -0
- package/dist/cli/runtime-process.js +153 -0
- package/dist/cli/setup.js +150 -0
- package/dist/cli.js +103 -2
- package/dist/domain/delivery-flows.js +8 -0
- package/dist/domain/diagnostic-aspects.js +103 -0
- package/dist/domain/diagnostic-flows.js +8 -0
- package/dist/domain/distill-flow.js +20 -0
- package/dist/domain/interactive-flow.js +1 -0
- package/dist/domain/memory-fix-flow.js +2 -0
- package/dist/domain/review-fix-flow.js +2 -0
- package/dist/domain/source-snapshot-flows.js +4 -0
- package/dist/domain/stage-catalog.js +1 -1
- package/dist/domain/stage-handler-identities.js +28 -0
- package/dist/harness-runtime/DD-ZCODE.md +112 -0
- package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
- package/dist/harness-runtime/bin/dd-agy.mjs +71 -0
- package/dist/harness-runtime/bin/dd-codex.mjs +27 -0
- package/dist/harness-runtime/bin/dd-droid.mjs +34 -0
- package/dist/harness-runtime/bin/dd-grok.mjs +50 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +95 -0
- package/dist/harness-runtime/lib/adapter-timeouts.d.mts +5 -0
- package/dist/harness-runtime/lib/adapter-timeouts.mjs +34 -0
- package/dist/harness-runtime/lib/agy-error-boundary.mjs +87 -0
- package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
- package/dist/harness-runtime/lib/agy-native-inspection.mjs +225 -0
- package/dist/harness-runtime/lib/agy-native-inventory.mjs +19 -0
- package/dist/harness-runtime/lib/agy-native_pb.js +117 -0
- package/dist/harness-runtime/lib/agy-terminal-envelope.mjs +74 -0
- package/dist/harness-runtime/lib/agy-transcript-stream.mjs +54 -0
- package/dist/harness-runtime/lib/daemon-observation.d.mts +3 -0
- package/dist/harness-runtime/lib/daemon-observation.mjs +171 -0
- package/dist/harness-runtime/lib/daemon-operations.d.mts +2 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +512 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +7 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +1362 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +105 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +271 -0
- package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +986 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +155 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +739 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +667 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +182 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +772 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +411 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +845 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +1239 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +16 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +179 -0
- package/dist/harness-runtime/lib/delivery-command.mjs +84 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +121 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +70 -0
- package/dist/harness-runtime/lib/entity-references.d.mts +2 -0
- package/dist/harness-runtime/lib/entity-references.mjs +9 -0
- package/dist/harness-runtime/lib/lease-renewal.d.mts +8 -0
- package/dist/harness-runtime/lib/lease-renewal.mjs +37 -0
- package/dist/harness-runtime/lib/lifecycle-command.d.mts +20 -0
- package/dist/harness-runtime/lib/lifecycle-command.mjs +273 -0
- package/dist/harness-runtime/lib/lifecycle-contract.d.mts +11 -0
- package/dist/harness-runtime/lib/lifecycle-contract.mjs +20 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +698 -0
- package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
- package/dist/harness-runtime/lib/model-observations.mjs +113 -0
- package/dist/harness-runtime/lib/native-children.d.mts +34 -0
- package/dist/harness-runtime/lib/native-children.mjs +265 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +8 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +306 -0
- package/dist/harness-runtime/lib/native-request-proof.d.mts +2 -0
- package/dist/harness-runtime/lib/native-request-proof.mjs +65 -0
- package/dist/harness-runtime/lib/native-streams.mjs +38 -0
- package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +95 -0
- package/dist/harness-runtime/lib/opencode-plugin.mjs +112 -0
- package/dist/harness-runtime/lib/operation-context.mjs +5 -0
- package/dist/harness-runtime/lib/operation-errors.d.mts +16 -0
- package/dist/harness-runtime/lib/operation-errors.mjs +140 -0
- package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
- package/dist/harness-runtime/lib/operation-progress.mjs +118 -0
- package/dist/harness-runtime/lib/process-json.d.mts +5 -0
- package/dist/harness-runtime/lib/process-json.mjs +200 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/provider-overload-policy.d.mts +23 -0
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +242 -0
- package/dist/harness-runtime/lib/runner-events.mjs +202 -0
- package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
- package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
- package/dist/harness-runtime/lib/setup-progress.d.mts +9 -0
- package/dist/harness-runtime/lib/setup-progress.mjs +53 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +238 -0
- package/dist/harness-runtime/lib/zcode-native-hook-ownership.mjs +109 -0
- package/dist/harness-runtime/lib/zcode-usage.mjs +55 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
- package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
- package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
- package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
- package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
- package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
- package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
- package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
- package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
- package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
- package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
- package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
- package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
- package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
- package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
- package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
- package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
- package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
- package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
- package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
- package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
- package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
- package/dist/protocol/local-files.js +18 -9
- package/dist/runtime/context.js +8 -4
- package/dist/schemas/agent-profile.schema.json +1 -1
- package/dist/schemas/code-review-decision.schema.json +9 -0
- package/dist/schemas/code-review-result.schema.json +1 -1
- package/dist/schemas/code-verification.schema.json +7 -5
- package/dist/schemas/code-work-batch.schema.json +2 -2
- package/dist/schemas/code-work-result.schema.json +2 -1
- package/dist/schemas/delivery-stage-result.schema.json +286 -0
- package/dist/schemas/diagnostic-stage-result.schema.json +354 -0
- package/dist/schemas/diagnostic-work-result.schema.json +296 -0
- package/dist/schemas/discovery-result.schema.json +184 -0
- package/dist/schemas/distill-stage-result.schema.json +667 -0
- package/dist/schemas/distill-work-result.schema.json +428 -0
- package/dist/schemas/execution-bundle.schema.json +215 -0
- package/dist/schemas/execution-settings.schema.json +162 -0
- package/dist/schemas/flow-descriptor.schema.json +54 -0
- package/dist/schemas/flow-run.schema.json +29 -0
- package/dist/schemas/harness-catalog.schema.json +80 -0
- package/dist/schemas/interactive-stage-result.schema.json +47 -0
- package/dist/schemas/interactive-work-result.schema.json +63 -0
- package/dist/schemas/mb-fix-stage-result.schema.json +93 -0
- package/dist/schemas/mb-init-compose-result.schema.json +457 -0
- package/dist/schemas/mb-init-discover-result.schema.json +500 -0
- package/dist/schemas/mb-init-finish-result.schema.json +422 -0
- package/dist/schemas/mb-init-preflight-result.schema.json +367 -0
- package/dist/schemas/mb-init-review-result.schema.json +396 -0
- package/dist/schemas/mb-init-verify-result.schema.json +391 -0
- package/dist/schemas/mb-upgrade-stage-result.schema.json +863 -0
- package/dist/schemas/memory-bootstrap-receipt-v2.schema.json +67 -0
- package/dist/schemas/memory-bootstrap-receipt.schema.json +354 -0
- package/dist/schemas/memory-composition-work-result.schema.json +38 -0
- package/dist/schemas/memory-repair-work-result.schema.json +56 -0
- package/dist/schemas/memory-review-correction-plan.schema.json +30 -0
- package/dist/schemas/memory-review-work-result.schema.json +43 -0
- package/dist/schemas/model-catalog.schema.json +153 -0
- package/dist/schemas/plan-review-decision.schema.json +12 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/profile-settings.schema.json +122 -0
- package/dist/schemas/project-flow-pack-manifest.schema.json +2 -2
- package/dist/schemas/release-impact.schema.json +3 -3
- package/dist/schemas/release-manifest.schema.json +291 -0
- package/dist/schemas/review-fix-stage-result.schema.json +210 -0
- package/dist/schemas/run-control-receipt.schema.json +119 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/run-engine-binding.schema.json +1 -1
- package/dist/schemas/stage-start-response.schema.json +4 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +3 -3
- package/dist/services/accepted-intent.js +139 -0
- package/dist/services/assigned-lifecycle.js +382 -0
- package/dist/services/branch-context.js +3 -3
- package/dist/services/canon.js +54 -15
- package/dist/services/check-environment.js +21 -0
- package/dist/services/check-runner-evidence.js +344 -0
- package/dist/services/check-runner-proof.js +373 -0
- package/dist/services/cleanup.js +133 -40
- package/dist/services/cli-operation-classifier.js +32 -64
- package/dist/services/cli-upgrade-allowlist.js +27 -0
- package/dist/services/code-checks.js +1426 -121
- package/dist/services/codex-capacity.js +367 -0
- package/dist/services/codex-hook-delivery.js +41 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/compatibility-preflight.js +16 -3
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +25 -0
- package/dist/services/controller-child-capacity.js +71 -0
- package/dist/services/controller-child-observer.js +121 -0
- package/dist/services/controller-child-repair.js +117 -0
- package/dist/services/controller-execution.js +97 -0
- package/dist/services/controller-fanout.js +277 -0
- package/dist/services/controller-memory-task.js +45 -0
- package/dist/services/controller-memory-worker.js +51 -0
- package/dist/services/controller-result-authority.js +127 -0
- package/dist/services/controller-work-failure.js +198 -0
- package/dist/services/dashboard.js +145 -58
- package/dist/services/delivery-access.js +123 -0
- package/dist/services/delivery-approval.js +68 -0
- package/dist/services/delivery-artifact.js +86 -0
- package/dist/services/delivery-checks.js +178 -0
- package/dist/services/delivery-execution.js +181 -0
- package/dist/services/delivery-intents.js +212 -0
- package/dist/services/delivery-operation.js +81 -0
- package/dist/services/delivery-policy.js +91 -0
- package/dist/services/delivery-procedures.js +43 -0
- package/dist/services/delivery-request.js +99 -0
- package/dist/services/delivery-result.js +144 -0
- package/dist/services/delivery-stage-commands.js +26 -0
- package/dist/services/delivery-stage-entry.js +56 -0
- package/dist/services/delivery-stage-handlers.js +135 -0
- package/dist/services/delivery-stage-results.js +94 -0
- package/dist/services/descriptor-coordinator-session.js +37 -0
- package/dist/services/descriptor-root-work.js +53 -0
- package/dist/services/descriptor-run-settlement.js +107 -0
- package/dist/services/descriptor-run-start.js +495 -0
- package/dist/services/descriptor-stage-coordinator.js +318 -0
- package/dist/services/descriptor-stage-settlement.js +268 -0
- package/dist/services/descriptor-stage-start.js +175 -0
- package/dist/services/diagnostic-evidence.js +73 -0
- package/dist/services/diagnostic-repair-intake.js +123 -0
- package/dist/services/diagnostic-repair-source-intake.js +102 -0
- package/dist/services/diagnostic-report-publication.js +72 -0
- package/dist/services/diagnostic-report.js +97 -0
- package/dist/services/diagnostic-run-bundle.js +113 -0
- package/dist/services/diagnostic-snapshot.js +159 -0
- package/dist/services/diagnostic-stage-handlers.js +109 -0
- package/dist/services/diagnostic-stage-results.js +158 -0
- package/dist/services/diagnostic-start.js +134 -0
- package/dist/services/diagnostic-work-batch.js +34 -0
- package/dist/services/diagnostic-work-collection.js +97 -0
- package/dist/services/diagnostic-work-registration.js +101 -0
- package/dist/services/diagnostic-work-results.js +93 -0
- package/dist/services/discovery/agy-discovery.js +2 -0
- package/dist/services/discovery/codex-discovery.js +2 -0
- package/dist/services/discovery/droid-discovery.js +2 -0
- package/dist/services/discovery/grok-discovery.js +2 -0
- package/dist/services/discovery/opencode-discovery.js +2 -0
- package/dist/services/discovery/static.js +31 -0
- package/dist/services/discovery/zcode-discovery.js +2 -0
- package/dist/services/distill-document-publication.js +280 -0
- package/dist/services/distill-promotion.js +197 -0
- package/dist/services/distill-publication-custody.js +162 -0
- package/dist/services/distill-stage-handlers.js +249 -0
- package/dist/services/distill-stage-results.js +105 -0
- package/dist/services/distill-user-inputs.js +4 -0
- package/dist/services/distill-work-batch.js +42 -0
- package/dist/services/distill-work-collection.js +74 -0
- package/dist/services/distill-work-registration.js +93 -0
- package/dist/services/distill-work-results.js +98 -0
- package/dist/services/engines.js +354 -163
- package/dist/services/eval-snapshots.js +1326 -150
- package/dist/services/execution-bundles.js +275 -0
- package/dist/services/execution-policy.js +185 -0
- package/dist/services/executor-onboarding.js +56 -0
- package/dist/services/external-work-launch.js +316 -0
- package/dist/services/flow-catalog.js +54 -0
- package/dist/services/flow-descriptors.js +82 -0
- package/dist/services/frozen-engine.js +404 -0
- package/dist/services/generic-execution.js +165 -0
- package/dist/services/harness-adapter.js +342 -35
- package/dist/services/harness-config.js +2 -0
- package/dist/services/harness-discovery.js +29 -0
- package/dist/services/harness-doctor.js +75 -0
- package/dist/services/harness-probe-effects.js +51 -0
- package/dist/services/harness-version-probe.js +100 -0
- package/dist/services/hook-memory-routing.js +188 -0
- package/dist/services/hook-recovery-guard.js +14 -0
- package/dist/services/hook-session-observation.js +24 -0
- package/dist/services/hooks.js +813 -327
- package/dist/services/hybrid-contracts.js +479 -0
- package/dist/services/hybrid-digest.js +14 -0
- package/dist/services/ids.js +29 -1
- package/dist/services/installation-lock.js +95 -0
- package/dist/services/installed-flow-source.js +261 -0
- package/dist/services/interactive-attached-session.js +215 -0
- package/dist/services/interactive-baseline-custody.js +54 -0
- package/dist/services/interactive-before-versions.js +148 -0
- package/dist/services/interactive-bundle-data.js +85 -0
- package/dist/services/interactive-checks.js +179 -0
- package/dist/services/interactive-execution.js +33 -0
- package/dist/services/interactive-finish-integration.js +236 -0
- package/dist/services/interactive-git-baseline.js +230 -0
- package/dist/services/interactive-git-dispatch.js +278 -0
- package/dist/services/interactive-input-delivery.js +82 -0
- package/dist/services/interactive-mutation-scope.js +231 -0
- package/dist/services/interactive-request.js +287 -0
- package/dist/services/interactive-run-bundle.js +109 -0
- package/dist/services/interactive-stage-entry.js +41 -0
- package/dist/services/interactive-stage-handlers.js +289 -0
- package/dist/services/interactive-stage-observation.js +136 -0
- package/dist/services/interactive-stage-results.js +111 -0
- package/dist/services/interactive-user-inputs.js +142 -0
- package/dist/services/interactive-work-batch.js +43 -0
- package/dist/services/interactive-work-collection.js +119 -0
- package/dist/services/interactive-work-completion.js +180 -0
- package/dist/services/interactive-work-context.js +249 -0
- package/dist/services/interactive-work-history.js +112 -0
- package/dist/services/interactive-work-registration.js +124 -0
- package/dist/services/interactive-work-results.js +115 -0
- package/dist/services/interactive-work-start.js +155 -0
- package/dist/services/lanes.js +78 -65
- package/dist/services/lifecycle-command.js +1 -288
- package/dist/services/lifecycle-contract.js +1 -0
- package/dist/services/lifecycle-invocations.js +2549 -0
- package/dist/services/managed-daemon-binding.js +129 -0
- package/dist/services/managed-lease-monitor.js +133 -0
- package/dist/services/managed-processes.js +449 -69
- package/dist/services/memory-accepted-composition.js +78 -0
- package/dist/services/memory-baseline-preservation.js +65 -0
- package/dist/services/memory-completed-correction-wave.js +328 -0
- package/dist/services/memory-compose-handler.js +380 -0
- package/dist/services/memory-composition-acceptance.js +375 -0
- package/dist/services/memory-composition-graph.js +165 -0
- package/dist/services/memory-composition-registration.js +161 -0
- package/dist/services/memory-composition-work-custody.js +156 -0
- package/dist/services/memory-composition-work-results.js +108 -0
- package/dist/services/memory-corrected-review-acceptance.js +129 -0
- package/dist/services/memory-corrected-review-batch.js +37 -0
- package/dist/services/memory-corrected-review-findings.js +108 -0
- package/dist/services/memory-corrected-review-inputs.js +215 -0
- package/dist/services/memory-corrected-review-projection.js +78 -0
- package/dist/services/memory-corrected-review-receipt.js +178 -0
- package/dist/services/memory-corrected-review-registration.js +192 -0
- package/dist/services/memory-correction-check-receipt.js +235 -0
- package/dist/services/memory-correction-input-owner.js +6 -0
- package/dist/services/memory-custody-snapshot.js +36 -0
- package/dist/services/memory-discover-handler.js +104 -0
- package/dist/services/memory-finish-evidence.js +457 -0
- package/dist/services/memory-finish-handler.js +229 -0
- package/dist/services/memory-finish-integration.js +491 -0
- package/dist/services/memory-finish-readiness.js +169 -0
- package/dist/services/memory-fix-finish-integration.js +129 -0
- package/dist/services/memory-fix-git-dispatch.js +139 -0
- package/dist/services/memory-fix-intake-custody.js +11 -0
- package/dist/services/memory-fix-intake-settlement.js +127 -0
- package/dist/services/memory-fix-publication.js +196 -0
- package/dist/services/memory-fix-repair-admission.js +116 -0
- package/dist/services/memory-fix-request.js +141 -0
- package/dist/services/memory-fix-run-bundle.js +83 -0
- package/dist/services/memory-fix-scope.js +78 -0
- package/dist/services/memory-fix-sources.js +85 -0
- package/dist/services/memory-fix-stage-entry.js +24 -0
- package/dist/services/memory-fix-stage-handlers.js +282 -0
- package/dist/services/memory-fix-stage-results.js +106 -0
- package/dist/services/memory-fix-workspace.js +127 -0
- package/dist/services/memory-flow-user-inputs.js +88 -0
- package/dist/services/memory-git-integration.js +220 -0
- package/dist/services/memory-historical-corrected-review.js +212 -0
- package/dist/services/memory-historical-original-review.js +143 -0
- package/dist/services/memory-historical-repair-registration.js +105 -0
- package/dist/services/memory-historical-second-review.js +147 -0
- package/dist/services/memory-init-bootstrap-readiness.js +210 -0
- package/dist/services/memory-init-contexts.js +181 -0
- package/dist/services/memory-init-controller-start.js +119 -0
- package/dist/services/memory-init-engine-release.js +223 -0
- package/dist/services/memory-init-git-policy.js +165 -0
- package/dist/services/memory-init-lint-capability.js +203 -0
- package/dist/services/memory-init-native-capacity.js +309 -0
- package/dist/services/memory-init-preflight.js +334 -0
- package/dist/services/memory-init-project-bootstrap.js +599 -0
- package/dist/services/memory-init-request-candidate.js +213 -0
- package/dist/services/memory-init-request-input.js +82 -0
- package/dist/services/memory-init-resource-storage.js +125 -0
- package/dist/services/memory-init-run-allocation.js +81 -0
- package/dist/services/memory-init-run-bundle.js +135 -0
- package/dist/services/memory-init-start.js +181 -0
- package/dist/services/memory-init-startup-custody.js +80 -0
- package/dist/services/memory-init-startup-input.js +240 -0
- package/dist/services/memory-init-storage.js +91 -0
- package/dist/services/memory-init-stores.js +359 -0
- package/dist/services/memory-init-worktrunk-capability.js +174 -0
- package/dist/services/memory-layer-publication.js +611 -0
- package/dist/services/memory-layer.js +225 -0
- package/dist/services/memory-lint-config.js +194 -0
- package/dist/services/memory-native-review-copy.js +127 -0
- package/dist/services/memory-normal-flow-entry.js +87 -0
- package/dist/services/memory-ordinary-defaults.js +129 -0
- package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
- package/dist/services/memory-preflight-handler.js +274 -0
- package/dist/services/memory-repair-current-view.js +299 -0
- package/dist/services/memory-repair-document-delta.js +489 -0
- package/dist/services/memory-repair-history.js +496 -0
- package/dist/services/memory-repair-physical-binding.js +194 -0
- package/dist/services/memory-repair-publication-files.js +152 -0
- package/dist/services/memory-repair-publication-intent.js +27 -0
- package/dist/services/memory-repair-publication-plan.js +162 -0
- package/dist/services/memory-repair-publication-source.js +225 -0
- package/dist/services/memory-repair-publication.js +795 -0
- package/dist/services/memory-repair-registration.js +240 -0
- package/dist/services/memory-repair-work-baseline.js +415 -0
- package/dist/services/memory-repair-work-completion.js +117 -0
- package/dist/services/memory-repair-work-custody.js +73 -0
- package/dist/services/memory-repair-work-results.js +108 -0
- package/dist/services/memory-repair-workspace.js +261 -0
- package/dist/services/memory-repair-writer-copy.js +736 -0
- package/dist/services/memory-result-binding.js +239 -0
- package/dist/services/memory-retained-review-authority.js +138 -0
- package/dist/services/memory-retained-review-results.js +70 -0
- package/dist/services/memory-retained-second-baseline.js +102 -0
- package/dist/services/memory-retained-second-repairs.js +162 -0
- package/dist/services/memory-review-acceptance.js +214 -0
- package/dist/services/memory-review-correction-plan.js +206 -0
- package/dist/services/memory-review-handler.js +585 -0
- package/dist/services/memory-review-inputs.js +246 -0
- package/dist/services/memory-review-limits.js +10 -0
- package/dist/services/memory-review-receipt.js +180 -0
- package/dist/services/memory-review-registration.js +117 -0
- package/dist/services/memory-review-work-custody.js +126 -0
- package/dist/services/memory-review-work-input.js +91 -0
- package/dist/services/memory-review-work-results.js +95 -0
- package/dist/services/memory-second-corrected-review-inputs.js +167 -0
- package/dist/services/memory-second-correction-plan.js +77 -0
- package/dist/services/memory-second-repair-baseline.js +91 -0
- package/dist/services/memory-second-repair-launch.js +614 -0
- package/dist/services/memory-second-repair-registration.js +88 -0
- package/dist/services/memory-second-repair-source.js +187 -0
- package/dist/services/memory-second-review-acceptance.js +115 -0
- package/dist/services/memory-source-observations.js +117 -0
- package/dist/services/memory-stage-dispatch.js +65 -0
- package/dist/services/memory-stage-results.js +290 -0
- package/dist/services/memory-tool-probe.js +25 -0
- package/dist/services/memory-upgrade-analysis-handler.js +243 -0
- package/dist/services/memory-upgrade-bootstrap-readiness.js +251 -0
- package/dist/services/memory-upgrade-evidence.js +100 -0
- package/dist/services/memory-upgrade-inventory.js +442 -0
- package/dist/services/memory-upgrade-publication-custody.js +73 -0
- package/dist/services/memory-upgrade-publication.js +413 -0
- package/dist/services/memory-upgrade-selection.js +430 -0
- package/dist/services/memory-upgrade-start.js +60 -0
- package/dist/services/memory-upgrade-storage-readiness.js +340 -0
- package/dist/services/memory-verification-acceptance.js +156 -0
- package/dist/services/memory-verification-checks.js +317 -0
- package/dist/services/memory-verification-receipt.js +160 -0
- package/dist/services/memory-verify-handler.js +137 -0
- package/dist/services/memory-work-result-json.js +12 -0
- package/dist/services/memory-work-result-preparation.js +64 -0
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +163 -35
- package/dist/services/migrations.js +164 -114
- package/dist/services/model-catalog.js +109 -0
- package/dist/services/model-discovery.js +46 -0
- package/dist/services/native-daemon-history.js +50 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/operator-profiles.js +236 -0
- package/dist/services/physical-startup.js +45 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/project-flow-source.js +195 -0
- package/dist/services/project-git-integration.js +92 -0
- package/dist/services/project-registry.js +97 -0
- package/dist/services/project-summary.js +1 -1
- package/dist/services/projects.js +17 -87
- package/dist/services/prompt-delivery.js +71 -0
- package/dist/services/prompts.js +28 -17
- package/dist/services/protocols.js +163 -87
- package/dist/services/provider-capacity.js +463 -0
- package/dist/services/recovery-observation-budget.js +121 -0
- package/dist/services/recovery-snapshot-database.js +588 -0
- package/dist/services/release-archive-producer.js +52 -0
- package/dist/services/release-archive.js +143 -0
- package/dist/services/release-cache.js +150 -0
- package/dist/services/release-compatibility.js +18 -0
- package/dist/services/release-download.js +67 -0
- package/dist/services/release-envelope.js +104 -0
- package/dist/services/release-manifest.js +45 -0
- package/dist/services/release-payload.js +114 -0
- package/dist/services/release-producer.js +63 -0
- package/dist/services/release-provenance.js +160 -0
- package/dist/services/release-registry.js +66 -0
- package/dist/services/release-source.js +194 -0
- package/dist/services/repair-intents.js +29 -0
- package/dist/services/repair-receipt.js +13 -0
- package/dist/services/retained-native-hook.js +274 -0
- package/dist/services/review-copy.js +165 -0
- package/dist/services/review-deferral.js +23 -0
- package/dist/services/review-fix-handoff.js +82 -0
- package/dist/services/review-fix-intake-custody.js +17 -0
- package/dist/services/review-fix-stage-entry.js +43 -0
- package/dist/services/review-fix-stage-handlers.js +176 -0
- package/dist/services/review-fix-stage-results.js +86 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +469 -0
- package/dist/services/run-control.js +1109 -0
- package/dist/services/run-controller-adapter.js +434 -0
- package/dist/services/run-controller-capture.js +186 -0
- package/dist/services/run-controller-process.js +226 -0
- package/dist/services/run-controller-recovery.js +335 -0
- package/dist/services/run-controller-state.js +106 -0
- package/dist/services/run-controller.js +1717 -0
- package/dist/services/run-engine-bindings.js +1 -1
- package/dist/services/run-fork.js +147 -0
- package/dist/services/run-health.js +149 -0
- package/dist/services/run-observations.js +152 -0
- package/dist/services/run-projection.js +22 -64
- package/dist/services/run-recovery-guard.js +107 -0
- package/dist/services/run-recovery-runtime.js +112 -0
- package/dist/services/run-recovery.js +485 -0
- package/dist/services/run-start-custody.js +189 -0
- package/dist/services/run-timeline.js +59 -0
- package/dist/services/runs.js +996 -271
- package/dist/services/runtime-budget.js +446 -0
- package/dist/services/runtime-command.js +43 -0
- package/dist/services/runtime-scope-capture.js +52 -0
- package/dist/services/runtime-scope-control.js +468 -0
- package/dist/services/runtime-scope-resume.js +605 -0
- package/dist/services/runtime-scope-stop.js +211 -0
- package/dist/services/runtime-scope-worker.js +314 -0
- package/dist/services/runtime-service.js +19 -14
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +27 -0
- package/dist/services/sessions.js +37 -91
- package/dist/services/setup.js +427 -0
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +240 -18
- package/dist/services/stage-handlers.js +141 -0
- package/dist/services/stage-lifecycle.js +156 -119
- package/dist/services/stage-pause.js +222 -94
- package/dist/services/stage-report-renderer.js +230 -6
- package/dist/services/stage-work-graph.js +52 -0
- package/dist/services/technical-notes.js +31 -0
- package/dist/services/tooling.js +111 -44
- package/dist/services/usage.js +49 -101
- package/dist/services/verification-matrix.js +393 -0
- package/dist/services/version-status.js +1 -1
- package/dist/services/vnext-code-review.js +302 -91
- package/dist/services/vnext-code.js +325 -251
- package/dist/services/vnext-contracts.js +10 -1
- package/dist/services/vnext-execution-profile.js +80 -5
- package/dist/services/vnext-fanout.js +399 -20
- package/dist/services/vnext-merge.js +336 -114
- package/dist/services/vnext-plan-review.js +288 -133
- package/dist/services/vnext-plan.js +257 -110
- package/dist/services/vnext-protocolize.js +534 -96
- package/dist/services/vnext-specify.js +131 -84
- package/dist/services/vnext-workspace-policy.js +7 -2
- package/dist/services/work-registry.js +1950 -215
- package/dist/services/work-retry-context.js +55 -0
- package/dist/services/workspace-bootstrap.js +53 -15
- package/dist/services/workspace-files.js +85 -0
- package/dist/services/worktrees.js +108 -48
- package/dist/shared/entity-references.js +1 -0
- package/dist/shared/errors.js +27 -0
- package/dist/storage/agent-output.js +26 -0
- package/dist/storage/data-preservation.js +65 -0
- package/dist/storage/database.js +931 -40
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +159 -0
- package/dist/storage/memory-upgrade-schema-bootstrap.js +38 -0
- package/dist/storage/native-cleanup.js +52 -0
- package/dist/storage/paired-writer-migration.js +424 -0
- package/dist/storage/paths.js +17 -4
- package/dist/storage/projection-lock.js +73 -0
- package/dist/storage/work-references.js +23 -0
- package/dist/storage/writer-contract.js +96 -0
- package/dist/storage/writer-migration.js +346 -0
- package/dist/storage/writer-restore.js +217 -0
- package/dist/verification-components.json +384 -0
- package/package.json +52 -13
- package/tools/create-canon-release.mjs +33 -0
- package/tools/probe-codex-history.mjs +37 -0
- package/tools/produce-hybrid-release.mjs +41 -0
- package/tools/repair-paused-run-status.mjs +84 -0
- package/tools/verification-jobs.mjs +342 -0
|
@@ -86,7 +86,7 @@ function isRunEngineBinding(value) {
|
|
|
86
86
|
&& typeof record.run_id === "string"
|
|
87
87
|
&& typeof record.project_root === "string"
|
|
88
88
|
&& typeof record.bound_at === "string"
|
|
89
|
-
&& ["run_creation", "legacy_recovery"].includes(String(record.source))
|
|
89
|
+
&& ["run_creation", "legacy_recovery", "fork_upgrade"].includes(String(record.source))
|
|
90
90
|
&& typeof record.reason === "string"
|
|
91
91
|
&& Boolean(engine && typeof engine === "object" && !Array.isArray(engine)
|
|
92
92
|
&& typeof engine.package_name === "string"
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { createContext } from "../runtime/context.js";
|
|
5
|
+
import { AppError } from "../shared/errors.js";
|
|
6
|
+
import { canonicalPath } from "../storage/paths.js";
|
|
7
|
+
import { importGuardPath, rearmCompletedSnapshotImport } from "../storage/import-guard.js";
|
|
8
|
+
import { installCurrentEngine, upgradeForkedRunEngine, prepareForkEngine } from "./engines.js";
|
|
9
|
+
import { restoreEvalRunSnapshot, prepareEvalRunSnapshot, prepareEvalRunRestore, prepareSnapshotOperationalDecision, restoredWorkspaceRoot } from "./eval-snapshots.js";
|
|
10
|
+
export function prepareRunFork(input) {
|
|
11
|
+
const requestId = requireId(input.requestId, "request-id");
|
|
12
|
+
const snapshot = canonicalPath(input.snapshot, false);
|
|
13
|
+
const output = canonicalPath(input.output, false);
|
|
14
|
+
if (snapshot === output || snapshot.startsWith(`${output}${path.sep}`) || output.startsWith(`${snapshot}${path.sep}`)) {
|
|
15
|
+
throw new AppError("fork_path_conflict", "Fork output must not contain or be contained by its source snapshot", 2, { snapshot, output });
|
|
16
|
+
}
|
|
17
|
+
const manifestFile = path.join(snapshot, "snapshot.json");
|
|
18
|
+
const intentFile = path.join(output, ".fork-intent.json");
|
|
19
|
+
const receiptFile = path.join(output, "fork.json");
|
|
20
|
+
const engineVersion = requireText(input.engineVersion, "engine-version");
|
|
21
|
+
if (fs.existsSync(receiptFile)) {
|
|
22
|
+
const receipt = readJson(receiptFile);
|
|
23
|
+
const prior = receipt?.intent;
|
|
24
|
+
if (!prior || prior.request_id !== requestId || prior.snapshot !== snapshot || prior.engine_version !== engineVersion || prior.integrity_checksum !== (input.integrityChecksum ?? null)
|
|
25
|
+
|| (prior.operational_decision_sha256 ?? null) !== (input.operationalDecisionFile ? fileHash(input.operationalDecisionFile) : null))
|
|
26
|
+
throw new AppError("fork_request_conflict", "Fork output already belongs to another request", 1, { output });
|
|
27
|
+
return { receipt, output };
|
|
28
|
+
}
|
|
29
|
+
prepareForkEngine(engineVersion, input.integrityChecksum);
|
|
30
|
+
const manifest = prepareEvalRunSnapshot(snapshot);
|
|
31
|
+
if (!["dd-flow/eval-run-snapshot@5", "dd-flow/eval-run-snapshot@7"].includes(manifest.schema_id) || manifest.purpose !== "stage_entry" || typeof manifest.stage_entry !== "string" || typeof manifest.run_id !== "string") {
|
|
32
|
+
throw new AppError("fork_checkpoint_invalid", "Fork requires a sealed stage-entry snapshot", 2, { snapshot });
|
|
33
|
+
}
|
|
34
|
+
const operational = prepareSnapshotOperationalDecision({ snapshot, runId: manifest.run_id, projectRoot: path.join(output, "project"), now: new Date().toISOString(), ...(input.operationalDecisionFile ? { file: input.operationalDecisionFile } : {}) });
|
|
35
|
+
const intent = {
|
|
36
|
+
schema_id: "dd-flow/run-fork-intent@1",
|
|
37
|
+
request_id: requestId,
|
|
38
|
+
snapshot,
|
|
39
|
+
snapshot_sha256: fileHash(manifestFile),
|
|
40
|
+
engine_version: engineVersion,
|
|
41
|
+
integrity_checksum: input.integrityChecksum ?? null,
|
|
42
|
+
...(operational ? { operational_decision_sha256: crypto.createHash("sha256").update(operational.bytes).digest("hex") } : {}),
|
|
43
|
+
target_stage: manifest.stage_entry
|
|
44
|
+
};
|
|
45
|
+
assertForkOutput(output, intentFile, intent);
|
|
46
|
+
return { manifest, snapshot, output, intent, intentFile, receiptFile, requestId };
|
|
47
|
+
}
|
|
48
|
+
function assertForkOutput(output, intentFile, intent) {
|
|
49
|
+
if (fs.existsSync(output) && !fs.statSync(output).isDirectory())
|
|
50
|
+
throw new AppError("fork_output_not_empty", "Fork output must be a directory", 2, { output });
|
|
51
|
+
if (fs.existsSync(output) && fs.readdirSync(output).length > 0) {
|
|
52
|
+
if (!fs.existsSync(intentFile) || hash(readJson(intentFile).intent) !== hash(intent))
|
|
53
|
+
throw new AppError("fork_output_not_empty", "Fork output must be empty", 2, { output });
|
|
54
|
+
const guardName = path.basename(importGuardPath(path.join(output, "dd-flow-home")));
|
|
55
|
+
const unknown = fs.readdirSync(output).filter(name => ![".fork-intent.json", "project", "dd-flow-home", guardName].includes(name));
|
|
56
|
+
if (unknown.length)
|
|
57
|
+
throw new AppError("fork_retry_inspect_required", "Fork output contains data not owned by the interrupted fork", 1, { output, unknown });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export async function forkRunFromSnapshot(context, input, prepared = prepareRunFork(input)) {
|
|
61
|
+
if ("receipt" in prepared)
|
|
62
|
+
return prepared.receipt;
|
|
63
|
+
const { manifest, snapshot, output, intent, intentFile, receiptFile, requestId } = prepared;
|
|
64
|
+
if (input.operationalDecisionFile && fileHash(input.operationalDecisionFile) !== intent.operational_decision_sha256)
|
|
65
|
+
throw new AppError("operational_decision_changed", "Accepted fork decision changed after preparation", 2);
|
|
66
|
+
assertForkOutput(output, intentFile, intent);
|
|
67
|
+
const projectRoot = path.join(output, "project");
|
|
68
|
+
const home = path.join(output, "dd-flow-home");
|
|
69
|
+
const prearmedImportId = rearmCompletedSnapshotImport({ home, projectRoot,
|
|
70
|
+
workspaceRoot: restoredWorkspaceRoot(manifest, projectRoot, home), sourceManifestSha256: intent.snapshot_sha256 });
|
|
71
|
+
for (const name of ["project", "dd-flow-home"])
|
|
72
|
+
fs.rmSync(path.join(output, name), { recursive: true, force: true });
|
|
73
|
+
fs.mkdirSync(output, { recursive: true, mode: 0o700 });
|
|
74
|
+
writeJsonAtomic(intentFile, { schema_id: "dd-flow/run-fork-intent@1", intent });
|
|
75
|
+
fs.mkdirSync(projectRoot, { recursive: true, mode: 0o700 });
|
|
76
|
+
const targetContext = createContext({ ...context.env, DD_FLOW_HOME: home, DD_FLOW_ENGINE_MODE: "1" }, "initialize", prearmedImportId ?? undefined);
|
|
77
|
+
const restoreInput = { snapshot, projectRoot, ...(input.operationalDecisionFile ? { operationalDecisionFile: input.operationalDecisionFile } : {}) };
|
|
78
|
+
const restored = restoreEvalRunSnapshot(targetContext, restoreInput, prepareEvalRunRestore(targetContext, restoreInput, manifest), prearmedImportId ?? undefined);
|
|
79
|
+
const restoredContext = createContext({ ...context.env, DD_FLOW_HOME: home, DD_FLOW_ENGINE_MODE: "1" });
|
|
80
|
+
try {
|
|
81
|
+
const runHome = String(restored.run_home);
|
|
82
|
+
const previousBinding = readJson(path.join(runHome, "engine-binding.json"));
|
|
83
|
+
const lineage = {
|
|
84
|
+
schema_id: "dd-flow/run-fork-lineage@1",
|
|
85
|
+
request_id: requestId,
|
|
86
|
+
source_snapshot: snapshot,
|
|
87
|
+
source_snapshot_sha256: intent.snapshot_sha256,
|
|
88
|
+
source_run_id: manifest.run_id,
|
|
89
|
+
target_stage: manifest.stage_entry,
|
|
90
|
+
inherited_engine: previousBinding,
|
|
91
|
+
created_at: restoredContext.now()
|
|
92
|
+
};
|
|
93
|
+
writeJsonAtomic(path.join(runHome, "fork-lineage.json"), lineage);
|
|
94
|
+
// Install the immutable artifact belonging to the currently executing
|
|
95
|
+
// CLI into the new home. Its exact version/checksum were checked before
|
|
96
|
+
// any interrupted-copy cleanup; snapshots exclude installed engines.
|
|
97
|
+
installCurrentEngine(restoredContext, { forRouting: true });
|
|
98
|
+
const binding = await upgradeForkedRunEngine(restoredContext, {
|
|
99
|
+
projectRoot,
|
|
100
|
+
runId: String(restored.run_id),
|
|
101
|
+
engineVersion: intent.engine_version,
|
|
102
|
+
...(intent.integrity_checksum ? { integrityChecksum: intent.integrity_checksum } : {}),
|
|
103
|
+
reason: `Fork ${requestId} from sealed checkpoint ${intent.snapshot_sha256}.`
|
|
104
|
+
});
|
|
105
|
+
const receipt = {
|
|
106
|
+
ok: true,
|
|
107
|
+
schema_id: "dd-flow/run-fork@1",
|
|
108
|
+
status: "ready",
|
|
109
|
+
intent,
|
|
110
|
+
fork: {
|
|
111
|
+
project_root: projectRoot,
|
|
112
|
+
dd_flow_home: home,
|
|
113
|
+
run_id: restored.run_id,
|
|
114
|
+
run_home: runHome,
|
|
115
|
+
workspace_root: restored.workspace_root,
|
|
116
|
+
target_stage: manifest.stage_entry,
|
|
117
|
+
engine: binding.engine,
|
|
118
|
+
lineage_file: path.join(runHome, "fork-lineage.json")
|
|
119
|
+
},
|
|
120
|
+
next_command: `dd-flow stage start ${restored.run_id} --stage ${manifest.stage_entry} --project-root ${JSON.stringify(projectRoot)} --json`
|
|
121
|
+
};
|
|
122
|
+
writeJsonAtomic(receiptFile, receipt);
|
|
123
|
+
return receipt;
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
restoredContext.db.close?.();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function readJson(file) {
|
|
130
|
+
try {
|
|
131
|
+
return JSON.parse(fs.readFileSync(file, "utf8"));
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
throw new AppError("fork_checkpoint_invalid", "Fork metadata is not valid JSON", 2, { file, cause: String(error) });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function writeJsonAtomic(file, value) {
|
|
138
|
+
const temporary = `${file}.tmp-${process.pid}-${crypto.randomUUID()}`;
|
|
139
|
+
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
|
|
140
|
+
fs.renameSync(temporary, file);
|
|
141
|
+
}
|
|
142
|
+
function hash(value) { return crypto.createHash("sha256").update(JSON.stringify(value)).digest("hex"); }
|
|
143
|
+
function fileHash(file) { return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex"); }
|
|
144
|
+
function requireText(value, name) { const text = value.trim(); if (!text)
|
|
145
|
+
throw new AppError("usage", `Missing required value: ${name}`, 2); return text; }
|
|
146
|
+
function requireId(value, name) { const text = requireText(value, name); if (!/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(text))
|
|
147
|
+
throw new AppError("usage", `Invalid ${name}`, 2); return text; }
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { AppError } from "../shared/errors.js";
|
|
2
|
+
import { managedProcessBinding, managedProcessRuntimeHome, managedProcessStatus, managedProcessObservation, processTreeIsAlive } from "./managed-processes.js";
|
|
3
|
+
import { reconcileStoredFlowRun } from "./runs.js";
|
|
4
|
+
import { recoveryGuard } from "./run-recovery.js";
|
|
5
|
+
import { spawnSync } from "node:child_process";
|
|
6
|
+
function physicalInventory() {
|
|
7
|
+
const reply = spawnSync('ps', ['-axo', 'pid=,pgid=,stat='], { encoding: 'utf8', timeout: 5000 });
|
|
8
|
+
if (reply.status !== 0)
|
|
9
|
+
return null;
|
|
10
|
+
return reply.stdout.trim().split('\n').map(line => line.trim().split(/\s+/)).filter(parts => parts.length === 3).map(parts => ({ pid: Number(parts[0]), group: Number(parts[1]), zombie: parts[2].startsWith('Z') }));
|
|
11
|
+
}
|
|
12
|
+
const terminalRun = (status) => ["done", "failed", "cancelled", "discarded"].includes(status);
|
|
13
|
+
const waiting = new Set(["waiting_for_user", "waiting_for_context", "waiting_for_capacity", "waiting_for_children", "waiting_for_merge", "stop_target_reached", "paused", "control_requested"]);
|
|
14
|
+
const table = (context, name) => Boolean(context.db.get("SELECT 1 FROM sqlite_schema WHERE name = ?", [name]));
|
|
15
|
+
const latest = (values) => values.filter((value) => typeof value === "string" && Number.isFinite(Date.parse(value))).sort((a, b) => Date.parse(b) - Date.parse(a))[0] ?? null;
|
|
16
|
+
/** Evidence only: lease expiry and quiet providers never prove an exit. */
|
|
17
|
+
export function assessRunHealth(input) {
|
|
18
|
+
const phase = input.phase ?? null;
|
|
19
|
+
let state = "unknown", reason = "owner_identity_missing";
|
|
20
|
+
if (terminalRun(input.status)) {
|
|
21
|
+
state = "settled";
|
|
22
|
+
reason = "saved_terminal_result";
|
|
23
|
+
}
|
|
24
|
+
else if (input.childrenAlive && input.owner === "absent") {
|
|
25
|
+
state = "owner_lost";
|
|
26
|
+
reason = "native_children_still_active";
|
|
27
|
+
}
|
|
28
|
+
else if (phase === 'recovery_required' || phase === 'capture_failed') {
|
|
29
|
+
state = input.owner === 'absent' ? 'owner_lost' : 'unknown';
|
|
30
|
+
reason = phase;
|
|
31
|
+
}
|
|
32
|
+
else if (phase && waiting.has(phase) || ["waiting_for_user", "blocked"].includes(input.status)) {
|
|
33
|
+
state = "waiting";
|
|
34
|
+
reason = phase ?? input.status;
|
|
35
|
+
}
|
|
36
|
+
else if (input.owner === "absent") {
|
|
37
|
+
state = "owner_lost";
|
|
38
|
+
reason = "physical_owner_retired";
|
|
39
|
+
}
|
|
40
|
+
else if (input.owner === "alive") {
|
|
41
|
+
const age = input.lastProgress ? Date.parse(input.now) - Date.parse(input.lastProgress) : NaN;
|
|
42
|
+
state = Number.isFinite(age) && age > input.noProgressMs ? "no_progress" : "active";
|
|
43
|
+
reason = state === "no_progress" ? "progress_overdue" : "physical_owner_observed";
|
|
44
|
+
}
|
|
45
|
+
else if (input.status === "paused") {
|
|
46
|
+
state = "waiting";
|
|
47
|
+
reason = "saved_pause";
|
|
48
|
+
}
|
|
49
|
+
return { schema_id: "dd-flow/run-health@1", state, reason, phase, owner_state: input.owner, last_progress_at: input.lastProgress ?? null, last_heartbeat_at: input.heartbeat ?? null, observed_at: input.now, controller_id: input.controllerId ?? null, generation: input.generation ?? null, no_progress_ms: input.noProgressMs };
|
|
50
|
+
}
|
|
51
|
+
/** No dispatch, cancellation, process signals or provider calls. All changes
|
|
52
|
+
* are fenced by the retained RUN revision, controller and process binding. */
|
|
53
|
+
export function reconcileFlowRunHealth(context, input = {}) {
|
|
54
|
+
const noProgressMs = input.noProgressMs ?? 30 * 60_000;
|
|
55
|
+
if (!Number.isSafeInteger(noProgressMs) || noProgressMs < 1_000)
|
|
56
|
+
throw new AppError("usage", "no-progress-ms must be an integer of at least 1000", 2);
|
|
57
|
+
const runs = context.db.all(`SELECT * FROM runs${input.runId ? " WHERE (id = ? OR short_id = ?)" : ""}`, input.runId ? [input.runId, input.runId] : []).filter(run => !input.projectRoot || run.project_root === input.projectRoot);
|
|
58
|
+
if (input.runId && runs.length !== 1)
|
|
59
|
+
throw new AppError("not_found", "RUN scope is missing or ambiguous", 1);
|
|
60
|
+
const processes = physicalInventory();
|
|
61
|
+
const alive = (record) => {
|
|
62
|
+
if (!record.pid)
|
|
63
|
+
return !['stopped', 'failed'].includes(record.state);
|
|
64
|
+
const physical = processes?.find(item => item.pid === record.pid);
|
|
65
|
+
if (processes && (!physical || physical.zombie)) {
|
|
66
|
+
const metadata = JSON.parse(record.metadata_json);
|
|
67
|
+
// A retired group leader may still own physical children. Merely ending
|
|
68
|
+
// the controller does not settle those children or remote provider work.
|
|
69
|
+
return Boolean(metadata.process_group_id && processes.some(item => item.group === metadata.process_group_id && !item.zombie));
|
|
70
|
+
}
|
|
71
|
+
return !record.pid_started_at || processTreeIsAlive(record);
|
|
72
|
+
};
|
|
73
|
+
return { ok: true, results: runs.map(run => {
|
|
74
|
+
const index = JSON.parse(run.index_json);
|
|
75
|
+
const controllers = table(context, "run_controllers") ? context.db.all("SELECT * FROM run_controllers WHERE project_id = ? AND run_id = ? ORDER BY generation DESC, created_at DESC", [run.project_id, run.id]) : [];
|
|
76
|
+
const controller = controllers[0];
|
|
77
|
+
const manifest = controller ? JSON.parse(controller.manifest_json) : null;
|
|
78
|
+
const resourceContext = manifest?.resource_home ? { ...context, env: { ...context.env, DD_FLOW_RESOURCE_HOME: manifest.resource_home } } : context;
|
|
79
|
+
let records = [], inventoryComplete = false;
|
|
80
|
+
try {
|
|
81
|
+
records = managedProcessStatus(resourceContext).filter(record => record.project_id === run.project_id && record.run_id === run.id && managedProcessRuntimeHome(record, context) === context.ddFlowHome);
|
|
82
|
+
inventoryComplete = true;
|
|
83
|
+
}
|
|
84
|
+
catch { /* Missing registry is uncertainty, never retirement proof. */ }
|
|
85
|
+
const physical = controller && records.find(record => record.id === controller.process_id && record.lease_token === controller.process_lease_token && record.owner_id === controller.controller_id && record.kind === "run-controller");
|
|
86
|
+
const owner = physical?.pid && physical.pid_started_at ? processes && !processes.some(item => item.pid === physical.pid && !item.zombie) && !alive(physical) ? 'absent' : managedProcessObservation(physical) : "unknown";
|
|
87
|
+
const retireController = Boolean(controller && owner === 'absent' && !['completed', 'cancelled', 'superseded', 'stop_target_reached', 'recovery_required', 'capture_failed', 'waiting_for_user', 'waiting_for_context', 'control_requested', 'paused'].includes(controller.status));
|
|
88
|
+
const phase = retireController ? 'recovery_required' : controller?.status ?? null;
|
|
89
|
+
const childrenAlive = records.some(record => record.id !== physical?.id && alive(record)) || Boolean(physical && owner === 'absent' && alive(physical));
|
|
90
|
+
const progressEvent = controller && table(context, "run_controller_events") ? context.db.get("SELECT MAX(created_at) AS at FROM run_controller_events WHERE controller_id = ? AND event_type NOT IN ('health_reconciled','heartbeat')", [controller.controller_id])?.at : null;
|
|
91
|
+
const workProgress = table(context, "works") ? context.db.get("SELECT MAX(at) AS at FROM (SELECT created_at AS at FROM works WHERE project_id=? AND run_id=? UNION ALL SELECT started_at FROM works WHERE project_id=? AND run_id=? UNION ALL SELECT completed_at FROM works WHERE project_id=? AND run_id=?)", [run.project_id, run.id, run.project_id, run.id, run.project_id, run.id])?.at : null;
|
|
92
|
+
let hookProgress = null;
|
|
93
|
+
if (table(context, 'hook_events') && table(context, 'sessions'))
|
|
94
|
+
try {
|
|
95
|
+
hookProgress = context.db.get("SELECT MAX(h.created_at) AS at FROM hook_events h JOIN sessions s ON s.session_id=h.session_id AND s.project_id=h.project_id WHERE s.project_id=? AND s.run_id=? AND h.event_name IN ('PostToolUse','UserPromptSubmit','SubagentStop','Stop','SessionStart')", [run.project_id, run.id])?.at ?? null;
|
|
96
|
+
}
|
|
97
|
+
catch { /* Legacy hooks have no certified Run membership. */ }
|
|
98
|
+
const lastProgress = latest([run.created_at, progressEvent, workProgress, hookProgress, ...index.stage_runs.flatMap(stage => [stage.started_at, stage.completed_at])]);
|
|
99
|
+
const policy = input.noProgressMs ?? (phase === 'starting' ? 120_000 : phase === 'capturing' ? 300_000 : 30 * 60_000);
|
|
100
|
+
const health = assessRunHealth({ status: run.status, phase, owner, childrenAlive, lastProgress, heartbeat: physical?.updated_at ?? null, now: context.now(), noProgressMs: policy, controllerId: controller?.controller_id ?? null, generation: controller?.generation ?? null });
|
|
101
|
+
if (terminalRun(run.status) && (childrenAlive || owner === "alive")) {
|
|
102
|
+
health.state = "unknown";
|
|
103
|
+
health.reason = "terminal_result_has_live_runtime";
|
|
104
|
+
}
|
|
105
|
+
const sessionState = controller ? JSON.parse(controller.state_json) : null;
|
|
106
|
+
const nativeSettled = Boolean(sessionState?.sessions.length && sessionState.sessions.every(session => session.stopped === true));
|
|
107
|
+
const outcomeUnknown = controller && table(context, "run_controller_operations") && context.db.get("SELECT 1 FROM run_controller_operations WHERE controller_id = ? AND generation = ? AND status IN ('accepted','outcome_unknown') LIMIT 1", [controller.controller_id, controller.generation]);
|
|
108
|
+
let transition;
|
|
109
|
+
const guard = table(context, 'run_recovery_guards') ? recoveryGuard(context, run.project_id, run.id) : null;
|
|
110
|
+
const currentGeneration = !guard || !controller || controller.generation === guard.generation;
|
|
111
|
+
if (!terminalRun(run.status) && currentGeneration) {
|
|
112
|
+
if (controller && ["recovery_required", "capture_failed"].includes(controller.status))
|
|
113
|
+
transition = "paused";
|
|
114
|
+
else if (controller?.status === "stop_target_reached" && owner !== "alive" && nativeSettled && inventoryComplete && !childrenAlive)
|
|
115
|
+
transition = "paused";
|
|
116
|
+
else if (health.state === "owner_lost" && owner === "absent") {
|
|
117
|
+
transition = controller?.last_error_json && nativeSettled && inventoryComplete && !childrenAlive && !outcomeUnknown && !guard ? "failed" : "paused";
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const nextStatus = transition ?? run.status;
|
|
121
|
+
if (transition === 'failed') {
|
|
122
|
+
health.state = 'settled';
|
|
123
|
+
health.reason = 'saved_terminal_result';
|
|
124
|
+
}
|
|
125
|
+
const unchanged = index.health && JSON.stringify({ ...index.health, observed_at: null }) === JSON.stringify({ ...health, observed_at: null }) && nextStatus === run.status;
|
|
126
|
+
let changed = false;
|
|
127
|
+
if (input.apply && !unchanged) {
|
|
128
|
+
// Verify the same physical inventory immediately before publishing. A
|
|
129
|
+
// replacement/renewal invalidates this observation, even with the same PID.
|
|
130
|
+
const binding = (items) => JSON.stringify(items.map(item => ({ ...managedProcessBinding(item, manifest?.resource_home ?? context.ddFlowHome), state: item.state, updated_at: item.updated_at, lease_expires_at: item.lease_expires_at })));
|
|
131
|
+
if (inventoryComplete) {
|
|
132
|
+
const fresh = managedProcessStatus(resourceContext).filter(record => record.project_id === run.project_id && record.run_id === run.id && managedProcessRuntimeHome(record, context) === context.ddFlowHome);
|
|
133
|
+
if (binding(fresh) !== binding(records) || physical && owner === "absent" && managedProcessObservation(physical) !== 'absent')
|
|
134
|
+
throw new AppError("run_health_changed", "Runtime ownership changed during reconciliation", 1);
|
|
135
|
+
}
|
|
136
|
+
context.db.writeTransaction(() => {
|
|
137
|
+
const current = controller && context.db.get("SELECT * FROM run_controllers WHERE controller_id = ?", [controller.controller_id]);
|
|
138
|
+
if (controller && JSON.stringify(current) !== JSON.stringify(controller))
|
|
139
|
+
throw new AppError("run_health_changed", "Controller changed during reconciliation", 1);
|
|
140
|
+
reconcileStoredFlowRun(context, run, health, transition, inventoryComplete && owner !== "alive" && !childrenAlive && nativeSettled);
|
|
141
|
+
if (controller && retireController) {
|
|
142
|
+
context.db.run("UPDATE run_controllers SET status = 'recovery_required', updated_at = ? WHERE controller_id = ? AND owner_token = ? AND generation = ?", [context.now(), controller.controller_id, controller.owner_token, controller.generation]);
|
|
143
|
+
}
|
|
144
|
+
changed = true;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return { project_id: run.project_id, run_id: run.id, previous_status: run.status, status: nextStatus, health, changed, would_change: !unchanged };
|
|
148
|
+
}) };
|
|
149
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { ToolObservations, replayToolJournal } from "../harness-runtime/lib/tool-observations.mjs";
|
|
4
|
+
import { harnessKey } from "./harness-config.js";
|
|
5
|
+
/** Evidence has ancestry, not executable ownership. Never open a source home. */
|
|
6
|
+
export function runObservations(context, projectId, runId) {
|
|
7
|
+
const home = fs.realpathSync(context.ddFlowHome), sources = new Map(), reasons = [];
|
|
8
|
+
const sessions = context.db.all("SELECT session_id, provider_session_id, harness, transcript_path FROM sessions WHERE project_id = ? AND run_id = ?", [projectId, runId]);
|
|
9
|
+
const inside = (root, file) => { const p = path.relative(root, file); return p !== "" && p !== ".." && !p.startsWith(`..${path.sep}`) && !path.isAbsolute(p); };
|
|
10
|
+
const add = (id, nativeId, journal, origin, provenance, harness) => {
|
|
11
|
+
if (sources.has(id))
|
|
12
|
+
return;
|
|
13
|
+
const candidates = sessions.filter(s => (s.provider_session_id ?? s.session_id) === nativeId && (!harness || s.harness === harness));
|
|
14
|
+
if (candidates.length > 1) {
|
|
15
|
+
reasons.push("journal_session_ambiguous");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const owner = candidates[0];
|
|
19
|
+
if (!owner)
|
|
20
|
+
return;
|
|
21
|
+
const source = { id, provenance, session: { harness_id: owner.harness, session_id: nativeId }, path: null, status: "unavailable" };
|
|
22
|
+
sources.set(id, source);
|
|
23
|
+
if (typeof journal !== "string" || !path.isAbsolute(journal) || !inside(origin, journal)) {
|
|
24
|
+
source.reason = "journal_outside_owned_home";
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
source.path = path.relative(origin, journal);
|
|
28
|
+
const file = path.resolve(home, source.path);
|
|
29
|
+
try {
|
|
30
|
+
if (!inside(home, fs.realpathSync(file))) {
|
|
31
|
+
source.reason = "journal_outside_owned_home";
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (!fs.statSync(file).isFile()) {
|
|
35
|
+
source.reason = "journal_not_file";
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
source.status = "available";
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
source.reason = "journal_missing";
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const controllers = (rows, origin, provenance) => {
|
|
45
|
+
for (const row of rows) {
|
|
46
|
+
if (row.project_id !== projectId || row.run_id !== runId)
|
|
47
|
+
continue;
|
|
48
|
+
try {
|
|
49
|
+
for (const session of JSON.parse(row.state_json).sessions ?? [])
|
|
50
|
+
add(`${row.controller_id}:${session.id}`, session.id, session.journal, origin, provenance, session.profile?.harness ? harnessKey(session.profile.harness) : undefined);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
reasons.push("controller_evidence_invalid");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
if (context.db.all("SELECT 1 FROM sqlite_schema WHERE type = 'table' AND name = 'run_controllers'").length) {
|
|
58
|
+
controllers(context.db.all("SELECT controller_id, project_id, run_id, state_json FROM run_controllers WHERE project_id = ? AND run_id = ?", [projectId, runId]), home, "current");
|
|
59
|
+
}
|
|
60
|
+
const imports = path.join(home, "snapshot-imports");
|
|
61
|
+
if (fs.existsSync(imports))
|
|
62
|
+
for (const file of fs.readdirSync(imports).filter(name => name.endsWith(".json")).sort()) {
|
|
63
|
+
try {
|
|
64
|
+
const location = path.join(imports, file);
|
|
65
|
+
if (!inside(home, fs.realpathSync(location))) {
|
|
66
|
+
reasons.push("lineage_outside_owned_home");
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const archive = JSON.parse(fs.readFileSync(location, "utf8"));
|
|
70
|
+
if (archive.schema_id !== "dd-flow/snapshot-runtime-lineage@1" || archive.run_id !== runId)
|
|
71
|
+
continue;
|
|
72
|
+
if (typeof archive.source_runtime !== "string" || !path.isAbsolute(archive.source_runtime)) {
|
|
73
|
+
reasons.push("lineage_source_invalid");
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
controllers(archive.run_tables?.run_controllers ?? [], archive.source_runtime, "inherited");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
reasons.push("lineage_evidence_invalid");
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const reducer = new ToolObservations();
|
|
83
|
+
for (const reason of reasons)
|
|
84
|
+
reducer.gaps.add(reason);
|
|
85
|
+
const expectedCodexIds = sessions.filter(session => session.harness === "codex-desktop").map(session => session.provider_session_id ?? session.session_id);
|
|
86
|
+
const replay = (source, sessionId) => {
|
|
87
|
+
const file = path.join(home, source.path);
|
|
88
|
+
let fd = null;
|
|
89
|
+
try {
|
|
90
|
+
const actual = fs.realpathSync(file);
|
|
91
|
+
if (!inside(home, actual))
|
|
92
|
+
throw new Error("journal escaped owned home");
|
|
93
|
+
fd = fs.openSync(actual, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW | fs.constants.O_NONBLOCK);
|
|
94
|
+
if (!fs.fstatSync(fd).isFile())
|
|
95
|
+
throw new Error("journal is not a regular file");
|
|
96
|
+
replayToolJournal(file, { harness: source.session.harness_id, rootSessionId: sessionId, text: fs.readFileSync(fd, "utf8"), ...(source.session.harness_id === "codex-desktop" ? { expectedSessionIds: expectedCodexIds } : {}) }, reducer);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
source.status = "unavailable";
|
|
100
|
+
source.reason = "journal_unavailable_during_read";
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
if (fd !== null)
|
|
104
|
+
fs.closeSync(fd);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
for (const source of sources.values()) {
|
|
108
|
+
if (source.status !== "available")
|
|
109
|
+
continue;
|
|
110
|
+
replay(source, source.session.session_id);
|
|
111
|
+
}
|
|
112
|
+
const covered = () => new Set(reducer.summary().sessions.map(item => JSON.stringify(item.session)));
|
|
113
|
+
// A managed root journal can contain all of its children's native events.
|
|
114
|
+
// Select transcript fallback only after replay reveals an actual gap.
|
|
115
|
+
for (const session of sessions) {
|
|
116
|
+
const nativeId = session.provider_session_id ?? session.session_id;
|
|
117
|
+
const sessionSummary = reducer.summary(nativeId);
|
|
118
|
+
if (!session.transcript_path || covered().has(JSON.stringify({ harness_id: session.harness, session_id: nativeId }))
|
|
119
|
+
&& sessionSummary.completeness === "complete" && sessionSummary.outcome_completeness === "complete")
|
|
120
|
+
continue;
|
|
121
|
+
const id = `transcript:${session.harness}:${nativeId}`;
|
|
122
|
+
add(id, nativeId, session.transcript_path, home, "current", session.harness);
|
|
123
|
+
const source = sources.get(id);
|
|
124
|
+
if (source?.status === "available")
|
|
125
|
+
replay(source, nativeId);
|
|
126
|
+
}
|
|
127
|
+
for (const source of sources.values())
|
|
128
|
+
if (source.status !== "available"
|
|
129
|
+
&& !covered().has(JSON.stringify(source.session)))
|
|
130
|
+
reducer.gaps.add(source.reason ?? "journal_unavailable");
|
|
131
|
+
const expected = [...new Map(sessions.map(s => { const session = { harness_id: s.harness, session_id: s.provider_session_id ?? s.session_id }; return [JSON.stringify(session), session]; })).values()];
|
|
132
|
+
const expectedIds = new Set(expected.map(s => JSON.stringify(s)));
|
|
133
|
+
for (const [key, event] of reducer.calls)
|
|
134
|
+
if (!expectedIds.has(JSON.stringify(event.session))) {
|
|
135
|
+
reducer.calls.delete(key);
|
|
136
|
+
}
|
|
137
|
+
for (const [key, event] of reducer.turns)
|
|
138
|
+
if (!expectedIds.has(JSON.stringify(event.session))) {
|
|
139
|
+
reducer.turns.delete(key);
|
|
140
|
+
}
|
|
141
|
+
for (const [key, event] of reducer.sources)
|
|
142
|
+
if (!expectedIds.has(JSON.stringify(event.session)))
|
|
143
|
+
reducer.sources.delete(key);
|
|
144
|
+
const summary = reducer.summary();
|
|
145
|
+
const observed = new Set(summary.sessions.map(s => JSON.stringify(s.session)));
|
|
146
|
+
const missing = expected.filter(s => !observed.has(JSON.stringify(s)));
|
|
147
|
+
const completeness = missing.length || summary.completeness !== "complete" || summary.outcome_completeness !== "complete" ? "partial" : "complete";
|
|
148
|
+
return { schema_id: "dd-flow/run-observations@1", home, sources: [...sources.values()], tools: { ...summary,
|
|
149
|
+
completeness, status: observed.size === 0 ? "unavailable" : completeness === "complete" ? "measured" : "partial",
|
|
150
|
+
observed_sessions: expected.length - missing.length, expected_sessions: expected.length, unavailable_sessions: missing.map(s => s.session_id), missing_sessions: missing,
|
|
151
|
+
reasons: [...new Set([...summary.reasons, ...(missing.length ? ["sessions_without_tool_observations"] : [])])] } };
|
|
152
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import path from "node:path";
|
|
3
2
|
import { reconcileSessionCoverageRows } from "../domain/session-coverage.js";
|
|
4
3
|
import { publicSessionIdentity } from "./session-identity.js";
|
|
4
|
+
import { publishRunProjections } from "./runs.js";
|
|
5
5
|
export function refreshRunSessionProjection(context, projectId, runId) {
|
|
6
|
+
// Review children can finish concurrently in separate processes. Reserve the
|
|
7
|
+
// writer before reading the RUN index so a sibling cannot invalidate it.
|
|
8
|
+
context.db.writeTransaction(() => refreshRunSessionProjectionLocked(context, projectId, runId), "run-projection.refresh");
|
|
9
|
+
}
|
|
10
|
+
function refreshRunSessionProjectionLocked(context, projectId, runId) {
|
|
6
11
|
const run = context.db.get("SELECT id, flow_kind, status, project_root, subject_type, subject_id, runtime_path, run_index_path, index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
7
12
|
if (!run)
|
|
8
13
|
return;
|
|
@@ -27,7 +32,7 @@ export function refreshRunSessionProjection(context, projectId, runId) {
|
|
|
27
32
|
missing: coverage.missing_unit_ids,
|
|
28
33
|
diagnostics: coverage.diagnostics
|
|
29
34
|
};
|
|
30
|
-
const plan = run.subject_type === "protocol" ? planProjection(context, projectId, run.subject_id, run.project_root) : {};
|
|
35
|
+
const plan = run.subject_type === "protocol" ? planProjection(context, projectId, run.subject_id, run.project_root, index) : {};
|
|
31
36
|
const workers = workerProjection(context, projectId, runId);
|
|
32
37
|
const vnext = run.flow_kind === "vnext_specify" || run.flow_kind === "vnext_protocolize";
|
|
33
38
|
const hadLegacyCoverage = vnext && ("session_coverage" in index || "usage_coverage" in index);
|
|
@@ -42,8 +47,8 @@ export function refreshRunSessionProjection(context, projectId, runId) {
|
|
|
42
47
|
&& JSON.stringify(index.works ?? []) === JSON.stringify(works)
|
|
43
48
|
&& index.root_work_id === rootWorkId
|
|
44
49
|
&& (vnext || JSON.stringify(index.session_coverage) === JSON.stringify(sessionCoverage))
|
|
45
|
-
&& JSON.stringify(index.plan_ref) === JSON.stringify(plan.plan_ref)
|
|
46
|
-
&& JSON.stringify(index.plan_progress) === JSON.stringify(plan.plan_progress)
|
|
50
|
+
&& (!plan.plan_ref || JSON.stringify(index.plan_ref) === JSON.stringify(plan.plan_ref))
|
|
51
|
+
&& (!plan.plan_progress || JSON.stringify(index.plan_progress) === JSON.stringify(plan.plan_progress))
|
|
47
52
|
&& (vnext || JSON.stringify(index.workers ?? {}) === JSON.stringify(workers))
|
|
48
53
|
&& !hadLegacyCoverage)
|
|
49
54
|
return;
|
|
@@ -59,44 +64,23 @@ export function refreshRunSessionProjection(context, projectId, runId) {
|
|
|
59
64
|
if (!vnext)
|
|
60
65
|
index.workers = workers;
|
|
61
66
|
index.updated_at = context.now();
|
|
62
|
-
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
: 1;
|
|
68
|
-
index.runtime_revision = runtimeRevision;
|
|
69
|
-
const authoritative = { ...(runtime ?? {}), ...index, schema_id: String(index.schema_id ?? runtime?.schema_id ?? "dd-flow/flow-run@3") };
|
|
70
|
-
authoritative.sessions = sessions;
|
|
71
|
-
authoritative.works = works;
|
|
72
|
-
authoritative.root_work_id = rootWorkId;
|
|
73
|
-
if (vnext) {
|
|
74
|
-
delete authoritative.session_coverage;
|
|
75
|
-
delete authoritative.usage_coverage;
|
|
76
|
-
delete authoritative.workers;
|
|
77
|
-
delete authoritative.current_stage;
|
|
78
|
-
delete authoritative.attempts;
|
|
79
|
-
}
|
|
80
|
-
else
|
|
81
|
-
authoritative.session_coverage = sessionCoverage;
|
|
82
|
-
if (plan.plan_ref)
|
|
83
|
-
authoritative.plan_ref = plan.plan_ref;
|
|
84
|
-
if (plan.plan_progress)
|
|
85
|
-
authoritative.plan_progress = plan.plan_progress;
|
|
86
|
-
if (!vnext)
|
|
87
|
-
authoritative.workers = workers;
|
|
88
|
-
authoritative.updated_at = index.updated_at;
|
|
89
|
-
authoritative.runtime_revision = runtimeRevision;
|
|
90
|
-
if (run.status !== "discarded" || fs.existsSync(run.runtime_path))
|
|
91
|
-
writeJson(run.runtime_path, authoritative);
|
|
92
|
-
context.db.run("UPDATE runs SET index_json = ?, updated_at = ? WHERE project_id = ? AND id = ?", [JSON.stringify(index), index.updated_at, projectId, runId]);
|
|
67
|
+
index.runtime_revision = typeof index.runtime_revision === "number" ? index.runtime_revision + 1 : 1;
|
|
68
|
+
const updated = context.db.run("UPDATE runs SET index_json = ?, updated_at = ? WHERE project_id = ? AND id = ? AND index_json = ?", [JSON.stringify(index), index.updated_at, projectId, runId, run.index_json]);
|
|
69
|
+
if (updated.changes !== 1)
|
|
70
|
+
throw new Error("RUN projection changed during preparation");
|
|
71
|
+
context.db.afterCommit(() => publishRunProjections(context, projectId, runId));
|
|
93
72
|
}
|
|
94
|
-
function planProjection(context, projectId, protocolId, projectRoot) {
|
|
95
|
-
const binding = context.db.get("SELECT plan_path, plan_revision, plan_sha256 FROM plan_bindings WHERE project_id = ? AND protocol_id = ?", [projectId, protocolId]);
|
|
73
|
+
function planProjection(context, projectId, protocolId, projectRoot, index) {
|
|
74
|
+
const binding = context.db.get("SELECT plan_id, plan_path, plan_revision, plan_sha256 FROM plan_bindings WHERE project_id = ? AND protocol_id = ?", [projectId, protocolId]);
|
|
96
75
|
if (!binding)
|
|
97
76
|
return {};
|
|
98
77
|
const planPath = path.relative(projectRoot, binding.plan_path).split(path.sep).join("/");
|
|
99
|
-
const
|
|
78
|
+
const priorRef = index.plan_ref && typeof index.plan_ref === "object" && !Array.isArray(index.plan_ref) ? index.plan_ref : {};
|
|
79
|
+
const planId = binding.plan_id ?? (typeof priorRef.plan_id === "string" ? priorRef.plan_id : null);
|
|
80
|
+
// A pre-migration binding without a RUN plan_ref needs canonical rebind before
|
|
81
|
+
// this projection can be updated; never invent a plan identifier.
|
|
82
|
+
if (!planId)
|
|
83
|
+
return {};
|
|
100
84
|
const progress = Object.fromEntries(context.db.all("SELECT item_id, status, summary, evidence_json FROM plan_progress WHERE project_id = ? AND protocol_id = ? ORDER BY item_id", [projectId, protocolId]).map((row) => [row.item_id, {
|
|
101
85
|
status: row.status,
|
|
102
86
|
...(row.summary ? { summary: row.summary } : {}),
|
|
@@ -112,18 +96,6 @@ function planProjection(context, projectId, protocolId, projectRoot) {
|
|
|
112
96
|
plan_progress: progress
|
|
113
97
|
};
|
|
114
98
|
}
|
|
115
|
-
function readPlanId(planPath) {
|
|
116
|
-
try {
|
|
117
|
-
const value = JSON.parse(fs.readFileSync(planPath, "utf8"));
|
|
118
|
-
if (value && typeof value === "object" && !Array.isArray(value) && typeof value.plan_id === "string") {
|
|
119
|
-
return value.plan_id;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
// The canonical validator owns malformed-plan errors; projection stays bounded.
|
|
124
|
-
}
|
|
125
|
-
return "unknown-plan";
|
|
126
|
-
}
|
|
127
99
|
function workerProjection(context, projectId, runId) {
|
|
128
100
|
return Object.fromEntries(context.db.all(`SELECT j.job_id, j.plan_item_id, j.status, j.worker_session_id, s.harness, s.provider_session_id
|
|
129
101
|
FROM flow_jobs j LEFT JOIN sessions s ON s.project_id = j.project_id AND s.session_id = j.worker_session_id
|
|
@@ -182,17 +154,3 @@ function parseCoverageUnits(value) {
|
|
|
182
154
|
return [];
|
|
183
155
|
}
|
|
184
156
|
}
|
|
185
|
-
function readJson(file) {
|
|
186
|
-
try {
|
|
187
|
-
return fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, "utf8")) : undefined;
|
|
188
|
-
}
|
|
189
|
-
catch {
|
|
190
|
-
return undefined;
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
function writeJson(file, value) {
|
|
194
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
195
|
-
const temporary = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
196
|
-
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`);
|
|
197
|
-
fs.renameSync(temporary, file);
|
|
198
|
-
}
|