@deksden-com/dd-flow-cli 0.9.0-beta.14 → 0.9.0-beta.141
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 +740 -0
- package/README.md +143 -1
- package/dist/build-info.json +8 -8
- package/dist/cli/argument-values.js +38 -0
- package/dist/cli/command-inputs.js +376 -0
- package/dist/cli/command-metadata.js +197 -0
- package/dist/cli/command-option-descriptions.js +191 -0
- package/dist/cli/completion-cli.js +70 -0
- package/dist/cli/completion.js +57 -0
- package/dist/cli/error-output.js +52 -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 +328 -18
- package/dist/cli/hook-ingress.js +78 -0
- package/dist/cli/input-preparation.js +165 -0
- package/dist/cli/memory-flow-admission.js +44 -0
- package/dist/cli/memory-init-invocation.js +78 -0
- package/dist/cli/memory-init.js +240 -0
- package/dist/cli/memory-storage-admission.js +53 -0
- package/dist/cli/models.js +39 -0
- package/dist/cli/native-hook-ingress.js +80 -0
- package/dist/cli/operator-profiles.js +61 -0
- package/dist/cli/output-options.js +35 -0
- package/dist/cli/response-file.js +71 -0
- package/dist/cli/run-cli.js +1689 -545
- 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 +149 -0
- package/dist/cli.js +71 -2
- package/dist/domain/stage-catalog.js +1 -1
- package/dist/domain/stage-handler-identities.js +20 -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 +56 -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 +40 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +22 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +87 -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-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
- package/dist/harness-runtime/lib/daemon-observation.d.mts +2 -0
- package/dist/harness-runtime/lib/daemon-observation.mjs +163 -0
- package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +371 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +728 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +70 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +196 -0
- package/dist/harness-runtime/lib/dd-codex.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +817 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +140 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +584 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +498 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +177 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +557 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +363 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +751 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +1145 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +14 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +157 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +139 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -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 +10 -0
- package/dist/harness-runtime/lib/lifecycle-contract.mjs +19 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +16 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +683 -0
- package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
- package/dist/harness-runtime/lib/model-observations.mjs +101 -0
- package/dist/harness-runtime/lib/native-children.d.mts +16 -0
- package/dist/harness-runtime/lib/native-children.mjs +113 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +7 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +251 -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 +45 -0
- package/dist/harness-runtime/lib/observation-clock.d.mts +18 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +92 -0
- package/dist/harness-runtime/lib/opencode-plugin.mjs +85 -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 +127 -0
- package/dist/harness-runtime/lib/operation-progress.d.mts +7 -0
- package/dist/harness-runtime/lib/operation-progress.mjs +114 -0
- package/dist/harness-runtime/lib/process-json.d.mts +5 -0
- package/dist/harness-runtime/lib/process-json.mjs +201 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/provider-overload-policy.d.mts +13 -0
- package/dist/harness-runtime/lib/provider-overload-policy.mjs +138 -0
- package/dist/harness-runtime/lib/runner-events.mjs +200 -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 +51 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +21 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +228 -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-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/discovery-result.schema.json +184 -0
- package/dist/schemas/execution-bundle.schema.json +205 -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 +28 -0
- package/dist/schemas/harness-catalog.schema.json +80 -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/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 +49 -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 +3 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/profile-settings.schema.json +122 -0
- package/dist/schemas/release-manifest.schema.json +291 -0
- package/dist/schemas/run-control-receipt.schema.json +118 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/run-engine-binding.schema.json +1 -1
- package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/branch-context.js +3 -3
- package/dist/services/canon.js +11 -8
- package/dist/services/check-runner-evidence.js +250 -0
- package/dist/services/cleanup.js +133 -40
- package/dist/services/cli-operation-classifier.js +25 -62
- package/dist/services/cli-upgrade-allowlist.js +27 -0
- package/dist/services/code-checks.js +1168 -107
- package/dist/services/codex-hook-delivery.js +32 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/compatibility-preflight.js +13 -3
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +20 -0
- package/dist/services/controller-child-capacity.js +13 -0
- package/dist/services/controller-child-observer.js +115 -0
- package/dist/services/controller-execution.js +88 -0
- package/dist/services/controller-fanout.js +202 -0
- package/dist/services/dashboard.js +143 -58
- package/dist/services/descriptor-coordinator-session.js +35 -0
- package/dist/services/descriptor-root-work.js +53 -0
- package/dist/services/descriptor-run-settlement.js +105 -0
- package/dist/services/descriptor-run-start.js +449 -0
- package/dist/services/descriptor-stage-coordinator.js +197 -0
- package/dist/services/descriptor-stage-settlement.js +222 -0
- package/dist/services/descriptor-stage-start.js +139 -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/engines.js +294 -153
- package/dist/services/eval-snapshots.js +1215 -116
- package/dist/services/execution-bundles.js +263 -0
- package/dist/services/execution-policy.js +185 -0
- package/dist/services/executor-onboarding.js +56 -0
- package/dist/services/external-work-launch.js +308 -0
- package/dist/services/flow-catalog.js +21 -0
- package/dist/services/flow-descriptors.js +82 -0
- package/dist/services/frozen-engine.js +250 -0
- package/dist/services/generic-execution.js +164 -0
- package/dist/services/harness-adapter.js +355 -36
- 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/hooks.js +771 -325
- package/dist/services/hybrid-contracts.js +483 -0
- package/dist/services/ids.js +29 -1
- package/dist/services/installation-lock.js +95 -0
- package/dist/services/installed-flow-source.js +183 -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 +2007 -0
- package/dist/services/managed-daemon-binding.js +38 -0
- package/dist/services/managed-lease-monitor.js +133 -0
- package/dist/services/managed-processes.js +475 -55
- package/dist/services/memory-accepted-composition.js +77 -0
- package/dist/services/memory-baseline-preservation.js +65 -0
- package/dist/services/memory-completed-correction-wave.js +320 -0
- package/dist/services/memory-compose-handler.js +258 -0
- package/dist/services/memory-composition-acceptance.js +199 -0
- package/dist/services/memory-composition-graph.js +134 -0
- package/dist/services/memory-composition-registration.js +146 -0
- package/dist/services/memory-composition-work-custody.js +151 -0
- package/dist/services/memory-composition-work-results.js +96 -0
- package/dist/services/memory-corrected-review-acceptance.js +129 -0
- package/dist/services/memory-corrected-review-batch.js +30 -0
- package/dist/services/memory-corrected-review-findings.js +106 -0
- package/dist/services/memory-corrected-review-inputs.js +210 -0
- package/dist/services/memory-corrected-review-projection.js +78 -0
- package/dist/services/memory-corrected-review-receipt.js +170 -0
- package/dist/services/memory-corrected-review-registration.js +191 -0
- package/dist/services/memory-correction-check-receipt.js +219 -0
- package/dist/services/memory-correction-input-owner.js +6 -0
- package/dist/services/memory-discover-handler.js +104 -0
- package/dist/services/memory-finish-evidence.js +435 -0
- package/dist/services/memory-finish-handler.js +215 -0
- package/dist/services/memory-finish-integration.js +280 -0
- package/dist/services/memory-finish-readiness.js +122 -0
- package/dist/services/memory-git-integration.js +151 -0
- package/dist/services/memory-historical-corrected-review.js +206 -0
- package/dist/services/memory-historical-original-review.js +130 -0
- package/dist/services/memory-historical-repair-registration.js +99 -0
- package/dist/services/memory-historical-second-review.js +128 -0
- package/dist/services/memory-init-bootstrap-readiness.js +210 -0
- package/dist/services/memory-init-contexts.js +89 -0
- package/dist/services/memory-init-controller-start.js +84 -0
- package/dist/services/memory-init-engine-release.js +223 -0
- package/dist/services/memory-init-git-policy.js +136 -0
- package/dist/services/memory-init-lint-capability.js +185 -0
- package/dist/services/memory-init-native-capacity.js +296 -0
- package/dist/services/memory-init-preflight.js +330 -0
- package/dist/services/memory-init-project-bootstrap.js +599 -0
- package/dist/services/memory-init-request-candidate.js +157 -0
- package/dist/services/memory-init-request-input.js +66 -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 +98 -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 +81 -0
- package/dist/services/memory-init-stores.js +359 -0
- package/dist/services/memory-init-worktrunk-capability.js +178 -0
- package/dist/services/memory-layer-publication.js +611 -0
- package/dist/services/memory-layer.js +156 -0
- package/dist/services/memory-lint-config.js +85 -0
- package/dist/services/memory-native-review-copy.js +165 -0
- package/dist/services/memory-normal-flow-entry.js +75 -0
- package/dist/services/memory-ordinary-defaults.js +112 -0
- package/dist/services/memory-preflight-bootstrap-custody.js +115 -0
- package/dist/services/memory-preflight-handler.js +259 -0
- package/dist/services/memory-repair-current-view.js +299 -0
- package/dist/services/memory-repair-document-delta.js +451 -0
- package/dist/services/memory-repair-history.js +491 -0
- package/dist/services/memory-repair-physical-binding.js +312 -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 +160 -0
- package/dist/services/memory-repair-publication-source.js +225 -0
- package/dist/services/memory-repair-publication.js +794 -0
- package/dist/services/memory-repair-registration.js +239 -0
- package/dist/services/memory-repair-work-baseline.js +413 -0
- package/dist/services/memory-repair-work-completion.js +97 -0
- package/dist/services/memory-repair-work-custody.js +73 -0
- package/dist/services/memory-repair-work-results.js +89 -0
- package/dist/services/memory-repair-workspace.js +252 -0
- package/dist/services/memory-repair-writer-copy.js +735 -0
- package/dist/services/memory-result-binding.js +173 -0
- package/dist/services/memory-retained-review-authority.js +129 -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 +156 -0
- package/dist/services/memory-review-acceptance.js +214 -0
- package/dist/services/memory-review-correction-plan.js +171 -0
- package/dist/services/memory-review-handler.js +585 -0
- package/dist/services/memory-review-inputs.js +200 -0
- package/dist/services/memory-review-receipt.js +180 -0
- package/dist/services/memory-review-registration.js +108 -0
- package/dist/services/memory-review-work-custody.js +124 -0
- package/dist/services/memory-review-work-input.js +72 -0
- package/dist/services/memory-review-work-results.js +73 -0
- package/dist/services/memory-second-corrected-review-inputs.js +165 -0
- package/dist/services/memory-second-correction-plan.js +76 -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 +28 -0
- package/dist/services/memory-stage-results.js +199 -0
- package/dist/services/memory-verification-acceptance.js +135 -0
- package/dist/services/memory-verification-checks.js +252 -0
- package/dist/services/memory-verification-receipt.js +159 -0
- package/dist/services/memory-verify-handler.js +135 -0
- package/dist/services/memory-work-result-preparation.js +63 -0
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +161 -35
- package/dist/services/migrations.js +37 -16
- package/dist/services/model-catalog.js +109 -0
- package/dist/services/model-discovery.js +46 -0
- package/dist/services/native-daemon-history.js +49 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/operator-profiles.js +236 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/projects.js +37 -17
- package/dist/services/prompts.js +28 -17
- package/dist/services/protocols.js +163 -87
- package/dist/services/provider-capacity.js +385 -0
- package/dist/services/recovery-observation-budget.js +121 -0
- package/dist/services/recovery-snapshot-database.js +560 -0
- package/dist/services/release-archive-producer.js +52 -0
- package/dist/services/release-archive.js +143 -0
- package/dist/services/release-cache.js +142 -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 +42 -0
- package/dist/services/review-copy.js +165 -0
- package/dist/services/review-deferral.js +23 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +411 -0
- package/dist/services/run-control.js +1056 -0
- package/dist/services/run-controller-adapter.js +399 -0
- package/dist/services/run-controller-capture.js +186 -0
- package/dist/services/run-controller-process.js +208 -0
- package/dist/services/run-controller-recovery.js +289 -0
- package/dist/services/run-controller-state.js +97 -0
- package/dist/services/run-controller.js +1205 -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 +77 -0
- package/dist/services/run-recovery-runtime.js +112 -0
- package/dist/services/run-recovery.js +489 -0
- package/dist/services/run-start-custody.js +177 -0
- package/dist/services/runs.js +1019 -247
- package/dist/services/runtime-budget.js +430 -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 +599 -0
- package/dist/services/runtime-scope-stop.js +210 -0
- package/dist/services/runtime-scope-worker.js +287 -0
- package/dist/services/runtime-service.js +96 -0
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +27 -0
- package/dist/services/sessions.js +35 -69
- package/dist/services/setup.js +377 -0
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +193 -19
- package/dist/services/stage-handlers.js +74 -0
- package/dist/services/stage-lifecycle.js +152 -116
- package/dist/services/stage-pause.js +89 -75
- package/dist/services/stage-report-renderer.js +234 -6
- package/dist/services/stage-work-graph.js +52 -0
- package/dist/services/tooling.js +41 -30
- package/dist/services/usage.js +49 -101
- package/dist/services/verification-matrix.js +375 -0
- package/dist/services/vnext-code-review.js +223 -88
- package/dist/services/vnext-code.js +327 -226
- package/dist/services/vnext-contracts.js +10 -1
- package/dist/services/vnext-execution-profile.js +80 -5
- package/dist/services/vnext-fanout.js +311 -19
- package/dist/services/vnext-merge.js +332 -111
- package/dist/services/vnext-plan-review.js +279 -127
- package/dist/services/vnext-plan.js +228 -104
- package/dist/services/vnext-protocolize.js +531 -95
- package/dist/services/vnext-specify.js +119 -81
- package/dist/services/vnext-workspace-policy.js +7 -2
- package/dist/services/work-registry.js +1627 -199
- package/dist/services/workspace-bootstrap.js +52 -15
- package/dist/services/workspace-files.js +85 -0
- package/dist/services/worktrees.js +105 -48
- package/dist/shared/entity-references.js +8 -0
- package/dist/shared/errors.js +27 -0
- package/dist/storage/agent-output.js +26 -0
- package/dist/storage/database.js +891 -39
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +102 -0
- package/dist/storage/native-cleanup.js +52 -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 +89 -0
- package/dist/storage/writer-migration.js +85 -0
- package/package.json +43 -13
- package/tools/create-canon-release.mjs +33 -0
- package/tools/produce-hybrid-release.mjs +41 -0
- package/tools/repair-paused-run-status.mjs +84 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
OpenCode 2.0.28 Promise client/plugin assets are copied unmodified by the build.
|
|
2
|
+
Source: https://github.com/anomalyco/opencode/tree/v2.0.28
|
|
3
|
+
|
|
4
|
+
MIT License
|
|
5
|
+
|
|
6
|
+
Copyright (c) 2025 opencode
|
|
7
|
+
|
|
8
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
in the Software without restriction, including without limitation the rights
|
|
11
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
furnished to do so, subject to the following conditions:
|
|
14
|
+
|
|
15
|
+
The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
copies or substantial portions of the Software.
|
|
17
|
+
|
|
18
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
SOFTWARE.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import { writeJsonAtomic } from "../lib/runner-events.mjs";
|
|
8
|
+
import { hookBudget, invokeNativeHook, readNativeHookInput } from "../lib/native-hook-command.mjs";
|
|
9
|
+
import { doctor } from "../lib/dd-agy.mjs";
|
|
10
|
+
import { callDaemon, qualifyAgyHooks, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-agy-daemon.mjs";
|
|
11
|
+
|
|
12
|
+
function parse(argv) { const positional = [], options = {}; for (let i = 0; i < argv.length; i += 1) { const token = argv[i]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json","cancel-tree","tree","no-flow"].includes(key)) options[key] = true; else { if (argv[i + 1] === undefined) throw new Error(`--${key} requires a value`); options[key] = argv[++i]; } } return { positional, options }; }
|
|
13
|
+
const prompt = async options => options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt;
|
|
14
|
+
async function hook(options) {
|
|
15
|
+
const budget = hookBudget(), requestId = randomUUID();
|
|
16
|
+
const payload = JSON.parse(await readNativeHookInput(process.stdin, budget) || "{}"), event = options.event;
|
|
17
|
+
try {
|
|
18
|
+
const observationMs = budget.remaining("observation");
|
|
19
|
+
const identity = await callDaemon(options["state-dir"], "hook.observe", { event, payload, daemonId: options["daemon-id"], deadlineAt: budget.deadlineAt }, observationMs, requestId);
|
|
20
|
+
if (identity.stale) return event === "PreToolUse" ? { decision: "deny", reason: "agy_stale_hook" } : {};
|
|
21
|
+
if (event === "PreToolUse" || event === "PostToolUse") {
|
|
22
|
+
const phase = event === "PreToolUse" ? "before" : "after", args = payload.toolCall?.args ?? {};
|
|
23
|
+
const normalized = { schema_id: "dd-flow/agy-tool-event@1", event_id: identity.event_id, phase, daemon_id: identity.daemon_id, launch_cwd: identity.launch_cwd, conversation_id: payload.conversationId, parent_conversation_id: identity.parent_conversation_id, execution_num: payload.executionNum, step_index: payload.stepIdx, tool: payload.toolCall?.name, input: args, workspace_paths: payload.workspacePaths, transcript_path: payload.transcriptPath, model: payload.modelName, profile: identity.profile, ...(phase === "after" ? { error: payload.error ?? "" } : {}) };
|
|
24
|
+
await invokeNativeHook({ bin: options["dd-flow-bin"] ?? identity.dd_flow_bin,
|
|
25
|
+
args: ["agy", "event", "handle", "--project-root", options["project-root"] ?? identity.project_root, "--json"],
|
|
26
|
+
payload: normalized, home: options["dd-flow-home"] ?? identity.dd_flow_home, timeoutMs: budget.remaining("admission", 15_000) });
|
|
27
|
+
}
|
|
28
|
+
return event === "PreToolUse" ? { decision: "allow" } : {};
|
|
29
|
+
} catch (error) {
|
|
30
|
+
// A failed socket cannot be used to report its own failure. The daemon
|
|
31
|
+
// reads only receipts matching request IDs it actually accepted this turn.
|
|
32
|
+
const correctable = event === "PreToolUse" && error.code === "lifecycle_shell_syntax_invalid" && error.details?.effect === "no_effect"
|
|
33
|
+
&& error.details?.recoverable === true && error.details?.disposition === "pre_cli_shell_refusal";
|
|
34
|
+
try { await writeJsonAtomic(path.join(options["state-dir"], "hook-failures", `${requestId}.json`), { request_id: requestId, observed_at: new Date().toISOString(), code: error.code ?? "agy_hook_rejected", message: error.message,
|
|
35
|
+
details: { ...error.details, effect: correctable ? "no_effect" : "unknown", ...(correctable ? { native_pre_cli_refusal: true } : {}) } }); }
|
|
36
|
+
catch (storage) { process.stderr.write(`${JSON.stringify({ code: error.code, receipt_error: storage.message })}\n`); }
|
|
37
|
+
throw error;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const { positional, options } = parse(process.argv.slice(2)), [family, command, modifier] = positional; const common = { journal: options.journal, stateDir: options["state-dir"], cwd: options.cwd, bin: options["agy-bin"], provider: options.provider, model: options.model, reasoning: options.reasoning, mode: options.mode, projectRoot: options["project-root"], ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], noFlow: options["no-flow"] === true, ...adapterTimeoutOptions(options, family === "session" ? command : null) }; let result;
|
|
43
|
+
if (family === "doctor") result = await doctor(common);
|
|
44
|
+
else if (family === "hooks" && ["install", "check"].includes(command)) result = await qualifyAgyHooks(common.projectRoot, { stateDir: common.stateDir, install: command === "install" });
|
|
45
|
+
else if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...common, sessionId: options["session-id"], entryPath: process.argv[1] }, startDaemon);
|
|
46
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(common.stateDir); process.exit(0); }
|
|
47
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(common.stateDir, "daemon.status");
|
|
48
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(common.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
49
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(common.stateDir, options["operation-id"]);
|
|
50
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(common.stateDir, options["operation-id"]);
|
|
51
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: common.stateDir, cancelTree: options["cancel-tree"], timeoutMs: common.timeoutMs });
|
|
52
|
+
else if (family === "hook" && command === "handle") { process.stdout.write(`${JSON.stringify(await hook(options))}\n`); process.exit(0); }
|
|
53
|
+
else if (family === "session") { if (command === "fork") throw Object.assign(new Error("Antigravity native headless fork is unsupported; use deterministic_replay"), { code: "agy_headless_fork_unsupported" }); const operation = command === "status" ? "inspect" : command; result = await callDaemon(common.stateDir, `session.${operation}`, { sessionId: options["session-id"], livenessTimeoutMs: common.livenessTimeoutMs, ...(command === "create" || command === "prompt" ? { prompt: await prompt(options) } : {}), tree: options.tree === true }, common.timeoutMs ?? 1_800_000); }
|
|
54
|
+
else throw new Error("usage: dd-agy doctor | hooks install|check | daemon start|status|stop | session create|prompt|inspect|resume|cancel|fork [options] --json");
|
|
55
|
+
process.stdout.write(`${JSON.stringify({ ok: true, ...result })}\n`);
|
|
56
|
+
} catch (error) { if (process.argv.includes("hook") && process.argv.includes("handle")) { process.stdout.write(`${JSON.stringify({ decision: "deny", reason: `${error.code ?? "agy_hook_rejected"}: ${error.message ?? "Native hook refused this tool call"}` })}\n`); process.exit(0); } process.stderr.write(`${JSON.stringify({ ok: false, error: error.message, ...(error.code ? { code: error.code, retryable: error.retryable === true, details: error.details } : {}) })}\n`); process.exit(1); }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { cancelSession, createSession, doctor, inspectSession, promptFromFile, promptSession, startSession } from "../lib/dd-codex.mjs";
|
|
5
|
+
import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-codex-daemon.mjs";
|
|
6
|
+
import { errorRecord } from "../lib/operation-errors.mjs";
|
|
7
|
+
|
|
8
|
+
function parse(argv) { const positional = []; const options = {}; for (let i = 0; i < argv.length; i += 1) { const token = argv[i]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json", "cancel-tree", "no-flow"].includes(key)) { options[key] = true; continue; } const value = argv[++i]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value; } return { positional, options }; }
|
|
9
|
+
function common(options, operation) { return { bin: options["codex-bin"], journal: options.journal, stateDir: options["state-dir"], cwd: options.cwd, sessionId: options["session-id"], turnId: options["turn-id"], model: options.model, reasoning: options.reasoning, ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], noFlow: options["no-flow"] === true, ...adapterTimeoutOptions(options, operation) }; }
|
|
10
|
+
try {
|
|
11
|
+
const { positional, options } = parse(process.argv.slice(2)); const [family, command, modifier] = positional; const shared = common(options, family === "session" ? command : null); let result;
|
|
12
|
+
if (family === "doctor") result = await doctor(shared);
|
|
13
|
+
else if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...shared, entryPath: process.argv[1] }, startDaemon);
|
|
14
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(shared.stateDir); process.exit(0); }
|
|
15
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(shared.stateDir, "daemon.status");
|
|
16
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(shared.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
17
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
18
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
19
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ ...shared, cancelTree: options["cancel-tree"] });
|
|
20
|
+
else if (family === "session" && command === "create") result = shared.stateDir ? await callDaemon(shared.stateDir, "session.create", shared) : await createSession(shared);
|
|
21
|
+
else if (family === "session" && command === "prompt") result = shared.stateDir ? await callDaemon(shared.stateDir, "session.prompt", { ...shared, prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt }, shared.timeoutMs ?? 1_800_000) : await promptSession({ ...shared, prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt });
|
|
22
|
+
else if (family === "session" && command === "start") result = shared.stateDir ? await callDaemon(shared.stateDir, "session.start", { ...shared, prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt }, shared.timeoutMs ?? 30_000) : await startSession({ ...shared, prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt });
|
|
23
|
+
else if (family === "session" && ["inspect", "status", "resume"].includes(command)) result = shared.stateDir ? await callDaemon(shared.stateDir, command === "resume" ? "session.resume" : "session.inspect", shared) : await inspectSession(shared);
|
|
24
|
+
else if (family === "session" && command === "cancel") result = shared.stateDir ? await callDaemon(shared.stateDir, "session.cancel", shared) : await cancelSession(shared);
|
|
25
|
+
else throw new Error("usage: dd-codex doctor | daemon start|status|stop | session create|start|prompt|inspect|status|resume|cancel [--json]");
|
|
26
|
+
process.stdout.write(`${JSON.stringify({ ok: true, ...result })}\n`);
|
|
27
|
+
} catch (error) { const failure = errorRecord(error); process.stderr.write(`${JSON.stringify({ ok: false, error: failure.message, code: failure.code, ...(failure.details ? { details: failure.details } : {}), ...(failure.cause ? { cause: failure.cause } : {}) })}\n`); process.exit(1); }
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { mkdtemp, readFile, rm } from "node:fs/promises";
|
|
5
|
+
import { randomUUID } from "node:crypto";
|
|
6
|
+
import os from "node:os";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { DROID_CONTRACT, DROID_PROTOCOL, DroidRuntime, droidVersion } from "../lib/dd-droid.mjs";
|
|
9
|
+
import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-droid-daemon.mjs";
|
|
10
|
+
import { errorRecord } from "../lib/operation-errors.mjs";
|
|
11
|
+
import { hookBudget, readNativeHookInput } from "../lib/native-hook-command.mjs";
|
|
12
|
+
|
|
13
|
+
function parse(argv) { const positional = [], options = {}; for (let i = 0; i < argv.length; i++) { const word = argv[i]; if (!word.startsWith("--")) { positional.push(word); continue; } const key = word.slice(2); if (["json", "cancel-tree", "tree", "no-flow"].includes(key)) options[key] = true; else { if (argv[i + 1] === undefined) throw new Error(`${word} requires a value`); options[key] = argv[++i]; } } return { positional, options }; }
|
|
14
|
+
try {
|
|
15
|
+
const { positional: [family, command, modifier], options } = parse(process.argv.slice(2));
|
|
16
|
+
const config = { stateDir: options["state-dir"], sessionId: options["session-id"], cwd: options.cwd, projectRoot: options["project-root"], bin: options["droid-bin"] ?? "droid", entryPath: process.argv[1], journal: options.journal, authHome: options["auth-home"], model: options.model, provider: options.provider, reasoning: options.reasoning, mode: options.mode, ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], noFlow: options["no-flow"] === true, ...adapterTimeoutOptions(options, family === "session" ? command : null, "droid-cli") };
|
|
17
|
+
let result;
|
|
18
|
+
if (family === "doctor") {
|
|
19
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), "dd-droid-doctor-"));
|
|
20
|
+
const runtime = new DroidRuntime({ ...config, stateDir: dir, home: path.join(dir, "home"), cwd: config.cwd ?? process.cwd(), journal: path.join(dir, "events.jsonl"), daemonId: randomUUID(), ddFlowHome: null, ddFlowBin: null }, {}, async () => {});
|
|
21
|
+
try { await runtime.start(); result = { harness: "droid-cli", observed_runtime: { droid: await droidVersion(config.bin), factory_protocol: runtime.protocol, dd_harness_contract: DROID_CONTRACT }, models: runtime.models.map(model => model.id ?? model.modelId), capabilities: { native_children: true, tree_cancel: true, selective_child_cancel: false, native_fork: false }, protocol_expected: DROID_PROTOCOL }; }
|
|
22
|
+
finally { await runtime.closeTree(true); await rm(dir, { recursive: true, force: true }); }
|
|
23
|
+
} else if (family === "daemon" && command === "start") result = await durableDaemonStart(config, startDaemon);
|
|
24
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(config.stateDir); process.exit(0); }
|
|
25
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(config.stateDir, "daemon.status");
|
|
26
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(config.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
27
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(config.stateDir, options["operation-id"]);
|
|
28
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(config.stateDir, options["operation-id"]);
|
|
29
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: config.stateDir, cancelTree: options["cancel-tree"] });
|
|
30
|
+
else if (family === "hook" && command === "handle") { const budget = hookBudget(); const payload = JSON.parse(await readNativeHookInput(process.stdin, budget)); const eventId = randomUUID(); result = await callDaemon(config.stateDir, "hook.observe", { payload, eventId, deadlineAt: budget.deadlineAt }, budget.remaining("observation"), eventId); }
|
|
31
|
+
else if (family === "session") { if (command === "fork") throw new Error("Droid fork is not qualified for this adapter"); const prompt = options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt; result = await callDaemon(config.stateDir, `session.${command === "status" ? "inspect" : command}`, { sessionId: options["session-id"], livenessTimeoutMs: config.livenessTimeoutMs, ...(config.noFlow ? { noFlow: true } : {}), ...(prompt ? { prompt } : {}) }); }
|
|
32
|
+
else throw new Error("usage: dd-droid doctor | daemon start|status|operation|stop | session create|resume|prompt|inspect|cancel");
|
|
33
|
+
process.stdout.write(`${JSON.stringify(family === "hook" ? { ...(result.hookSpecificOutput ? { hookSpecificOutput: result.hookSpecificOutput } : {}), ...(typeof result.continue === "boolean" ? { continue: result.continue } : {}), ...(result.stopReason ? { stopReason: result.stopReason } : {}) } : { ok: true, ...result })}\n`);
|
|
34
|
+
} catch (error) { process.stderr.write(`${JSON.stringify({ ok: false, error: errorRecord(error) })}\n`); process.exitCode = process.argv[2] === "hook" ? 2 : 1; }
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { hookBudget, invokeNativeHook, readNativeHookInput, writeNativeHookFailure } from "../lib/native-hook-command.mjs";
|
|
5
|
+
import { cancelSession, createSession, doctor, forkSession, inspectSession, promptFromFile, promptSession } from "../lib/dd-grok.mjs";
|
|
6
|
+
import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-grok-daemon.mjs";
|
|
7
|
+
import { errorRecord } from "../lib/operation-errors.mjs";
|
|
8
|
+
|
|
9
|
+
function parse(argv) { const positional = []; const options = {}; for (let index = 0; index < argv.length; index += 1) { const token = argv[index]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json", "cancel-tree", "no-flow"].includes(key)) { options[key] = true; continue; } const value = argv[++index]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value; } return { positional, options }; }
|
|
10
|
+
function common(options, operation) { return { bin: options["grok-bin"], journal: options.journal, stateDir: options["state-dir"], cwd: options.cwd, sessionId: options["session-id"], model: options.model, reasoning: options.reasoning, mode: options.mode ?? "bypassPermissions", authPath: options["auth-path"], authMethodId: options["auth-method-id"], ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], sessionArchive: options["session-archive"], noFlow: options["no-flow"] === true, ...adapterTimeoutOptions(options, operation) }; }
|
|
11
|
+
async function hook(options) {
|
|
12
|
+
const budget = hookBudget();
|
|
13
|
+
const stdin = await readNativeHookInput(process.stdin, budget); const payload = JSON.parse(stdin || "{}"); const identity = await callDaemon(options["state-dir"], "hook.resolve", { sessionId: payload.sessionId ?? payload.session_id, payload }, budget.remaining("identity"));
|
|
14
|
+
const enriched = { ...payload, _meta: { ...(payload._meta ?? {}), ddGrok: identity } }; const args = ["grok", "event", "handle", "--project-root", options["project-root"], "--json"]; const command = options["dd-flow-bin"];
|
|
15
|
+
try { return await invokeNativeHook({ bin: command, args, home: options["dd-flow-home"], payload: enriched, timeoutMs: budget.remaining("admission", 15_000) }); }
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (identity.nativeHookBinding) error.details = { ...error.details, native_hook_binding: identity.nativeHookBinding };
|
|
18
|
+
try {
|
|
19
|
+
await writeNativeHookFailure(options["state-dir"], identity.nativeHookBinding, error, hookBudget(1_000, null));
|
|
20
|
+
if (identity.nativeHookBinding) await callDaemon(options["state-dir"], "hook.failed", { requestId: identity.nativeHookBinding.request_id }, 1_000);
|
|
21
|
+
} catch (storage) { process.stderr.write(`${JSON.stringify({ code: error.code, receipt_error: storage.message })}\n`); }
|
|
22
|
+
throw error;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const { positional, options } = parse(process.argv.slice(2)); const [family, command, modifier] = positional; const shared = common(options, family === "session" ? command : null); let result;
|
|
28
|
+
if (family === "doctor") result = await doctor(shared);
|
|
29
|
+
else if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...shared, entryPath: process.argv[1] }, startDaemon);
|
|
30
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(shared.stateDir); process.exit(0); }
|
|
31
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(shared.stateDir, "daemon.status");
|
|
32
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(shared.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
33
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
34
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
35
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: shared.stateDir, cancelTree: options["cancel-tree"], timeoutMs: shared.timeoutMs });
|
|
36
|
+
else if (family === "hook" && command === "handle") { process.stdout.write(`${JSON.stringify(await hook(options))}\n`); process.exit(0); }
|
|
37
|
+
else if (family === "session") { const params = { ...shared, ...(command === "create" || command === "prompt" ? { prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt } : {}), ...(command === "fork" ? { target: JSON.parse(options["target-json"] ?? "null") } : {}), ...(command === "archive" ? { archiveDir: options["archive-dir"] } : {}) }; if (shared.stateDir) result = await callDaemon(shared.stateDir, `session.${command === "status" ? "inspect" : command}`, params, shared.timeoutMs ?? 1_800_000); else if (command === "create") result = await createSession(params); else if (command === "prompt") result = await promptSession(params); else if (["inspect", "status", "resume"].includes(command)) result = await inspectSession(params); else if (command === "cancel") result = await cancelSession(params); else if (command === "fork") result = await forkSession(params); else throw new Error(`unknown session command: ${command}`); }
|
|
38
|
+
else throw new Error("usage: dd-grok doctor | daemon start|status|stop | session create|prompt|inspect|status|resume|cancel|fork|archive [options] --json");
|
|
39
|
+
process.stdout.write(`${JSON.stringify({ ok: true, ...result })}\n`);
|
|
40
|
+
} catch (error) { if (process.argv[2] === "hook") { process.stderr.write(`${JSON.stringify({ native_hook_failure: errorRecord(error), bound: Boolean(error.details?.native_hook_binding) })}\n`); process.stdout.write(`${JSON.stringify({ decision: "deny", reason: error.message })}\n`); process.exit(2); } const failure = errorRecord(error); process.stderr.write(`${JSON.stringify({ ok: false, error: failure.message, ...failure })}\n`); process.exit(1); }
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { readFile } from "node:fs/promises";
|
|
5
|
+
import { callDaemon, doctor, openCodeProfileOptions, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-opencode-daemon.mjs";
|
|
6
|
+
|
|
7
|
+
function parse(argv) { const positional = [], options = {}; for (let i = 0; i < argv.length; i += 1) { const token = argv[i]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json","cancel-tree","no-flow"].includes(key)) options[key] = true; else { if (argv[i + 1] === undefined) throw new Error(`--${key} requires a value`); options[key] = argv[++i]; } } return { positional, options }; }
|
|
8
|
+
const prompt = async options => options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt;
|
|
9
|
+
try {
|
|
10
|
+
const { positional, options } = parse(process.argv.slice(2)), [family, command, modifier] = positional; const common = { journal: options.journal, stateDir: options["state-dir"], sessionId: options["session-id"], cwd: options.cwd, bin: options["opencode-bin"], provider: options.provider, model: options.model, ...openCodeProfileOptions(options), authPath: options["auth-path"], configPath: options["config-path"], projectRoot: options["project-root"], ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], noFlow: options["no-flow"] === true, sessionArchive: options["session-archive"], ...adapterTimeoutOptions(options, family === "session" ? command : null) }; let result;
|
|
11
|
+
if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...common, entryPath: process.argv[1] }, startDaemon);
|
|
12
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(common.stateDir); process.exit(0); }
|
|
13
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(common.stateDir, "daemon.status");
|
|
14
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(common.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
15
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(common.stateDir, options["operation-id"]);
|
|
16
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(common.stateDir, options["operation-id"]);
|
|
17
|
+
else if (family === "doctor") result = await doctor(common);
|
|
18
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: common.stateDir, cancelTree: options["cancel-tree"], timeoutMs: common.timeoutMs });
|
|
19
|
+
else if (family === "session") { const operation = command === "status" ? "inspect" : command; const params = { livenessTimeoutMs: common.livenessTimeoutMs, sessionId: options["session-id"], title: options.title, messageId: options["message-id"], archiveFile: options["archive-file"], ...(command === "prompt" ? { prompt: await prompt(options) } : {}) }; result = await callDaemon(common.stateDir, `session.${operation}`, params, common.timeoutMs ?? 1_800_000); }
|
|
20
|
+
else throw new Error("usage: dd-opencode daemon start|status|stop | session create|prompt|inspect|fork|cancel|archive [options] --json");
|
|
21
|
+
process.stdout.write(`${JSON.stringify({ ok: true, ...result })}\n`);
|
|
22
|
+
} catch (error) { process.stderr.write(`${JSON.stringify({ ok: false, error: error.message, ...(error.code ? { code: error.code, retryable: error.retryable === true, details: error.details } : {}) })}\n`); process.exit(1); }
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { adapterTimeoutOptions } from "../lib/adapter-timeouts.mjs";
|
|
3
|
+
import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, settleDaemonOperation } from "../lib/daemon-operations.mjs";
|
|
4
|
+
import { hookBudget, invokeNativeHook, readNativeHookInput, writeNativeHookFailure } from "../lib/native-hook-command.mjs";
|
|
5
|
+
import { cancelChild, cancelSession, createSession, doctor, forkSession, inspectSession, promptFromFile, promptSession } from "../lib/dd-zcode.mjs";
|
|
6
|
+
import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-zcode-daemon.mjs";
|
|
7
|
+
import { errorRecord } from "../lib/operation-errors.mjs";
|
|
8
|
+
|
|
9
|
+
function parse(argv) {
|
|
10
|
+
const positional = []; const options = {};
|
|
11
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
12
|
+
const token = argv[index];
|
|
13
|
+
if (!token.startsWith("--")) { positional.push(token); continue; }
|
|
14
|
+
const key = token.slice(2); if (["json", "cancel-tree", "no-flow"].includes(key)) { options[key] = true; continue; }
|
|
15
|
+
const value = argv[++index]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value;
|
|
16
|
+
}
|
|
17
|
+
return { positional, options };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function common(options, operation) {
|
|
21
|
+
return {
|
|
22
|
+
bin: options["zcode-acp-bin"], zcodePath: options["zcode-path"], journal: options.journal,
|
|
23
|
+
stateDir: options["state-dir"],
|
|
24
|
+
cwd: options.cwd, sessionId: options["session-id"], adapterSessionId: options["adapter-session-id"], provider: options.provider,
|
|
25
|
+
childSessionId: options["child-session-id"],
|
|
26
|
+
model: options.model, reasoning: options.reasoning, mode: options.mode,
|
|
27
|
+
permission: options.permission ?? "deny", ddFlowBin: options["dd-flow-bin"],
|
|
28
|
+
ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], noFlow: options["no-flow"] === true,
|
|
29
|
+
env: options["dd-flow-home"] ? { DD_FLOW_HOME: options["dd-flow-home"] } : undefined,
|
|
30
|
+
...adapterTimeoutOptions(options, operation),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function hook(options) {
|
|
35
|
+
const budget = hookBudget();
|
|
36
|
+
const payload = JSON.parse((await readNativeHookInput(process.stdin, budget)) || "{}");
|
|
37
|
+
const identity = await callDaemon(options["state-dir"], "hook.resolve", { sessionId: payload.session_id ?? payload.sessionId, payload }, budget.remaining("identity"));
|
|
38
|
+
const command = options["dd-flow-bin"]; const args = ["zcode", "hook", "handle", "--project-root", options["project-root"], "--json"];
|
|
39
|
+
|
|
40
|
+
try { return await invokeNativeHook({ bin: command, args, home: options["dd-flow-home"], timeoutMs: budget.remaining("admission", 15_000), payload: { ...payload, _meta: { ...(payload._meta ?? {}), ddZcode: identity } } }); }
|
|
41
|
+
catch (error) {
|
|
42
|
+
if (identity.nativeHookBinding) error.details = { ...error.details, native_hook_binding: identity.nativeHookBinding };
|
|
43
|
+
try {
|
|
44
|
+
// The 25s work budget leaves this bounded 2s evidence tail inside the
|
|
45
|
+
// qualified 30s native hook limit, even after the work deadline expired.
|
|
46
|
+
await writeNativeHookFailure(options["state-dir"], identity.nativeHookBinding, error, hookBudget(1_000, null));
|
|
47
|
+
if (identity.nativeHookBinding) await callDaemon(options["state-dir"], "hook.failed", { requestId: identity.nativeHookBinding.request_id }, 1_000);
|
|
48
|
+
} catch (storage) { process.stderr.write(`${JSON.stringify({ code: error.code, receipt_error: storage.message })}\n`); }
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
const { positional, options } = parse(process.argv.slice(2)); const [family, command, modifier] = positional; let result;
|
|
55
|
+
const answers = options["answers-file"] ? JSON.parse(await promptFromFile(options["answers-file"])) : undefined;
|
|
56
|
+
const shared = common(options, family === "session" ? command : null);
|
|
57
|
+
if (family === "doctor") result = await doctor(shared);
|
|
58
|
+
else if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...shared, entryPath: process.argv[1] }, startDaemon);
|
|
59
|
+
else if (family === "daemon" && command === "serve") { await serveDaemon(shared.stateDir); process.exit(0); }
|
|
60
|
+
else if (family === "daemon" && command === "status") result = await callDaemon(shared.stateDir, "daemon.status");
|
|
61
|
+
else if (family === "daemon" && command === "operation" && modifier === "interrupt") result = await interruptDaemonOperation(shared.stateDir, options["operation-id"], { control_id: options["control-id"], stop_operation_id: options["stop-operation-id"], daemon_id: options["daemon-id"], session_id: options["session-id"], evidence: options.evidence ? JSON.parse(options.evidence) : null });
|
|
62
|
+
else if (family === "daemon" && command === "operation" && modifier === "settle") result = await settleDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
63
|
+
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(shared.stateDir, options["operation-id"]);
|
|
64
|
+
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: shared.stateDir, cancelTree: options["cancel-tree"], timeoutMs: shared.timeoutMs });
|
|
65
|
+
else if (family === "hook" && command === "handle") { process.stdout.write(`${JSON.stringify(await hook(options))}\n`); process.exit(0); }
|
|
66
|
+
else if (family === "session") {
|
|
67
|
+
const params = { ...shared, answers, ...(command === "create" || command === "prompt" ? { prompt: options["prompt-file"] ? await promptFromFile(options["prompt-file"]) : options.prompt } : {}), ...(command === "fork" ? { target: JSON.parse(options["target-json"] ?? "null") } : {}) };
|
|
68
|
+
// The daemon owns the durable native-request deadline. A disposable RPC
|
|
69
|
+
// wait must not manufacture a second provider timeout.
|
|
70
|
+
const operation = `session.${command === "status" ? "inspect" : command}`;
|
|
71
|
+
const rpcTimeout = command === "prompt" && shared.timeoutMs === undefined
|
|
72
|
+
? null
|
|
73
|
+
: (shared.timeoutMs ?? 1_800_000);
|
|
74
|
+
if (shared.stateDir) result = await callDaemon(shared.stateDir, operation, params, rpcTimeout);
|
|
75
|
+
else if (command === "create") result = await createSession(params);
|
|
76
|
+
else if (command === "prompt") result = await promptSession(params);
|
|
77
|
+
else if (["inspect", "status", "resume"].includes(command)) result = await inspectSession(params);
|
|
78
|
+
else if (command === "cancel") result = await cancelSession(params);
|
|
79
|
+
else if (command === "cancel-child") result = await cancelChild(params);
|
|
80
|
+
else if (command === "fork") result = await forkSession(params);
|
|
81
|
+
else throw new Error(`unknown session command: ${command}`);
|
|
82
|
+
} else throw new Error("usage: dd-zcode doctor | daemon start|status|stop | hook handle | session create|prompt|inspect|status|resume|cancel|cancel-child|fork [options] --json");
|
|
83
|
+
process.stdout.write(`${JSON.stringify({ ok: true, ...result })}\n`);
|
|
84
|
+
} catch (error) {
|
|
85
|
+
if (process.argv[2] === "hook") { process.stderr.write(`${JSON.stringify({ native_hook_failure: errorRecord(error), bound: Boolean(error.details?.native_hook_binding) })}\n`); process.stdout.write(`${JSON.stringify({ decision: "deny", reason: error.message })}\n`); process.exit(2); }
|
|
86
|
+
const failure = errorRecord(error); process.stderr.write(`${JSON.stringify({ ok: false, error: failure.message, ...failure })}\n`); process.exit(1);
|
|
87
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export const NATIVE_OPERATION_WAIT_CONTRACT: "native-operation-wait@1";
|
|
2
|
+
export function canonicalNativeOperation(harness: string, operation: string): string;
|
|
3
|
+
export function nativeOperationWait(harness: string, operation: string): "native-work" | "control";
|
|
4
|
+
export function validateDaemonWait(harness: string, operation: string, duration: number | null): void;
|
|
5
|
+
export function adapterTimeoutOptions(options: Record<string, unknown>, operation?: string | null, harness?: string): { timeoutMs?: number; livenessTimeoutMs?: number; requestTimeoutMs?: number };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Public work flags express silence, never the lifetime of a native Turn.
|
|
2
|
+
import { validateObservationDuration } from "./observation-clock.mjs";
|
|
3
|
+
export const NATIVE_OPERATION_WAIT_CONTRACT = "native-operation-wait@1";
|
|
4
|
+
// Grok's resume only inspects its retained native Session. Other adapters
|
|
5
|
+
// materialize that Session, so their original operation remains productive.
|
|
6
|
+
export function canonicalNativeOperation(harness, operation) {
|
|
7
|
+
return ["grok", "grok-acp"].includes(harness) && operation === "session.resume" ? "session.inspect" : operation;
|
|
8
|
+
}
|
|
9
|
+
// Only Droid's start waits for the full Turn. Codex start returns acceptance;
|
|
10
|
+
// the other bundled adapters do not expose start as a productive operation.
|
|
11
|
+
export function nativeOperationWait(harness, operation) {
|
|
12
|
+
operation = canonicalNativeOperation(harness, operation);
|
|
13
|
+
return operation === "session.prompt" || ["droid", "droid-cli"].includes(harness) && operation === "session.start" ? "native-work" : "control";
|
|
14
|
+
}
|
|
15
|
+
export function validateDaemonWait(harness, operation, duration) {
|
|
16
|
+
if (duration === null && nativeOperationWait(harness, operation) === "native-work") return;
|
|
17
|
+
validateObservationDuration(duration, "daemon control duration");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function adapterTimeoutOptions(options, operation, harness) {
|
|
21
|
+
const duration = name => {
|
|
22
|
+
if (options[name] === undefined) return undefined;
|
|
23
|
+
const ms = Number(options[name]) * 1_000;
|
|
24
|
+
if (!Number.isInteger(ms) || ms < 1 || ms > 2_147_483_647) throw Object.assign(new Error(`--${name} requires positive finite seconds within the timer range`), { code: "invalid_timeout" });
|
|
25
|
+
return ms;
|
|
26
|
+
};
|
|
27
|
+
const timeoutMs = duration("timeout"), livenessTimeoutMs = duration("liveness-timeout"), requestTimeoutMs = duration("request-timeout");
|
|
28
|
+
if (operation === "prompt" || nativeOperationWait(harness, `session.${operation}`) === "native-work") {
|
|
29
|
+
if (timeoutMs !== undefined && livenessTimeoutMs !== undefined && timeoutMs !== livenessTimeoutMs) throw Object.assign(new Error("--timeout and --liveness-timeout must agree for session.prompt"), { code: "invalid_timeout" });
|
|
30
|
+
if (requestTimeoutMs !== undefined) throw Object.assign(new Error("--request-timeout cannot limit a productive prompt"), { code: "invalid_timeout" });
|
|
31
|
+
return { timeoutMs: undefined, livenessTimeoutMs: livenessTimeoutMs ?? timeoutMs };
|
|
32
|
+
}
|
|
33
|
+
return { timeoutMs, livenessTimeoutMs, requestTimeoutMs };
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function agyWorkspaceHooks(): Record<string, unknown>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Qualified hooks are stable; only the launching process selects its pinned
|
|
2
|
+
// entrypoint and daemon. Keep this document shared with product-file policy.
|
|
3
|
+
export function agyWorkspaceHooks() {
|
|
4
|
+
const command = '"${DD_AGY_HOOK_NODE:?missing AGY hook binding}" "${DD_AGY_HOOK_ENTRY:?missing AGY hook binding}" hook handle --event __EVENT__ --state-dir "${DD_AGY_STATE_DIR:?missing AGY hook binding}" --daemon-id "${DD_AGY_DAEMON_ID:?missing AGY hook binding}" --json';
|
|
5
|
+
return { "dd-flow": {
|
|
6
|
+
PreToolUse: [{ matcher: "^run_command$", hooks: [{ type: "command", command: command.replace("__EVENT__", "PreToolUse"), timeout: 30 }] }],
|
|
7
|
+
Stop: [{ type: "command", command: command.replace("__EVENT__", "Stop"), timeout: 30 }]
|
|
8
|
+
} };
|
|
9
|
+
}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export function recoverDaemonReply(root: string, id: string, options?: { timeoutMs?: number | null; signal?: AbortSignal; binding?: Record<string, unknown>; onProgress?: (value: Record<string, unknown>) => void; onOutcome?: (value: Record<string, unknown>) => void; onPendingSettlement?: (value: Record<string, unknown>) => Promise<void>; observationClock?: import("./observation-clock.mjs").ObservationClock }): Promise<Record<string, unknown>>;
|
|
2
|
+
export function retainedDaemonReply(root: string, id: string, binding?: Record<string, unknown>): Promise<{ ready: boolean; outcome: unknown; value?: unknown; settlement?: Record<string, unknown> | null; reason?: string } | null>;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import net from 'node:net';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { hashJson, writeJsonAtomic } from './runner-events.mjs';
|
|
5
|
+
import { ObservationClock } from './observation-clock.mjs';
|
|
6
|
+
import { canonicalNativeOperation, nativeOperationWait, validateDaemonWait } from './adapter-timeouts.mjs';
|
|
7
|
+
import { assertNativeLine, retainNativeReplyBuffer } from './native-streams.mjs';
|
|
8
|
+
import { operationDirectory, readOperationRecord, readOperationProgress, readOperationWaiting, suspendOperationClock } from './operation-progress.mjs';
|
|
9
|
+
|
|
10
|
+
const productive = new Set(['session.create', 'session.prompt', 'session.start', 'session.fork', 'session.resume']);
|
|
11
|
+
const fault = (code, message, details) => Object.assign(new Error(message), { code, retryable: false, details });
|
|
12
|
+
export async function retainedDaemonReply(root, id, binding = {}) {
|
|
13
|
+
const requested = await readOperationRecord(root, id, 'requested.json');
|
|
14
|
+
if (!requested) return null;
|
|
15
|
+
if (requested.operation_id !== id || Object.entries(binding).some(([key, value]) => (requested[key] ?? null) !== (value ?? null))) throw fault('operation_conflict', 'retained operation differs from dispatched request', { operation_id: id });
|
|
16
|
+
const terminal = await readOperationRecord(root, id, 'result.json');
|
|
17
|
+
if (!terminal) return null;
|
|
18
|
+
if (['operation_id','daemon_id','operation','params_sha256','owner_id','generation'].some(field=>Object.hasOwn(terminal,field)&&(terminal[field] ?? null)!==(requested[field] ?? null))) throw fault('operation_conflict','native outcome binding differs from original operation',{operation_id:id});
|
|
19
|
+
if (terminal.state !== 'completed') throw Object.assign(new Error(terminal.error?.message ?? 'native operation failed'), terminal.error);
|
|
20
|
+
if (Number.isSafeInteger(requested.generation)) try {
|
|
21
|
+
const fence = JSON.parse(await readFile(path.join(root,'operation-fence.json'),'utf8'));
|
|
22
|
+
if (fence.daemon_id === requested.daemon_id && fence.generation > requested.generation) throw fault('operation_cancelled','continuation is fenced by newer control',{operation_id:id,native_result:terminal.result});
|
|
23
|
+
} catch(error) { if (error.code !== 'ENOENT') throw error; }
|
|
24
|
+
const settlement = await readOperationRecord(root, id, 'settlement.json');
|
|
25
|
+
try {
|
|
26
|
+
const daemon = JSON.parse(await readFile(path.join(root,'daemon.json'),'utf8'));
|
|
27
|
+
if ((daemon.daemon_id ?? daemon.config?.daemonId ?? null)!==requested.daemon_id || (daemon.config?.runtime_owner?.owner_id ?? null)!==(requested.owner_id ?? null) || ['stopping','clean','unclean','cleanup_failed','failed'].includes(daemon.shutdown_state)) return {ready:false,outcome:terminal.result,settlement,reason:'daemon_authority_changed'};
|
|
28
|
+
if (requested.owner_id) try { process.kill(daemon.pid,0); } catch { return {ready:false,outcome:terminal.result,settlement,reason:'daemon_owner_dead'}; }
|
|
29
|
+
} catch(error) { if(error.code!=='ENOENT') throw error; if(requested.daemon_id || requested.owner_id) return {ready:false,outcome:terminal.result,settlement,reason:'daemon_absent'}; }
|
|
30
|
+
if (!['settled', 'not_required'].includes(settlement?.state)) return { ready: false, outcome: terminal.result, settlement };
|
|
31
|
+
return { ready: true, outcome: terminal.result, settlement, value: settlement.state === 'not_required' ? terminal.result : { ...terminal.result, settlement } };
|
|
32
|
+
}
|
|
33
|
+
export async function recoverDaemonReply(root, id, { timeoutMs = 30_000, signal, binding = {}, onProgress = () => {}, onOutcome = () => {}, onPendingSettlement, observationClock } = {}) {
|
|
34
|
+
const saved = observationClock ? null : await readOperationRecord(root, id, 'observer-recovery.json') ?? await readOperationRecord(root, id, 'observer-transport.json');
|
|
35
|
+
signal?.throwIfAborted();
|
|
36
|
+
const clock = observationClock ?? new ObservationClock({ timeoutMs: saved?.timeout_ms ?? timeoutMs, saved });
|
|
37
|
+
let lastSequence = clock.progress ?? 0, lastSaved = 0, latestProgress, settlementAttempted = false, settlementError;
|
|
38
|
+
const exhaustedCursor = clock.progress;
|
|
39
|
+
let exhausted = clock.observationLost || clock.elapsed >= clock.timeoutMs;
|
|
40
|
+
for (;;) {
|
|
41
|
+
signal?.throwIfAborted();
|
|
42
|
+
const retained = await retainedDaemonReply(root, id, binding);
|
|
43
|
+
signal?.throwIfAborted();
|
|
44
|
+
if (retained) {
|
|
45
|
+
onOutcome(retained.outcome);
|
|
46
|
+
signal?.throwIfAborted();
|
|
47
|
+
if (retained.ready) return retained.value;
|
|
48
|
+
}
|
|
49
|
+
const progress = await readOperationProgress(root, id, binding);
|
|
50
|
+
signal?.throwIfAborted();
|
|
51
|
+
if (progress && progress.sequence > lastSequence) {
|
|
52
|
+
lastSequence = progress.sequence;
|
|
53
|
+
const observedAt = Date.parse(progress.observed_at);
|
|
54
|
+
// The outer cursor counts diagnostics, not durable sequences. A handoff
|
|
55
|
+
// may recognize a higher sequence with the same already-observed event.
|
|
56
|
+
if (clock.progressAt === null || observedAt > clock.progressAt) {
|
|
57
|
+
latestProgress={cursor:progress.sequence,observed_at:observedAt}; onProgress(progress);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
const waiting = await readOperationWaiting(root,id,binding);
|
|
61
|
+
signal?.throwIfAborted();
|
|
62
|
+
if (waiting) suspendOperationClock(clock);
|
|
63
|
+
const sampled = waiting ? false : clock.sample(latestProgress);
|
|
64
|
+
if (clock.progress !== exhaustedCursor && clock.elapsed < clock.timeoutMs && !clock.observationLost) exhausted = false;
|
|
65
|
+
const expired = !waiting && (exhausted || sampled);
|
|
66
|
+
if ((expired || Date.now() - lastSaved >= 1_000) && await readOperationRecord(root,id,'requested.json')) { await writeJsonAtomic(path.join(operationDirectory(root,id),'observer-recovery.json'),clock.state()); lastSaved = Date.now(); }
|
|
67
|
+
if (expired) {
|
|
68
|
+
const final = await retainedDaemonReply(root, id, binding);
|
|
69
|
+
signal?.throwIfAborted();
|
|
70
|
+
if (final?.ready) return final.value;
|
|
71
|
+
throw fault(final ? 'settlement_reconciliation_required' : 'operation_observation_lost', 'original operation has no dispatch-ready reply', { operation_id: id, native_outcome: final ? 'completed' : 'unknown', native_result: final?.outcome, settlement: final?.settlement, reason:final?.reason, ...(settlementError ? { settlement_error:settlementError } : {}), state_dir: root });
|
|
72
|
+
}
|
|
73
|
+
if (retained && onPendingSettlement && !settlementAttempted && !retained.reason) {
|
|
74
|
+
settlementAttempted = true;
|
|
75
|
+
try { await onPendingSettlement(retained); } catch (error) { settlementError = {code:error.code,message:error.message}; }
|
|
76
|
+
signal?.throwIfAborted();
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
await new Promise(resolve => setTimeout(resolve, Math.min(100, timeoutMs / 4)));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export async function callDaemonObserved({ stateDir, socket, request, responseSchema, harness, timeoutMs }) {
|
|
83
|
+
request = { ...request, operation: canonicalNativeOperation(harness, request.operation) };
|
|
84
|
+
validateDaemonWait(harness, request.operation, timeoutMs);
|
|
85
|
+
assertNativeLine(JSON.stringify(request), 'request');
|
|
86
|
+
const durable = productive.has(request.operation);
|
|
87
|
+
const binding = { operation: request.operation, params_sha256: hashJson({ operation: request.operation, params: request.params ?? {} }) };
|
|
88
|
+
let initialDaemon;
|
|
89
|
+
if (durable) try {
|
|
90
|
+
const state = JSON.parse(await readFile(path.join(stateDir,'daemon.json'),'utf8'));
|
|
91
|
+
initialDaemon = state.daemon_id ?? state.config?.daemonId ?? null;
|
|
92
|
+
binding.owner_id = state.config?.runtime_owner?.owner_id ?? null;
|
|
93
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
94
|
+
// Reject a reused ID with different inputs before opening a transport.
|
|
95
|
+
// Otherwise its retained progress can win the race with the daemon's
|
|
96
|
+
// conflict reply and misclassify a valid old receipt as corrupt progress.
|
|
97
|
+
if (durable) await retainedDaemonReply(stateDir, request.id, {
|
|
98
|
+
...binding, ...(initialDaemon === undefined ? {} : { daemon_id: initialDaemon })
|
|
99
|
+
});
|
|
100
|
+
const savedClock = durable ? await readOperationRecord(stateDir,request.id,'observer-transport.json') : null;
|
|
101
|
+
return await new Promise((resolve, reject) => {
|
|
102
|
+
const client = net.createConnection(socket);
|
|
103
|
+
let buffer = '', done = false, polling = false, pollFlight, lastSequence = savedClock?.cursor ?? 0, frozenDaemon = initialDaemon, disconnected = false, latestProgress, lastSaved = 0;
|
|
104
|
+
const bound = () => ({ ...binding, ...(frozenDaemon === undefined ? {} : { daemon_id: frozenDaemon }) });
|
|
105
|
+
const nativeWork = nativeOperationWait(harness, request.operation) === 'native-work';
|
|
106
|
+
let clock = nativeWork ? null : new ObservationClock({ timeoutMs, saved: savedClock });
|
|
107
|
+
const finish = (error, result) => { if (done) return; done = true; clearInterval(timer); client.destroy(); void Promise.resolve(pollFlight).then(() => error ? reject(error) : resolve(result)); };
|
|
108
|
+
const reconcile = async error => {
|
|
109
|
+
if (done) return;
|
|
110
|
+
try {
|
|
111
|
+
const reply = durable ? await retainedDaemonReply(stateDir, request.id, bound()) : null;
|
|
112
|
+
if (reply?.ready) return finish(null, reply.value);
|
|
113
|
+
if (reply) error = fault('settlement_reconciliation_required', 'native outcome retained; dispatch readiness is not confirmed', { operation_id: request.id, native_outcome: 'completed', native_result: reply.outcome, settlement: reply.settlement, reason:reply.reason, state_dir: stateDir });
|
|
114
|
+
else if (durable) error = fault(error.code, error.message, { ...error.details, operation_id: request.id, native_outcome: 'unknown', state_dir: stateDir });
|
|
115
|
+
finish(error);
|
|
116
|
+
} catch (cause) { finish(cause); }
|
|
117
|
+
};
|
|
118
|
+
const poll = () => {
|
|
119
|
+
if (done || polling) return pollFlight; polling = true;
|
|
120
|
+
pollFlight = (async () => {
|
|
121
|
+
try {
|
|
122
|
+
const progress = durable ? await readOperationProgress(stateDir, request.id, { ...binding, ...(frozenDaemon === undefined ? {} : { daemon_id: frozenDaemon }) }) : null;
|
|
123
|
+
if (done) return;
|
|
124
|
+
if (progress && progress.sequence > lastSequence) {
|
|
125
|
+
frozenDaemon ??= progress.daemon_id; lastSequence = progress.sequence;
|
|
126
|
+
binding.generation ??= progress.generation;
|
|
127
|
+
latestProgress = {cursor:progress.sequence,observed_at:Date.parse(progress.observed_at)};
|
|
128
|
+
process.stderr.write(`${JSON.stringify({ kind: 'operation_progress', ...progress })}\n`);
|
|
129
|
+
}
|
|
130
|
+
if (durable && disconnected) {
|
|
131
|
+
const reply = await retainedDaemonReply(stateDir, request.id, bound());
|
|
132
|
+
if (reply?.ready) return finish(null, reply.value);
|
|
133
|
+
}
|
|
134
|
+
const waiting = durable && await readOperationWaiting(stateDir,request.id,bound());
|
|
135
|
+
if (done) return;
|
|
136
|
+
if (clock && waiting) suspendOperationClock(clock);
|
|
137
|
+
const expired = !waiting && clock?.sample(latestProgress ?? (durable ? undefined : buffer.length || undefined));
|
|
138
|
+
if (durable && clock && (expired || Date.now()-lastSaved>=1_000) && await readOperationRecord(stateDir,request.id,'requested.json')) { await writeJsonAtomic(path.join(operationDirectory(stateDir,request.id),'observer-transport.json'),clock.state()); lastSaved=Date.now(); }
|
|
139
|
+
if (expired) await reconcile(fault('daemon_timeout', `${request.operation} timed out`));
|
|
140
|
+
} catch (error) { finish(error); } finally { polling = false; }
|
|
141
|
+
})();
|
|
142
|
+
return pollFlight;
|
|
143
|
+
};
|
|
144
|
+
const timer = setInterval(poll, Math.max(1, Math.min(100, (timeoutMs ?? 400) / 4)));
|
|
145
|
+
client.setEncoding('utf8'); client.on('connect', () => client.write(`${JSON.stringify(request)}\n`));
|
|
146
|
+
const lost = error => { if (durable) { disconnected = true; clock ??= new ObservationClock({timeoutMs: timeoutMs ?? 30_000,saved:savedClock}); void poll(); } else void reconcile(error); };
|
|
147
|
+
client.on('error', error => lost(fault('daemon_not_running', error.message)));
|
|
148
|
+
client.on('end', () => lost(fault('daemon_connection_closed', 'daemon closed before reply')));
|
|
149
|
+
client.on('close', () => lost(fault('daemon_connection_closed', 'daemon closed before reply')));
|
|
150
|
+
client.on('data', chunk => { void (async () => {
|
|
151
|
+
buffer += chunk; if (!retainNativeReplyBuffer(buffer, finish)) return;
|
|
152
|
+
const at = buffer.indexOf('\n'); if (at < 0) return;
|
|
153
|
+
try {
|
|
154
|
+
const response = JSON.parse(buffer.slice(0, at));
|
|
155
|
+
if (response.schema_id !== responseSchema || response.id !== request.id) throw fault('operation_observation_lost', 'daemon reply identity mismatch');
|
|
156
|
+
if (!response.ok) return finish(Object.assign(new Error(response.error?.message ?? 'daemon operation failed'), response.error));
|
|
157
|
+
if (durable && (binding.owner_id && !response.result?.settlement || response.result?.settlement && !['settled','not_required'].includes(response.result.settlement.state))) { disconnected = true; clock ??= new ObservationClock({timeoutMs:savedClock?.timeout_ms ?? timeoutMs ?? 30_000,saved:savedClock}); void poll(); return; }
|
|
158
|
+
if (durable) { const retained=await retainedDaemonReply(stateDir,request.id,bound()); if(retained) { if(retained.ready) return finish(null,retained.value); disconnected=true; clock ??= new ObservationClock({timeoutMs:timeoutMs ?? 30_000,saved:savedClock}); void poll(); return; } return void reconcile(fault('operation_observation_lost','productive native reply has no durable original receipt')); }
|
|
159
|
+
finish(null, response.result);
|
|
160
|
+
} catch (error) { void reconcile(error.code ? error : Object.assign(fault('operation_observation_lost', 'daemon reply could not be decoded', {native_outcome:'unknown'}), {cause:error})); }
|
|
161
|
+
})(); });
|
|
162
|
+
});
|
|
163
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function inspectDaemonOperation(root: string, id: string): Promise<Record<string, unknown>>;
|