@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
|
@@ -1,14 +1,243 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { AppError } from "../shared/errors.js";
|
|
5
|
+
import { withProjectionLock } from "../storage/projection-lock.js";
|
|
3
6
|
import { writeJsonAtomic } from "../storage/paths.js";
|
|
7
|
+
import { assertRunBundleSqlAuthority } from "./runs.js";
|
|
8
|
+
import { hybridDigest } from "./hybrid-contracts.js";
|
|
9
|
+
/** Accepted bytes come from SQL receipts, never from the mutable publication.
|
|
10
|
+
* Stage completion and its independent committed checksum must agree. This is
|
|
11
|
+
* byte custody, not a substitute for the registered handler's semantic gates.
|
|
12
|
+
*/
|
|
13
|
+
export function readAcceptedStageData(context, scope) {
|
|
14
|
+
function refuse() { throw new AppError("stage_data_custody_invalid", "Accepted stage data lacks matching committed SQL byte custody", 1, { run_id: scope.runId, stage: scope.stage }); }
|
|
15
|
+
const run = context.db.get("SELECT index_json, run_root, run_dir FROM runs WHERE project_id = ? AND id = ?", [scope.projectId, scope.runId]);
|
|
16
|
+
if (!run)
|
|
17
|
+
refuse();
|
|
18
|
+
const index = JSON.parse(run.index_json);
|
|
19
|
+
assertRunBundleSqlAuthority(context, scope, index.execution_bundle);
|
|
20
|
+
const stage = index.stage_runs?.find((item) => item.stage === scope.stage);
|
|
21
|
+
const portable = (value) => typeof value === "string" && Boolean(value) && !path.posix.isAbsolute(value) && !path.win32.isAbsolute(value) && !value.includes("\\") && !value.includes("\0") && value.split("/").every(part => Boolean(part) && part !== "." && part !== "..");
|
|
22
|
+
if (!stage || stage.status !== "done" || !portable(stage.dir) || !portable(stage.data)
|
|
23
|
+
|| typeof stage.attempt !== "string" || !/^try-[0-9]{3,}$/.test(stage.attempt)
|
|
24
|
+
|| typeof stage.data_sha256 !== "string" || !/^[a-f0-9]{64}$/.test(stage.data_sha256))
|
|
25
|
+
refuse();
|
|
26
|
+
const root = run.run_root ?? run.run_dir;
|
|
27
|
+
if (!path.isAbsolute(root))
|
|
28
|
+
refuse();
|
|
29
|
+
const relative = `${stage.dir}/${stage.data}`, destination = path.resolve(root, relative);
|
|
30
|
+
const rows = context.db.all("SELECT event_type, payload_json FROM audit_events WHERE project_id = ? AND event_type IN ('flow_run.stage_packet', 'flow_run.stage_report') AND json_extract(payload_json, '$.run_id') = ? AND json_extract(payload_json, '$.stage') = ? AND json_extract(payload_json, '$.attempt') = ? AND json_extract(payload_json, '$.sha256') = ?", [scope.projectId, scope.runId, scope.stage, stage.attempt, stage.data_sha256]);
|
|
31
|
+
let accepted;
|
|
32
|
+
for (const row of rows) {
|
|
33
|
+
const receipt = JSON.parse(row.payload_json);
|
|
34
|
+
if (receipt.sha256 !== stage.data_sha256)
|
|
35
|
+
continue;
|
|
36
|
+
const locator = row.event_type === "flow_run.stage_packet" ? receipt.file : typeof receipt.root === "string" ? path.join(receipt.root, "stage-report.json") : null;
|
|
37
|
+
if (typeof locator !== "string" || resolveStagePublicationPath(context, scope.projectId, scope.runId, locator) !== destination)
|
|
38
|
+
continue;
|
|
39
|
+
let bytes;
|
|
40
|
+
if (row.event_type === "flow_run.stage_packet") {
|
|
41
|
+
if (typeof receipt.base64 !== "string")
|
|
42
|
+
refuse();
|
|
43
|
+
bytes = Buffer.from(receipt.base64, "base64");
|
|
44
|
+
if (bytes.toString("base64") !== receipt.base64)
|
|
45
|
+
refuse();
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
if (typeof receipt.bytes?.json !== "string")
|
|
49
|
+
refuse();
|
|
50
|
+
bytes = Buffer.from(receipt.bytes.json);
|
|
51
|
+
}
|
|
52
|
+
if (!bytes.length || crypto.createHash("sha256").update(bytes).digest("hex") !== stage.data_sha256)
|
|
53
|
+
refuse();
|
|
54
|
+
if (accepted && !accepted.equals(bytes))
|
|
55
|
+
refuse();
|
|
56
|
+
accepted = bytes;
|
|
57
|
+
}
|
|
58
|
+
if (!accepted)
|
|
59
|
+
refuse();
|
|
60
|
+
return { bytes: Buffer.from(accepted), result: { path: relative, sha256: stage.data_sha256 },
|
|
61
|
+
input_sha256: stage.input_sha256, data_schema_id: stage.data_schema_id,
|
|
62
|
+
authority_sha256: hybridDigest({ scope, attempt: stage.attempt, directory: stage.dir, data: stage.data,
|
|
63
|
+
input_sha256: stage.input_sha256 ?? null, data_schema_id: stage.data_schema_id ?? null,
|
|
64
|
+
anchor: index.execution_bundle ?? null, data_sha256: stage.data_sha256 }) };
|
|
65
|
+
}
|
|
4
66
|
/** Deterministic JSON -> Markdown/HTML projection shared by every stage. */
|
|
5
67
|
export function writeStageReport(root, report) {
|
|
6
68
|
const json = path.join(root, "stage-report.json");
|
|
7
69
|
const markdown = path.join(root, "stage-report.md");
|
|
8
70
|
const html = path.join(root, "stage-report.html");
|
|
71
|
+
const normalized = normalizeStageReport(report);
|
|
72
|
+
writeJsonAtomic(json, normalized);
|
|
73
|
+
const text = renderStageReportMarkdown(normalized);
|
|
74
|
+
fs.writeFileSync(markdown, text);
|
|
75
|
+
fs.writeFileSync(html, renderStageReportHtml(normalized, text));
|
|
76
|
+
return { json, markdown, html };
|
|
77
|
+
}
|
|
78
|
+
export function prepareStageReport(report) {
|
|
79
|
+
const normalized = normalizeStageReport(report);
|
|
80
|
+
const json = `${JSON.stringify(normalized, null, 2)}\n`;
|
|
81
|
+
const markdown = renderStageReportMarkdown(normalized);
|
|
82
|
+
const html = renderStageReportHtml(normalized, markdown);
|
|
83
|
+
return { normalized, bytes: { json, markdown, html }, sha256: crypto.createHash("sha256").update(json).digest("hex") };
|
|
84
|
+
}
|
|
85
|
+
export function prepareStagePacket(file, bytes) {
|
|
86
|
+
if (fs.existsSync(file) && !bytes.equals(fs.readFileSync(file)))
|
|
87
|
+
throw new AppError("stage_packet_conflict", "An existing Stage packet differs from prepared bytes", 2, { file });
|
|
88
|
+
return { file, bytes, sha256: crypto.createHash("sha256").update(bytes).digest("hex") };
|
|
89
|
+
}
|
|
90
|
+
export function acceptStagePacket(context, input) {
|
|
91
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [input.projectId, input.runId]);
|
|
92
|
+
const index = run ? JSON.parse(run.index_json) : null;
|
|
93
|
+
const attempt = index?.stage_runs?.find((item) => item.stage === input.stage)?.attempt;
|
|
94
|
+
if (!attempt)
|
|
95
|
+
throw new AppError("stage_packet_owner_missing", "Stage packet has no owning attempt", 1, { run_id: input.runId, stage: input.stage });
|
|
96
|
+
const payload = { run_id: input.runId, stage: input.stage, attempt, file: input.prepared.file, sha256: input.prepared.sha256, base64: input.prepared.bytes.toString("base64") };
|
|
97
|
+
context.db.run("INSERT INTO audit_events (project_id, event_type, forced, payload_json, created_at) VALUES (?, 'flow_run.stage_packet', 0, ?, ?)", [input.projectId, JSON.stringify(payload), context.now()]);
|
|
98
|
+
context.db.afterCommit(() => publishStagePacket(context, input.projectId, input.runId, input.stage, input.prepared.file));
|
|
99
|
+
}
|
|
100
|
+
export function publishStagePacket(context, projectId, runId, stage, file) {
|
|
101
|
+
file = resolveStagePublicationPath(context, projectId, runId, file);
|
|
102
|
+
assertPublicationPath(context, projectId, runId, file);
|
|
103
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
104
|
+
withProjectionLock(`${file}.publish-lock`, () => {
|
|
105
|
+
assertPublicationPath(context, projectId, runId, file);
|
|
106
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
107
|
+
const index = run ? JSON.parse(run.index_json) : null;
|
|
108
|
+
const currentAttempt = index?.stage_runs?.find((item) => item.stage === stage)?.attempt;
|
|
109
|
+
const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.stage_packet' ORDER BY id DESC", [projectId]);
|
|
110
|
+
const packet = rows.map((row) => JSON.parse(row.payload_json)).find((item) => item.run_id === runId && item.stage === stage && item.attempt === currentAttempt && resolveStagePublicationPath(context, projectId, runId, item.file) === file);
|
|
111
|
+
if (!packet)
|
|
112
|
+
return;
|
|
113
|
+
const bytes = Buffer.from(packet.base64, "base64");
|
|
114
|
+
if (crypto.createHash("sha256").update(bytes).digest("hex") !== packet.sha256)
|
|
115
|
+
throw new AppError("stage_packet_invalid", "Stored Stage packet hash does not match its bytes", 1, { file });
|
|
116
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
117
|
+
try {
|
|
118
|
+
fs.writeFileSync(file, bytes, { flag: "wx" });
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error.code !== "EEXIST")
|
|
122
|
+
throw error;
|
|
123
|
+
if (!bytes.equals(fs.readFileSync(file)))
|
|
124
|
+
throw new AppError("stage_packet_conflict", "Accepted Stage packet differs from the published file", 1, { file, run_id: runId, stage, attempt: currentAttempt });
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
/** SQL receipt and exact bytes are committed with the owning Stage transition. */
|
|
129
|
+
export function acceptStageReport(context, input) {
|
|
130
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [input.projectId, input.runId]);
|
|
131
|
+
const index = run ? JSON.parse(run.index_json) : null;
|
|
132
|
+
const attempt = index?.stage_runs?.find((item) => item.stage === input.stage)?.attempt;
|
|
133
|
+
if (!attempt)
|
|
134
|
+
throw new AppError("stage_report_owner_missing", "Stage report has no owning attempt", 1, { run_id: input.runId, stage: input.stage });
|
|
135
|
+
const payload = { run_id: input.runId, stage: input.stage, attempt, root: input.root, sha256: input.prepared.sha256, bytes: input.prepared.bytes };
|
|
136
|
+
context.db.run("INSERT INTO audit_events (project_id, event_type, forced, payload_json, created_at) VALUES (?, 'flow_run.stage_report', 0, ?, ?)", [input.projectId, JSON.stringify(payload), context.now()]);
|
|
137
|
+
context.db.afterCommit(() => publishStageReport(context, input.projectId, input.runId, input.stage, input.root));
|
|
138
|
+
}
|
|
139
|
+
/** Replays the latest committed receipt, never an obsolete attempt. */
|
|
140
|
+
export function publishStageReport(context, projectId, runId, stage, root) {
|
|
141
|
+
root = resolveStagePublicationPath(context, projectId, runId, root);
|
|
142
|
+
assertPublicationPath(context, projectId, runId, root);
|
|
143
|
+
withProjectionLock(`${root}.report-publish-lock`, () => {
|
|
144
|
+
assertPublicationPath(context, projectId, runId, root);
|
|
145
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
146
|
+
const index = run ? JSON.parse(run.index_json) : null;
|
|
147
|
+
const currentAttempt = index?.stage_runs?.find((item) => item.stage === stage)?.attempt;
|
|
148
|
+
const events = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.stage_report' ORDER BY id DESC", [projectId]);
|
|
149
|
+
const receipt = events.map((row) => JSON.parse(row.payload_json)).find((item) => item.run_id === runId && item.stage === stage && item.attempt === currentAttempt && resolveStagePublicationPath(context, projectId, runId, item.root) === root);
|
|
150
|
+
if (!receipt)
|
|
151
|
+
return;
|
|
152
|
+
fs.mkdirSync(root, { recursive: true });
|
|
153
|
+
for (const [name, bytes] of Object.entries(receipt.bytes)) {
|
|
154
|
+
const file = path.join(root, `stage-report.${name === "json" ? "json" : name === "markdown" ? "md" : "html"}`);
|
|
155
|
+
assertPublicationPath(context, projectId, runId, file);
|
|
156
|
+
try {
|
|
157
|
+
fs.writeFileSync(file, bytes, { flag: "wx" });
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
if (error.code !== "EEXIST")
|
|
161
|
+
throw error;
|
|
162
|
+
if (fs.readFileSync(file, "utf8") !== bytes)
|
|
163
|
+
throw new AppError("stage_report_conflict", "Accepted Stage report differs from the published file", 1, { run_id: runId, stage, attempt: currentAttempt, file });
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
/** Operational destinations follow validated imports, while audit bytes retain
|
|
169
|
+
* their original locators. SQL-only so readers may also use it in settlement. */
|
|
170
|
+
export function resolveStagePublicationPath(context, projectId, runId, locator) {
|
|
171
|
+
const run = context.db.get("SELECT run_root FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
172
|
+
if (!run?.run_root || !path.isAbsolute(locator))
|
|
173
|
+
throw new AppError("stage_packet_invalid", "Stage publication has no absolute bound RUN locator", 1, { run_id: runId, locator });
|
|
174
|
+
let destination = path.resolve(locator);
|
|
175
|
+
const mappings = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.publication_relocation' ORDER BY id", [projectId]);
|
|
176
|
+
for (const row of mappings) {
|
|
177
|
+
const mapping = JSON.parse(row.payload_json);
|
|
178
|
+
if (mapping.run_id !== runId || !path.isAbsolute(mapping.from) || !path.isAbsolute(mapping.to))
|
|
179
|
+
continue;
|
|
180
|
+
const relative = path.relative(mapping.from, destination);
|
|
181
|
+
if (relative && relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))
|
|
182
|
+
destination = path.resolve(mapping.to, relative);
|
|
183
|
+
}
|
|
184
|
+
const relative = path.relative(run.run_root, destination);
|
|
185
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path.sep}`) || path.isAbsolute(relative))
|
|
186
|
+
throw new AppError("publication_pending", "Stage publication escaped its bound RUN lineage", 1, { effect: "committed", run_id: runId, locator });
|
|
187
|
+
return destination;
|
|
188
|
+
}
|
|
189
|
+
/** Recheck the actual destination after preparation: a missing leaf may have
|
|
190
|
+
* an existing symlink ancestor, and retained packet bytes never authorize it. */
|
|
191
|
+
function assertPublicationPath(context, projectId, runId, file) {
|
|
192
|
+
const run = context.db.get("SELECT run_root FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
193
|
+
const root = run?.run_root && path.resolve(run.run_root), destination = path.resolve(file);
|
|
194
|
+
if (!root || !destination.startsWith(`${root}${path.sep}`))
|
|
195
|
+
throw new AppError("publication_pending", "Stage publication escaped its RUN", 1, { effect: "committed", run_id: runId, file });
|
|
196
|
+
let ancestor = destination;
|
|
197
|
+
while (!fs.existsSync(ancestor) && ancestor !== root)
|
|
198
|
+
ancestor = path.dirname(ancestor);
|
|
199
|
+
const actual = fs.realpathSync(ancestor), realRoot = fs.realpathSync(root);
|
|
200
|
+
if (actual !== realRoot && !actual.startsWith(`${realRoot}${path.sep}`))
|
|
201
|
+
throw new AppError("publication_pending", "Stage publication escaped its RUN through a symlink", 1, { effect: "committed", run_id: runId, file });
|
|
202
|
+
}
|
|
203
|
+
/** Admission repair for predecessor reports; the stage being retried is archived separately. */
|
|
204
|
+
export function reconcileRunStageReports(context, projectId, runId, exceptStage) {
|
|
205
|
+
const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.stage_report' ORDER BY id DESC", [projectId]);
|
|
206
|
+
const seen = new Set();
|
|
207
|
+
for (const row of rows) {
|
|
208
|
+
const receipt = JSON.parse(row.payload_json);
|
|
209
|
+
if (receipt.run_id !== runId || typeof receipt.stage !== "string" || typeof receipt.root !== "string" || receipt.stage === exceptStage || seen.has(receipt.stage))
|
|
210
|
+
continue;
|
|
211
|
+
seen.add(receipt.stage);
|
|
212
|
+
publishStageReport(context, projectId, runId, receipt.stage, receipt.root);
|
|
213
|
+
}
|
|
214
|
+
const packets = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.stage_packet' ORDER BY id DESC", [projectId]);
|
|
215
|
+
const packetFiles = new Set();
|
|
216
|
+
for (const row of packets) {
|
|
217
|
+
const packet = JSON.parse(row.payload_json);
|
|
218
|
+
if (packet.run_id !== runId || typeof packet.stage !== "string" || typeof packet.file !== "string" || packet.stage === exceptStage || packetFiles.has(packet.file))
|
|
219
|
+
continue;
|
|
220
|
+
packetFiles.add(packet.file);
|
|
221
|
+
publishStagePacket(context, projectId, runId, packet.stage, packet.file);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function normalizeStageReport(report) {
|
|
9
225
|
const semantic = object(report.semantic);
|
|
226
|
+
if (semantic.materialization !== undefined) {
|
|
227
|
+
const value = object(semantic.materialization);
|
|
228
|
+
const authored = object(value.authored_result);
|
|
229
|
+
const relative = (item) => typeof item === "string" && item.length > 0 && !path.isAbsolute(item) && !item.split(/[\\/]/).includes("..");
|
|
230
|
+
if (value.schema_id !== "dd-flow/protocolize-materialization@1" || value.run_id !== report.run_id || report.stage !== "protocolize" || value.stage !== "protocolize"
|
|
231
|
+
|| !["create", "link", "update", "not_applicable"].includes(String(value.action)) || value.status !== "passed"
|
|
232
|
+
|| authored.role !== "authored_input" || !relative(authored.run_relative_path) || !/^[a-f0-9]{64}$/.test(String(authored.sha256))
|
|
233
|
+
|| !(value.feature_path === null || relative(value.feature_path)) || !Array.isArray(value.protocol_ids) || value.protocol_ids.some(id => typeof id !== "string")
|
|
234
|
+
|| !Array.isArray(value.documents) || value.documents.some(item => { const ref = object(item); return !relative(ref.path) || !/^[a-f0-9]{64}$/.test(String(ref.sha256)); })
|
|
235
|
+
|| !Array.isArray(value.owned_links) || value.owned_links.some(item => { const edge = object(item); return !relative(edge.feature_path) || !relative(edge.protocol_path) || !value.protocol_ids.includes(edge.protocol_id); })) {
|
|
236
|
+
throw new AppError("stage_report_materialization_invalid", "PROTOCOLIZE materialization receipt is malformed or out of scope", 1);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
10
239
|
const sourceArtifacts = object(report.artifacts);
|
|
11
|
-
|
|
240
|
+
return {
|
|
12
241
|
...report,
|
|
13
242
|
schema_id: "dd-flow/stage-report@2",
|
|
14
243
|
summary: string(report.summary) || string(semantic.result) || "Stage completed.",
|
|
@@ -27,11 +256,6 @@ export function writeStageReport(root, report) {
|
|
|
27
256
|
html: string(sourceArtifacts.html) || "stage-report.html"
|
|
28
257
|
}
|
|
29
258
|
};
|
|
30
|
-
writeJsonAtomic(json, normalized);
|
|
31
|
-
const text = renderStageReportMarkdown(normalized);
|
|
32
|
-
fs.writeFileSync(markdown, text);
|
|
33
|
-
fs.writeFileSync(html, renderStageReportHtml(normalized, text));
|
|
34
|
-
return { json, markdown, html };
|
|
35
259
|
}
|
|
36
260
|
export function renderStageReportMarkdown(report) {
|
|
37
261
|
const semantic = object(report.semantic);
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AppError } from "../shared/errors.js";
|
|
2
|
+
export function stageAttempt(context, projectId, runId, stage) {
|
|
3
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
4
|
+
if (!run)
|
|
5
|
+
throw new AppError("not_found", "Stage graph RUN is unavailable", 1);
|
|
6
|
+
const stages = JSON.parse(run.index_json).stage_runs ?? [];
|
|
7
|
+
return [...stages].reverse().find(item => item.stage === stage)?.attempt ?? "try-001";
|
|
8
|
+
}
|
|
9
|
+
export function bindStageWork(context, input) {
|
|
10
|
+
context.db.writeTransaction(() => bindStageWorkOwned(context, input), "stage-work.bind");
|
|
11
|
+
}
|
|
12
|
+
function bindStageWorkOwned(context, input) {
|
|
13
|
+
const run = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [input.projectId, input.runId]);
|
|
14
|
+
const index = run ? JSON.parse(run.index_json) : null;
|
|
15
|
+
if (index?.execution_bundle) {
|
|
16
|
+
// Stage attachment already admitted the frozen descriptor outside the writer.
|
|
17
|
+
// Membership checks here consume only authoritative SQLite facts.
|
|
18
|
+
const stage = index.stage_runs.find(item => item.stage === input.stage && item.status === "running");
|
|
19
|
+
const work = context.db.get("SELECT parent_work_id FROM works WHERE project_id = ? AND run_id = ? AND work_id = ?", [input.projectId, input.runId, input.workId]);
|
|
20
|
+
const parentOwned = !work?.parent_work_id || context.db.get("SELECT 1 FROM works WHERE project_id = ? AND run_id = ? AND work_id = ?", [input.projectId, input.runId, work.parent_work_id]);
|
|
21
|
+
const currentStage = index.current_stage ?? (index.execution_bundle.flow_id === "sdlc" ? index.stage_runs.at(-1)?.stage : undefined);
|
|
22
|
+
if (!stage || currentStage !== input.stage || !work || !parentOwned || input.attempt !== undefined && input.attempt !== (stage.attempt ?? "try-001")
|
|
23
|
+
|| input.cycle !== undefined && input.cycle !== stageCycle(context, input.projectId, input.runId, input.stage)) {
|
|
24
|
+
throw new AppError("stage_work_scope_invalid", "Work membership does not belong to the active frozen stage scope", 1, { run_id: input.runId, stage: input.stage, work_id: input.workId });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
context.db.run("INSERT OR IGNORE INTO stage_work_memberships (project_id, run_id, work_id, stage, attempt, cycle) VALUES (?, ?, ?, ?, ?, ?)", [input.projectId, input.runId, input.workId, input.stage, input.attempt ?? stageAttempt(context, input.projectId, input.runId, input.stage), input.cycle ?? stageCycle(context, input.projectId, input.runId, input.stage)]);
|
|
28
|
+
}
|
|
29
|
+
export function stageCycle(context, projectId, runId, stage) {
|
|
30
|
+
if (stage !== "code" && stage !== "code-review")
|
|
31
|
+
return "";
|
|
32
|
+
const row = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
33
|
+
const cycle = row ? JSON.parse(row.index_json).variables?.["merge.source_repair"]?.cycle : undefined;
|
|
34
|
+
return typeof cycle === "string" ? cycle : stage === "code-review" ? "initial" : "";
|
|
35
|
+
}
|
|
36
|
+
export function stageWorkIds(context, projectId, runId, stage) {
|
|
37
|
+
if (!context.db.get("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'stage_work_memberships'"))
|
|
38
|
+
throw new AppError("stage_graph_compatibility_required", "Stage Work membership is unavailable; use the RUN's pinned engine", 1);
|
|
39
|
+
return new Set(context.db.all("SELECT work_id FROM stage_work_memberships WHERE project_id = ? AND run_id = ? AND stage = ? AND attempt = ? AND cycle = ?", [projectId, runId, stage, stageAttempt(context, projectId, runId, stage), stageCycle(context, projectId, runId, stage)]).map(row => row.work_id));
|
|
40
|
+
}
|
|
41
|
+
/** Generic Work APIs also serve non-stage runs; null preserves that contract. */
|
|
42
|
+
export function currentStageWorkIds(context, projectId, runId) {
|
|
43
|
+
const row = context.db.get("SELECT index_json FROM runs WHERE project_id = ? AND id = ?", [projectId, runId]);
|
|
44
|
+
if (!row)
|
|
45
|
+
return null;
|
|
46
|
+
const index = JSON.parse(row.index_json);
|
|
47
|
+
const stage = [...(index.stage_runs ?? [])].reverse().find(item => item.status === "running")?.stage;
|
|
48
|
+
return stage ? stageWorkIds(context, projectId, runId, stage) : null;
|
|
49
|
+
}
|
|
50
|
+
export function stageGraphScope(context, projectId, runId, stage) {
|
|
51
|
+
return { project_id: projectId, run_id: runId, attempt: stageAttempt(context, projectId, runId, stage), cycle: stageCycle(context, projectId, runId, stage) };
|
|
52
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import { appendNoteTimeline } from "./run-timeline.js";
|
|
3
|
+
/** Optional operational evidence never replaces a committed semantic outcome. */
|
|
4
|
+
export function recordTechnicalNote(context, projectId, runId, input) {
|
|
5
|
+
const id = crypto.createHash("sha256").update(JSON.stringify([runId, input.generation, input.stage ?? null,
|
|
6
|
+
input.work_id ?? null, input.phase, input.source_operation_id ?? null, input.code, input.resource_identity ?? null])).digest("hex");
|
|
7
|
+
try {
|
|
8
|
+
const previous = readTechnicalNotes(context, projectId, runId).find(note => note.id === id);
|
|
9
|
+
if (input.state === "resolved" && !previous)
|
|
10
|
+
return;
|
|
11
|
+
const now = context.now(), note = { ...input, id, run_id: runId, state: input.state ?? "open",
|
|
12
|
+
first_seen: previous?.first_seen ?? now, last_seen: now };
|
|
13
|
+
if (previous?.state === note.state && previous.consequence === note.consequence)
|
|
14
|
+
return;
|
|
15
|
+
appendNoteTimeline(context, projectId, runId, { type: note.state === "resolved" ? "technical_note_resolved" : "technical_note_recorded", note });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Do not copy arbitrary provider messages, environment or transcript here.
|
|
19
|
+
process.stderr.write(`${JSON.stringify({ event: "technical_note_persistence_unavailable", run_id: runId, code: input.code, phase: input.phase, note_id: id })}\n`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export function readTechnicalNotes(context, projectId, runId) {
|
|
23
|
+
const rows = context.db.all("SELECT payload_json FROM audit_events WHERE project_id = ? AND event_type = 'flow_run.timeline' AND json_extract(payload_json, '$.run_id') = ? ORDER BY id", [projectId, runId]);
|
|
24
|
+
const notes = new Map();
|
|
25
|
+
for (const row of rows) {
|
|
26
|
+
const event = JSON.parse(row.payload_json).event;
|
|
27
|
+
if (["technical_note_recorded", "technical_note_resolved"].includes(event?.type ?? "") && event.note?.id)
|
|
28
|
+
notes.set(event.note.id, event.note);
|
|
29
|
+
}
|
|
30
|
+
return [...notes.values()];
|
|
31
|
+
}
|
package/dist/services/tooling.js
CHANGED
|
@@ -2,9 +2,11 @@ import crypto from "node:crypto";
|
|
|
2
2
|
import fs from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { commandResult, commandText } from '../harness-runtime/lib/process-json.mjs';
|
|
6
|
+
import { publishSetup, SETUP_STARTUP_MS } from '../harness-runtime/lib/setup-progress.mjs';
|
|
7
|
+
import { AppError, errorRecord, processEvidence } from "../shared/errors.js";
|
|
7
8
|
import { ensureDir } from "../storage/paths.js";
|
|
9
|
+
import { acquireInstallationLock } from "./installation-lock.js";
|
|
8
10
|
const manifestRelativePath = path.join("tools", "worktrunk-manifest.json");
|
|
9
11
|
const managedToolRootName = "wt";
|
|
10
12
|
const manifestSchemaId = "dd-flow/managed-tool-manifest@1";
|
|
@@ -44,7 +46,7 @@ export function worktrunkPlatform() {
|
|
|
44
46
|
});
|
|
45
47
|
}
|
|
46
48
|
export function worktrunkCacheRoot(context, platform = worktrunkPlatform()) {
|
|
47
|
-
return path.join(context.ddFlowHome, "tools", managedToolRootName, worktrunkManifest().version, platform);
|
|
49
|
+
return path.join(path.resolve(context.env.DD_FLOW_RESOURCE_HOME || context.ddFlowHome), "tools", managedToolRootName, worktrunkManifest().version, platform);
|
|
48
50
|
}
|
|
49
51
|
export function worktrunkCacheBinary(context, platform = worktrunkPlatform()) {
|
|
50
52
|
return path.join(worktrunkCacheRoot(context, platform), process.platform === "win32" ? "wt.exe" : "wt");
|
|
@@ -71,14 +73,40 @@ export function inspectManagedWorktrunk(context) {
|
|
|
71
73
|
};
|
|
72
74
|
}
|
|
73
75
|
}
|
|
74
|
-
export function ensureManagedWorktrunk(context) {
|
|
76
|
+
export async function ensureManagedWorktrunk(context) {
|
|
75
77
|
const manifest = worktrunkManifest();
|
|
76
78
|
const platform = worktrunkPlatform();
|
|
77
79
|
const cachedRoot = worktrunkCacheRoot(context, platform);
|
|
78
80
|
if (fs.existsSync(cachedRoot))
|
|
79
81
|
return verifyCachedWorktrunk(context, manifest, platform);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
+
ensureDir(path.dirname(cachedRoot));
|
|
83
|
+
const lockFile = `${cachedRoot}.lock`;
|
|
84
|
+
const identity = crypto.createHash("sha256").update(JSON.stringify([manifest.tool, manifest.version, platform, artifactFor(manifest, platform).sha256])).digest("hex");
|
|
85
|
+
let lock;
|
|
86
|
+
try {
|
|
87
|
+
lock = acquireInstallationLock(lockFile, identity);
|
|
88
|
+
}
|
|
89
|
+
catch (cause) {
|
|
90
|
+
if (fs.existsSync(cachedRoot))
|
|
91
|
+
return verifyCachedWorktrunk(context, manifest, platform);
|
|
92
|
+
if (!(cause instanceof AppError) || cause.code !== "installation_locked")
|
|
93
|
+
throw cause;
|
|
94
|
+
throw new AppError("tool_install_pending", "Pinned Worktrunk installation requires its current owner", 1, { tool: manifest.tool, version: manifest.version, platform, cache_root: cachedRoot, lock_file: lockFile,
|
|
95
|
+
phase: "prepare", effect: "no_effect", recoverable: false, cause: errorRecord(cause) });
|
|
96
|
+
}
|
|
97
|
+
let primary;
|
|
98
|
+
const release = () => {
|
|
99
|
+
try {
|
|
100
|
+
lock.release();
|
|
101
|
+
}
|
|
102
|
+
catch (cause) {
|
|
103
|
+
if (!primary || typeof primary !== "object")
|
|
104
|
+
throw cause;
|
|
105
|
+
Object.assign(primary, { cleanup_error: errorRecord(cause) });
|
|
106
|
+
if (primary instanceof AppError)
|
|
107
|
+
Object.assign(primary.details, { recoverable: false, lock_cleanup_error: errorRecord(cause) });
|
|
108
|
+
}
|
|
109
|
+
};
|
|
82
110
|
try {
|
|
83
111
|
if (fs.existsSync(cachedRoot))
|
|
84
112
|
return verifyCachedWorktrunk(context, manifest, platform);
|
|
@@ -89,35 +117,57 @@ export function ensureManagedWorktrunk(context) {
|
|
|
89
117
|
platform,
|
|
90
118
|
cache_root: cachedRoot,
|
|
91
119
|
artifact_url: artifactFor(manifest, platform).url,
|
|
120
|
+
phase: "prepare", effect: "no_effect", recoverable: true,
|
|
92
121
|
next_action: "Place the verified official artifact in the managed tool cache and retry."
|
|
93
122
|
});
|
|
94
123
|
}
|
|
95
|
-
installWorktrunkArtifact(manifest, platform, cachedRoot);
|
|
124
|
+
await installWorktrunkArtifact(manifest, platform, cachedRoot, lock.assertOwnership);
|
|
96
125
|
return verifyCachedWorktrunk(context, manifest, platform);
|
|
97
126
|
}
|
|
127
|
+
catch (cause) {
|
|
128
|
+
primary = cause;
|
|
129
|
+
throw cause;
|
|
130
|
+
}
|
|
98
131
|
finally {
|
|
99
|
-
|
|
132
|
+
release();
|
|
100
133
|
}
|
|
101
134
|
}
|
|
102
|
-
function installWorktrunkArtifact(manifest, platform, targetRoot) {
|
|
135
|
+
async function installWorktrunkArtifact(manifest, platform, targetRoot, assertOwnership) {
|
|
103
136
|
const artifact = artifactFor(manifest, platform);
|
|
104
137
|
const parent = path.dirname(targetRoot);
|
|
105
138
|
ensureDir(parent);
|
|
106
139
|
const tempRoot = fs.mkdtempSync(path.join(parent, `.wt-${process.pid}-`));
|
|
107
140
|
const archivePath = path.join(tempRoot, `worktrunk.${artifact.archive}`);
|
|
108
141
|
const extractedRoot = path.join(tempRoot, "extracted");
|
|
142
|
+
let acquisitionPhase = "tool-download", cleanupSafe = true;
|
|
109
143
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
144
|
+
let marker = null, progress = 0;
|
|
145
|
+
publishSetup('probe_started', 'worktrunk-download');
|
|
146
|
+
const download = await commandResult("curl", ["--fail", "--location", "--silent", "--show-error", "--retry", "2", "--retry-delay", "1", "--retry-connrefused", "--connect-timeout", "30", "-o", archivePath, artifact.url], { startupMs: SETUP_STARTUP_MS, phase: acquisitionPhase, progress: () => {
|
|
147
|
+
const stat = fs.statSync(archivePath, { bigint: true, throwIfNoEntry: false });
|
|
148
|
+
const next = stat ? `${stat.size}:${stat.mtimeNs}` : null;
|
|
149
|
+
if (next !== marker && stat && stat.size > 0n) {
|
|
150
|
+
progress++;
|
|
151
|
+
publishSetup('transfer_progress', `worktrunk-transfer:${progress}`);
|
|
152
|
+
}
|
|
153
|
+
marker = next;
|
|
154
|
+
return progress;
|
|
155
|
+
} });
|
|
156
|
+
if (download.exit_code !== 0 || download.signal) {
|
|
112
157
|
throw new AppError("tool_unavailable", "Unable to download the pinned Worktrunk artifact", 1, {
|
|
113
158
|
tool: manifest.tool,
|
|
114
159
|
version: manifest.version,
|
|
115
160
|
platform,
|
|
116
161
|
artifact_url: artifact.url,
|
|
162
|
+
cache_root: targetRoot, acquisition_phase: acquisitionPhase,
|
|
163
|
+
phase: "prepare", effect: "no_effect", recoverable: true,
|
|
164
|
+
process: processEvidence(download),
|
|
117
165
|
stdout: sanitize(download.stdout),
|
|
118
166
|
stderr: sanitize(download.stderr)
|
|
119
167
|
});
|
|
120
168
|
}
|
|
169
|
+
acquisitionPhase = "tool-archive-verification";
|
|
170
|
+
publishSetup('probe_completed', 'worktrunk-download');
|
|
121
171
|
const archiveChecksum = sha256File(archivePath);
|
|
122
172
|
if (archiveChecksum !== artifact.sha256) {
|
|
123
173
|
throw new AppError("tool_integrity_failed", "Pinned Worktrunk artifact checksum mismatch", 1, {
|
|
@@ -129,12 +179,14 @@ function installWorktrunkArtifact(manifest, platform, targetRoot) {
|
|
|
129
179
|
});
|
|
130
180
|
}
|
|
131
181
|
ensureDir(extractedRoot);
|
|
132
|
-
|
|
182
|
+
acquisitionPhase = "tool-extraction";
|
|
183
|
+
await extractArchive(archivePath, extractedRoot, artifact.archive);
|
|
133
184
|
const extractedBinary = findBinary(extractedRoot);
|
|
134
185
|
if (!extractedBinary)
|
|
135
186
|
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive does not contain wt", 1, { platform });
|
|
136
187
|
fs.chmodSync(extractedBinary, 0o755);
|
|
137
|
-
|
|
188
|
+
acquisitionPhase = "tool-version";
|
|
189
|
+
await verifyWorktrunkVersion(extractedBinary, manifest.version);
|
|
138
190
|
const binaryChecksum = sha256File(extractedBinary);
|
|
139
191
|
const stagedRoot = path.join(tempRoot, "managed");
|
|
140
192
|
ensureDir(stagedRoot);
|
|
@@ -149,12 +201,36 @@ function installWorktrunkArtifact(manifest, platform, targetRoot) {
|
|
|
149
201
|
archive_sha256: artifact.sha256,
|
|
150
202
|
binary_sha256: binaryChecksum
|
|
151
203
|
}, null, 2)}\n`);
|
|
204
|
+
assertOwnership();
|
|
152
205
|
if (fs.existsSync(targetRoot))
|
|
153
206
|
throw new AppError("tool_integrity_failed", "Managed Worktrunk cache appeared during installation", 1, { cache_root: targetRoot });
|
|
154
207
|
fs.renameSync(stagedRoot, targetRoot);
|
|
155
208
|
}
|
|
209
|
+
catch (cause) {
|
|
210
|
+
const cleanupError = cause?.cleanup_error;
|
|
211
|
+
cleanupSafe = !cleanupError && (cause instanceof AppError || cause?.code === "command_observation_lost");
|
|
212
|
+
if (cause?.code === "command_observation_lost") {
|
|
213
|
+
throw new AppError("tool_unavailable", "Pinned Worktrunk acquisition lost command observation", 1, { tool: manifest.tool, version: manifest.version, platform, artifact_url: artifact.url, cache_root: targetRoot,
|
|
214
|
+
acquisition_phase: acquisitionPhase, phase: "prepare", effect: cleanupError ? "unknown" : "no_effect",
|
|
215
|
+
recoverable: !cleanupError, cause: errorRecord(cause), ...(cleanupError ? { cleanup_error: errorRecord(cleanupError), staging_root: tempRoot } : {}) });
|
|
216
|
+
}
|
|
217
|
+
if (cause instanceof AppError) {
|
|
218
|
+
throw new AppError(cause.code, cause.message, cause.exitCode, {
|
|
219
|
+
tool: manifest.tool, version: manifest.version, platform, artifact_url: artifact.url, cache_root: targetRoot,
|
|
220
|
+
acquisition_phase: acquisitionPhase, phase: "prepare", effect: "no_effect", recoverable: false,
|
|
221
|
+
...cause.details,
|
|
222
|
+
...(cleanupError ? { effect: "unknown", recoverable: false, cleanup_error: errorRecord(cleanupError), staging_root: tempRoot } : {})
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
throw new AppError("tool_unavailable", "Pinned Worktrunk acquisition did not complete", 1, {
|
|
226
|
+
tool: manifest.tool, version: manifest.version, platform, artifact_url: artifact.url, cache_root: targetRoot,
|
|
227
|
+
acquisition_phase: acquisitionPhase, phase: "prepare", effect: "unknown", recoverable: false,
|
|
228
|
+
staging_root: tempRoot, cause: errorRecord(cause), ...(cleanupError ? { cleanup_error: errorRecord(cleanupError) } : {})
|
|
229
|
+
});
|
|
230
|
+
}
|
|
156
231
|
finally {
|
|
157
|
-
|
|
232
|
+
if (cleanupSafe)
|
|
233
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
158
234
|
}
|
|
159
235
|
}
|
|
160
236
|
function verifyCachedWorktrunk(context, manifest, platform) {
|
|
@@ -186,7 +262,7 @@ function verifyCachedWorktrunk(context, manifest, platform) {
|
|
|
186
262
|
actual_binary_sha256: actualBinaryChecksum
|
|
187
263
|
});
|
|
188
264
|
}
|
|
189
|
-
|
|
265
|
+
// The admitted binary checksum binds the version probe performed at install.
|
|
190
266
|
return {
|
|
191
267
|
bin,
|
|
192
268
|
version: manifest.version,
|
|
@@ -195,24 +271,26 @@ function verifyCachedWorktrunk(context, manifest, platform) {
|
|
|
195
271
|
binary_sha256: actualBinaryChecksum
|
|
196
272
|
};
|
|
197
273
|
}
|
|
198
|
-
function extractArchive(archive, destination, format) {
|
|
274
|
+
export async function extractArchive(archive, destination, format) {
|
|
199
275
|
if (format === "tar.xz") {
|
|
200
|
-
const listing =
|
|
201
|
-
if (listing.
|
|
202
|
-
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
276
|
+
const listing = await commandResult("tar", ["-tJf", archive], { startupMs: SETUP_STARTUP_MS, phase: "tool-archive-list" });
|
|
277
|
+
if (listing.exit_code !== 0 || listing.signal)
|
|
278
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive listing failed", 1, { process: processEvidence(listing) });
|
|
279
|
+
if (listing.stdout.split("\n").some(unsafeArchivePath))
|
|
280
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive has an unsafe file list", 1, { phase: "archive_path_validation" });
|
|
281
|
+
const extracted = await commandResult("tar", ["-xJvf", archive, "-C", destination], { startupMs: SETUP_STARTUP_MS, phase: "tool-extraction" });
|
|
282
|
+
if (extracted.exit_code !== 0 || extracted.signal)
|
|
283
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive extraction failed", 1, { process: processEvidence(extracted) });
|
|
207
284
|
return;
|
|
208
285
|
}
|
|
209
|
-
const listing =
|
|
210
|
-
if (listing.
|
|
211
|
-
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
286
|
+
const listing = await commandResult("unzip", ["-Z1", archive], { startupMs: SETUP_STARTUP_MS, phase: "tool-archive-list" });
|
|
287
|
+
if (listing.exit_code !== 0 || listing.signal)
|
|
288
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive listing failed", 1, { process: processEvidence(listing) });
|
|
289
|
+
if (listing.stdout.split("\n").some(unsafeArchivePath))
|
|
290
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive has an unsafe file list", 1, { phase: "archive_path_validation" });
|
|
291
|
+
const extracted = await commandResult("unzip", [archive, "-d", destination], { startupMs: SETUP_STARTUP_MS, phase: "tool-extraction" });
|
|
292
|
+
if (extracted.exit_code !== 0 || extracted.signal)
|
|
293
|
+
throw new AppError("tool_integrity_failed", "Pinned Worktrunk archive extraction failed", 1, { process: processEvidence(extracted) });
|
|
216
294
|
}
|
|
217
295
|
function findBinary(root) {
|
|
218
296
|
const expected = process.platform === "win32" ? "wt.exe" : "wt";
|
|
@@ -229,13 +307,11 @@ function findBinary(root) {
|
|
|
229
307
|
}
|
|
230
308
|
return null;
|
|
231
309
|
}
|
|
232
|
-
function verifyWorktrunkVersion(bin, expected) {
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
if (result.status !== 0 || !output.includes(expected)) {
|
|
310
|
+
async function verifyWorktrunkVersion(bin, expected) {
|
|
311
|
+
const output = await commandText(bin, ['--version'], { startupMs: SETUP_STARTUP_MS, phase: 'tool-version' });
|
|
312
|
+
if (!output.includes(expected)) {
|
|
236
313
|
throw new AppError("tool_integrity_failed", "Managed Worktrunk version verification failed", 1, {
|
|
237
314
|
expected_version: expected,
|
|
238
|
-
status: result.status,
|
|
239
315
|
output: sanitize(output)
|
|
240
316
|
});
|
|
241
317
|
}
|
|
@@ -251,15 +327,6 @@ function validateManifest(value, file) {
|
|
|
251
327
|
throw new AppError("tool_manifest_invalid", `Managed Worktrunk manifest is invalid: ${file}`, 1, { manifest: file });
|
|
252
328
|
}
|
|
253
329
|
}
|
|
254
|
-
function acquireLock(lockDir) {
|
|
255
|
-
ensureDir(path.dirname(lockDir));
|
|
256
|
-
try {
|
|
257
|
-
fs.mkdirSync(lockDir);
|
|
258
|
-
}
|
|
259
|
-
catch {
|
|
260
|
-
throw new AppError("tool_install_locked", "Another Worktrunk installation is in progress", 1, { lock_dir: lockDir });
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
330
|
function sha256File(file) {
|
|
264
331
|
return crypto.createHash("sha256").update(fs.readFileSync(file)).digest("hex");
|
|
265
332
|
}
|