@deksden-com/dd-flow-cli 0.9.0-beta.137 → 0.9.0-beta.139
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 +19 -0
- package/README.md +9 -0
- package/dist/build-info.json +6 -6
- package/dist/cli/argument-values.js +5 -5
- package/dist/cli/command-inputs.js +89 -20
- 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 +240 -6
- package/dist/cli/input-preparation.js +54 -5
- 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 +1 -1
- 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 +283 -160
- package/dist/cli/runtime-process.js +1 -1
- package/dist/cli/setup.js +149 -0
- package/dist/cli.js +56 -2
- package/dist/domain/stage-handler-identities.js +20 -0
- package/dist/harness-runtime/lib/daemon-operations.d.mts +1 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +4 -3
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +53 -22
- package/dist/harness-runtime/lib/dd-agy.mjs +16 -5
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +12 -6
- package/dist/harness-runtime/lib/dd-codex.mjs +24 -12
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +2 -1
- package/dist/harness-runtime/lib/dd-droid.mjs +32 -9
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +11 -3
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +100 -15
- package/dist/harness-runtime/lib/dd-opencode.mjs +51 -20
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +22 -10
- package/dist/harness-runtime/lib/dd-zcode.mjs +17 -4
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +1 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +16 -3
- package/dist/harness-runtime/lib/lease-renewal.mjs +2 -1
- package/dist/harness-runtime/lib/lifecycle-command.mjs +1 -0
- package/dist/harness-runtime/lib/managed-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +50 -15
- package/dist/harness-runtime/lib/managed-flow-env.mjs +15 -0
- package/dist/harness-runtime/lib/native-children.d.mts +2 -0
- package/dist/harness-runtime/lib/native-children.mjs +20 -1
- package/dist/harness-runtime/lib/native-hook-command.mjs +1 -1
- 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/opencode-plugin.mjs +32 -9
- package/dist/harness-runtime/lib/operation-progress.mjs +3 -1
- 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/runtime/context.js +1 -1
- 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 +26 -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/profile-settings.schema.json +122 -0
- package/dist/schemas/release-manifest.schema.json +291 -0
- package/dist/schemas/run-engine-binding.schema.json +1 -1
- package/dist/services/check-runner-evidence.js +51 -4
- package/dist/services/cli-operation-classifier.js +8 -47
- package/dist/services/cli-upgrade-allowlist.js +27 -0
- package/dist/services/code-checks.js +387 -34
- package/dist/services/controller-child-capacity.js +13 -0
- package/dist/services/controller-child-observer.js +18 -2
- package/dist/services/controller-execution.js +88 -0
- package/dist/services/controller-fanout.js +71 -12
- package/dist/services/dashboard.js +8 -2
- 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 +39 -22
- package/dist/services/eval-snapshots.js +83 -25
- package/dist/services/execution-bundles.js +263 -0
- package/dist/services/execution-policy.js +20 -16
- package/dist/services/executor-onboarding.js +56 -0
- package/dist/services/external-work-launch.js +93 -15
- 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 +28 -2
- 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 +24 -6
- 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/lifecycle-invocations.js +257 -78
- package/dist/services/managed-processes.js +31 -10
- 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-server.js +2 -4
- package/dist/services/model-catalog.js +109 -0
- package/dist/services/model-discovery.js +46 -0
- package/dist/services/operator-profiles.js +236 -0
- package/dist/services/projects.js +17 -2
- package/dist/services/{codex-capacity.js → provider-capacity.js} +34 -16
- package/dist/services/recovery-snapshot-database.js +417 -2
- 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 +1 -1
- package/dist/services/review-copy.js +10 -2
- package/dist/services/run-control.js +80 -9
- package/dist/services/run-controller-adapter.js +1 -1
- package/dist/services/run-controller-capture.js +10 -3
- package/dist/services/run-controller-process.js +21 -0
- package/dist/services/run-controller-recovery.js +5 -5
- package/dist/services/run-controller-state.js +1 -1
- package/dist/services/run-controller.js +158 -64
- package/dist/services/run-recovery-guard.js +5 -3
- package/dist/services/run-recovery-runtime.js +3 -3
- package/dist/services/run-recovery.js +145 -5
- package/dist/services/run-start-custody.js +177 -0
- package/dist/services/runs.js +413 -30
- package/dist/services/setup.js +377 -0
- package/dist/services/stage-context.js +9 -1
- package/dist/services/stage-handlers.js +74 -0
- package/dist/services/stage-report-renderer.js +63 -0
- package/dist/services/stage-work-graph.js +17 -0
- package/dist/services/vnext-code-review.js +1 -1
- package/dist/services/vnext-code.js +6 -6
- package/dist/services/vnext-execution-profile.js +2 -2
- package/dist/services/vnext-fanout.js +73 -11
- package/dist/services/vnext-merge.js +8 -3
- package/dist/services/vnext-plan-review.js +7 -5
- package/dist/services/vnext-plan.js +3 -3
- package/dist/services/vnext-protocolize.js +20 -6
- package/dist/services/vnext-workspace-policy.js +7 -2
- package/dist/services/work-registry.js +616 -71
- package/dist/services/workspace-files.js +1 -1
- package/dist/storage/database.js +84 -6
- package/dist/storage/writer-contract.js +11 -7
- package/package.json +13 -3
- package/tools/create-canon-release.mjs +33 -0
- package/tools/produce-hybrid-release.mjs +41 -0
- package/dist/harness-runtime/lib/codex-capacity-policy.d.mts +0 -10
- package/dist/harness-runtime/lib/codex-capacity-policy.mjs +0 -102
|
@@ -91,7 +91,7 @@ export async function dispatchRuntimeProcess(context, action, parsed, prepared =
|
|
|
91
91
|
return { ...receipt, ok: receipt.owned };
|
|
92
92
|
}
|
|
93
93
|
if (action === "admission") {
|
|
94
|
-
const [{ controllerHitlAdmission }, { assertCapacityOwnerAdmission }] = await Promise.all([import("../services/run-controller-adapter.js"), import("../services/
|
|
94
|
+
const [{ controllerHitlAdmission }, { assertCapacityOwnerAdmission }] = await Promise.all([import("../services/run-controller-adapter.js"), import("../services/provider-capacity.js")]);
|
|
95
95
|
const record = managedProcessStatus(context).find(process => process.id === requiredOption(parsed, "id"));
|
|
96
96
|
if (!record || record.lease_token !== requiredOption(parsed, "lease-token") || record.owner_id !== requiredOption(parsed, "owner") || record.state !== "running" || !record.pid || !record.pid_started_at || !processIsAlive(record))
|
|
97
97
|
throw new AppError("process_ownership_unknown", "Productive dispatch requires its current confirmed runtime owner", 1);
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { prepareCommandRoute } from "./command-inputs.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { parseOutputOptions } from "./output-options.js";
|
|
4
|
+
import { resolveDdFlowHome } from "../storage/paths.js";
|
|
5
|
+
import { readSetupStatus, installAuthenticatedRelease, readRetainedSetupExecutor, hasDeferredSetupOnboarding, readSetupOnboarding, commitSetupOnboarding } from "../services/setup.js";
|
|
6
|
+
import { readTrustedReleaseProducers, readReleaseBundle } from "../services/release-source.js";
|
|
7
|
+
import { createReleaseCompatibility, installedCatalogVersions } from "../services/release-compatibility.js";
|
|
8
|
+
import { getCliVersionReport } from "../services/build-info.js";
|
|
9
|
+
import { readOperatorProfiles, readProfileCreationIntent } from "../services/operator-profiles.js";
|
|
10
|
+
import { onboardExecutor, selectOnboardingExecutor } from "../services/executor-onboarding.js";
|
|
11
|
+
import { askExecutorChoice } from "./executor-onboarding.js";
|
|
12
|
+
import { requiredOption, optionalOption } from "./argument-values.js";
|
|
13
|
+
import { AppError, errorRecord } from "../shared/errors.js";
|
|
14
|
+
import { hybridDigest } from "../services/hybrid-contracts.js";
|
|
15
|
+
import { prepareResponseDestination, writeResponseFile } from "./response-file.js";
|
|
16
|
+
import { readRegistryRelease } from "../services/release-registry.js";
|
|
17
|
+
import { writePreparationError } from "./error-output.js";
|
|
18
|
+
import { publishSetup } from "../harness-runtime/lib/setup-progress.mjs";
|
|
19
|
+
/** Lightweight global diagnostic ingress; never creates a runtime context. */
|
|
20
|
+
export async function runSetupCli(args, env, io = { stdout: process.stdout, stderr: process.stderr, stdin: process.stdin }) {
|
|
21
|
+
let json = false;
|
|
22
|
+
try {
|
|
23
|
+
const output = parseOutputOptions(args);
|
|
24
|
+
json = output.json;
|
|
25
|
+
if (output.responseFile)
|
|
26
|
+
prepareResponseDestination(output.responseFile);
|
|
27
|
+
const route = prepareCommandRoute(output.args);
|
|
28
|
+
const humanProgress = !output.json && !output.progressJsonl;
|
|
29
|
+
const reportHumanProgress = (message) => {
|
|
30
|
+
// Diagnostic delivery cannot turn a completed installation into failure.
|
|
31
|
+
try {
|
|
32
|
+
io.stderr.write(`setup: ${message}\n`);
|
|
33
|
+
}
|
|
34
|
+
catch { /* Best-effort human progress only. */ }
|
|
35
|
+
};
|
|
36
|
+
const home = resolveDdFlowHome(env);
|
|
37
|
+
let result;
|
|
38
|
+
if (route.key === "setup status")
|
|
39
|
+
result = { ok: true, action: "setup_status", observed_cli: getCliVersionReport().cli, ...readSetupStatus(home) };
|
|
40
|
+
else if (route.key === "setup" || route.key === "setup update") {
|
|
41
|
+
const parsed = route.parsed;
|
|
42
|
+
const source = optionalOption(parsed, "canon-source"), version = optionalOption(parsed, "canon-version");
|
|
43
|
+
const registryFile = optionalOption(parsed, "release-registry");
|
|
44
|
+
if (source && (version || registryFile))
|
|
45
|
+
throw new AppError("usage", "--canon-source is exclusive with --canon-version and --release-registry; see dd-flow setup --help", 2, { effect: "no_effect" });
|
|
46
|
+
const channel = (optionalOption(parsed, "channel") ?? "stable");
|
|
47
|
+
const selection = source ? null : readRegistryRelease(registryFile ?? env.DD_FLOW_RELEASE_REGISTRY ?? path.join(home, "release-registry.json"), channel, version);
|
|
48
|
+
const profile = optionalOption(parsed, "profile"), skip = parsed.options.has("skip-agent-setup");
|
|
49
|
+
const intentFile = optionalOption(parsed, "save-profile-intent");
|
|
50
|
+
if (intentFile && skip)
|
|
51
|
+
throw new AppError("usage", "--save-profile-intent conflicts with --skip-agent-setup", 2, { effect: "no_effect" });
|
|
52
|
+
let profileCreation = intentFile ? readProfileCreationIntent(intentFile) : undefined;
|
|
53
|
+
const stdin = io.stdin ?? process.stdin;
|
|
54
|
+
const nonInteractive = parsed.options.has("non-interactive") || output.json || output.progressJsonl
|
|
55
|
+
|| !stdin.isTTY || !io.stderr.isTTY;
|
|
56
|
+
const profileFile = optionalOption(parsed, "profile-file");
|
|
57
|
+
const requestId = requiredOption(parsed, "request-id");
|
|
58
|
+
const retained = profile === undefined && profileFile === undefined && !intentFile && !skip ? readRetainedSetupExecutor(home, requestId) : null;
|
|
59
|
+
if (retained?.profileCreation)
|
|
60
|
+
profileCreation = retained.profileCreation;
|
|
61
|
+
const choice = { ...(profile !== undefined ? { profileId: profile } : {}),
|
|
62
|
+
...(profileFile !== undefined ? { profileFile } : {}),
|
|
63
|
+
...(retained?.executor ? { profile: retained.executor } : profileCreation && profile === undefined && profileFile === undefined ? { profile: profileCreation.profile } : {}),
|
|
64
|
+
skip: skip || retained !== null && retained.executor === null };
|
|
65
|
+
let deferred = hasDeferredSetupOnboarding(home, requestId);
|
|
66
|
+
let selected;
|
|
67
|
+
if (!deferred) {
|
|
68
|
+
try {
|
|
69
|
+
selected = selectOnboardingExecutor(choice, () => readOperatorProfiles(home), { allowSkip: true });
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (!(error instanceof AppError) || error.code !== "agent_profile_missing" || nonInteractive
|
|
73
|
+
|| profile !== undefined || profileFile !== undefined || intentFile || skip)
|
|
74
|
+
throw error;
|
|
75
|
+
deferred = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
else if (profile !== undefined || profileFile !== undefined || intentFile || skip) {
|
|
79
|
+
// Explicit continuation inputs still fail before downloading or replaying.
|
|
80
|
+
selected = selectOnboardingExecutor(choice, () => readOperatorProfiles(home), { allowSkip: true });
|
|
81
|
+
}
|
|
82
|
+
const observedCli = getCliVersionReport().cli;
|
|
83
|
+
const compatibility = createReleaseCompatibility({ channel,
|
|
84
|
+
catalogVersions: installedCatalogVersions, routerVersion: observedCli.version });
|
|
85
|
+
const producers = readTrustedReleaseProducers(requiredOption(parsed, "trust-file"));
|
|
86
|
+
const bundle = await readReleaseBundle(source ?? selection.envelope_url, producers, compatibility, {
|
|
87
|
+
...(selection ? { expectedVersion: selection.version } : {}),
|
|
88
|
+
...((output.progressJsonl || humanProgress) ? { onProgress: (progress) => {
|
|
89
|
+
if (output.progressJsonl)
|
|
90
|
+
io.stdout.write(`${JSON.stringify({ type: "setup_download_progress", request_id: requestId, ...progress })}\n`);
|
|
91
|
+
else if (progress.received_bytes === progress.expected_bytes)
|
|
92
|
+
reportHumanProgress(`${progress.artifact} archive received (${progress.received_bytes} bytes); integrity validation follows`);
|
|
93
|
+
} } : {})
|
|
94
|
+
});
|
|
95
|
+
if (selection && bundle.authenticated.manifest.version !== selection.version)
|
|
96
|
+
throw new AppError("release_registry", "Authenticated release differs from selected registry version", 1, { reason: "selected_version_mismatch", phase: "release_selection", effect: "no_effect", help: "setup" });
|
|
97
|
+
const installed = installAuthenticatedRelease(home, { requestId, action: route.key === "setup update" ? "update" : "install",
|
|
98
|
+
envelope: bundle.envelope, trustedProducers: producers, compatibility, canonArchive: bundle.canonArchive, engineArchive: bundle.engineArchive,
|
|
99
|
+
...(deferred ? { deferredOnboarding: true } : { executor: selected.profile, ...(profileCreation ? { profileCreation } : {}) }),
|
|
100
|
+
onCheckpoint: phase => {
|
|
101
|
+
publishSetup("dependency_check_completed", `release-setup:${phase}`);
|
|
102
|
+
if (output.progressJsonl)
|
|
103
|
+
io.stdout.write(`${JSON.stringify({ type: "setup_progress", request_id: requestId, phase })}\n`);
|
|
104
|
+
else if (humanProgress)
|
|
105
|
+
reportHumanProgress({ prepared: "verified release request retained", canon_cached: "canon cache verified", engine_cached: "engine cache verified",
|
|
106
|
+
profiles_saved: "profile settings saved", committed: "installation committed; runtime qualification remains unknown" }[phase]);
|
|
107
|
+
} });
|
|
108
|
+
if (humanProgress && installed.replayed)
|
|
109
|
+
reportHumanProgress("exact request replay verified; retained selection was not reactivated");
|
|
110
|
+
if (deferred) {
|
|
111
|
+
const saved = readSetupOnboarding(home, requestId);
|
|
112
|
+
const explicit = profile !== undefined || profileFile !== undefined || intentFile !== undefined || skip;
|
|
113
|
+
const deferredChoice = saved && !explicit ? { ...(saved.executor ? { profile: saved.executor } : { skip: true }),
|
|
114
|
+
...(saved.profileCreation ? { profileCreation: saved.profileCreation } : {}) } : choice;
|
|
115
|
+
try {
|
|
116
|
+
selected ??= await onboardExecutor(deferredChoice, () => readOperatorProfiles(home), { allowSkip: true, nonInteractive }, settings => askExecutorChoice(settings, { stdin, stderr: io.stderr }));
|
|
117
|
+
const consent = commitSetupOnboarding(home, requestId, { executor: selected.profile,
|
|
118
|
+
...(profileCreation ?? selected.profileCreation ? { profileCreation: profileCreation ?? selected.profileCreation } : {}) });
|
|
119
|
+
installed.executor = consent.executor;
|
|
120
|
+
if (humanProgress)
|
|
121
|
+
reportHumanProgress("executor onboarding committed after installation");
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (error instanceof AppError) {
|
|
125
|
+
error.details.installation = "committed";
|
|
126
|
+
error.details.request_id = requestId;
|
|
127
|
+
error.details.next_action = "Replay the same setup request to resume executor onboarding; installation remains retained";
|
|
128
|
+
}
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
result = { ...installed, action: route.key === "setup update" ? "setup_update" : "setup_install", observed_cli: observedCli,
|
|
133
|
+
executor: installed.executor ? { profile_id: installed.executor.id, revision: hybridDigest(installed.executor), readiness: "unknown_requires_qualification" } : { profile_id: null, readiness: "not_configured" },
|
|
134
|
+
...readSetupStatus(home) };
|
|
135
|
+
}
|
|
136
|
+
else
|
|
137
|
+
throw new AppError("usage", "Unknown setup command; see dd-flow setup --help", 2, { effect: "no_effect" });
|
|
138
|
+
io.stdout.write(`${JSON.stringify(writeResponseFile(result, output), null, json ? undefined : 2)}\n`);
|
|
139
|
+
return 0;
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const record = errorRecord(error);
|
|
143
|
+
writePreparationError(io, args, record);
|
|
144
|
+
if (!json && error instanceof AppError && error.details.installation === "committed") {
|
|
145
|
+
io.stderr.write("setup: installation remains committed; replay the same request to resume executor onboarding\n");
|
|
146
|
+
}
|
|
147
|
+
return record.exitCode;
|
|
148
|
+
}
|
|
149
|
+
}
|
package/dist/cli.js
CHANGED
|
@@ -1,14 +1,68 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { isNativeHookIngress } from "./cli/native-hook-ingress.js";
|
|
3
3
|
import { isRuntimeMaintenanceIngress, runRuntimeMaintenanceIngress } from "./cli/runtime-maintenance-ingress.js";
|
|
4
|
+
import { resolveHelp } from "./cli/help.js";
|
|
5
|
+
import { errorRecord } from "./shared/errors.js";
|
|
6
|
+
import { writePreparationError } from "./cli/error-output.js";
|
|
4
7
|
import { publishSetup } from './harness-runtime/lib/setup-progress.mjs';
|
|
5
8
|
const args = process.argv.slice(2);
|
|
6
|
-
|
|
9
|
+
let help;
|
|
10
|
+
try {
|
|
11
|
+
help = resolveHelp(args);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
const record = errorRecord(error);
|
|
15
|
+
writePreparationError({ stderr: process.stderr }, args, record);
|
|
16
|
+
process.exit(record.exitCode);
|
|
17
|
+
}
|
|
18
|
+
if (help) {
|
|
19
|
+
process.stdout.write(`${help.json ? JSON.stringify(help.data) : help.text}\n`);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (args[0] === "completion") {
|
|
23
|
+
const { runCompletionCli } = await import("./cli/completion-cli.js");
|
|
24
|
+
process.exit(runCompletionCli(args));
|
|
25
|
+
}
|
|
26
|
+
if (args[0] === "profiles") {
|
|
27
|
+
const { runOperatorProfilesCli } = await import("./cli/operator-profiles.js");
|
|
28
|
+
process.exit(runOperatorProfilesCli(args, process.env));
|
|
29
|
+
}
|
|
30
|
+
if (args[0] === "setup") {
|
|
31
|
+
const { runSetupCli } = await import("./cli/setup.js");
|
|
32
|
+
process.exit(await runSetupCli(args, process.env));
|
|
33
|
+
}
|
|
34
|
+
if (args[0] === "harnesses") {
|
|
35
|
+
const { runHarnessesCli } = await import("./cli/harnesses.js");
|
|
36
|
+
process.exit(await runHarnessesCli(args, process.env));
|
|
37
|
+
}
|
|
38
|
+
if (args[0] === "models") {
|
|
39
|
+
const { runModelsCli } = await import("./cli/models.js");
|
|
40
|
+
process.exit(runModelsCli(args));
|
|
41
|
+
}
|
|
42
|
+
if (args[0] === "flow" && ["list", "show"].includes(args[1] ?? "")) {
|
|
43
|
+
const { runFlowCatalogCli } = await import("./cli/flows.js");
|
|
44
|
+
process.exit(runFlowCatalogCli(args));
|
|
45
|
+
}
|
|
46
|
+
if (args[0] === "init" || args[0] === "flow" && args[1] === "mb-init") {
|
|
47
|
+
publishSetup('ingress_entered');
|
|
48
|
+
const { runMemoryInitCli } = await import("./cli/memory-init.js");
|
|
49
|
+
publishSetup('imports_ready');
|
|
50
|
+
process.exit(await runMemoryInitCli(args, process.env));
|
|
51
|
+
}
|
|
52
|
+
if (args.slice(0, 3).join(" ") === "runtime storage admit") {
|
|
53
|
+
const { runMemoryStorageAdmissionCli } = await import("./cli/memory-storage-admission.js");
|
|
54
|
+
process.exit(runMemoryStorageAdmissionCli(args));
|
|
55
|
+
}
|
|
56
|
+
if (args.slice(0, 3).join(" ") === "runtime flow admit") {
|
|
57
|
+
const { runMemoryFlowAdmissionCli } = await import("./cli/memory-flow-admission.js");
|
|
58
|
+
process.exit(await runMemoryFlowAdmissionCli(args));
|
|
59
|
+
}
|
|
60
|
+
const managedHook = Boolean(process.env.DD_FLOW_CODEX_STATE_DIR) && args.slice(0, 3).join(" ") === "codex hook handle";
|
|
7
61
|
const exitCode = isRuntimeMaintenanceIngress(args, process.env)
|
|
8
62
|
? await runRuntimeMaintenanceIngress(args)
|
|
9
63
|
: managedHook
|
|
10
64
|
? await (await import("./cli/hook-ingress.js")).runHookIngress(args)
|
|
11
|
-
: isNativeHookIngress(args)
|
|
65
|
+
: isNativeHookIngress(args)
|
|
12
66
|
? await (await import("./cli/native-hook-ingress.js")).runNativeHookIngress(args)
|
|
13
67
|
: await (async () => {
|
|
14
68
|
publishSetup('ingress_entered');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/** Engine-owned identities shared by inspection and executable registration.
|
|
2
|
+
* Keep this module dependency-free: catalog inspection must not load handlers.
|
|
3
|
+
*/
|
|
4
|
+
export const sdlcHandlerIdentities = Object.freeze({
|
|
5
|
+
specify: Object.freeze({ stage: "specify", entryId: "sdlc-specify-entry", finishId: "sdlc-specify-finish" }),
|
|
6
|
+
protocolize: Object.freeze({ stage: "protocolize", entryId: "sdlc-protocolize-entry", finishId: "sdlc-protocolize-finish" }),
|
|
7
|
+
plan: Object.freeze({ stage: "plan", entryId: "sdlc-plan-entry", finishId: "sdlc-plan-finish" }),
|
|
8
|
+
"plan-review": Object.freeze({ stage: "plan-review", entryId: "sdlc-plan-review-entry", finishId: "sdlc-plan-review-finish" }),
|
|
9
|
+
code: Object.freeze({ stage: "code", entryId: "sdlc-code-entry", finishId: "sdlc-code-finish" }),
|
|
10
|
+
"code-review": Object.freeze({ stage: "code-review", entryId: "sdlc-code-review-entry", finishId: "sdlc-code-review-finish" }),
|
|
11
|
+
merge: Object.freeze({ stage: "merge", entryId: "sdlc-merge-entry", finishId: "sdlc-merge-finish" })
|
|
12
|
+
});
|
|
13
|
+
export const memoryInitHandlerIdentities = Object.freeze({
|
|
14
|
+
preflight: Object.freeze({ stage: "preflight", entryId: "memory-stage-entry", finishId: "memory-stage-finish" }),
|
|
15
|
+
discover: Object.freeze({ stage: "discover", entryId: "memory-stage-entry", finishId: "memory-stage-finish" }),
|
|
16
|
+
compose: Object.freeze({ stage: "compose", entryId: "memory-stage-entry", finishId: "memory-stage-finish" }),
|
|
17
|
+
verify: Object.freeze({ stage: "verify", entryId: "memory-stage-entry", finishId: "memory-stage-finish" }),
|
|
18
|
+
review: Object.freeze({ stage: "review", entryId: "memory-stage-entry", finishId: "memory-stage-finish" }),
|
|
19
|
+
finish: Object.freeze({ stage: "finish", entryId: "memory-stage-entry", finishId: "memory-stage-finish" })
|
|
20
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function inspectDaemonOperation(root: string, id: string): Promise<Record<string, unknown>>;
|
|
@@ -8,6 +8,7 @@ import { errorRecord, isObservationLoss, isProvenShellCorrection, reportedError
|
|
|
8
8
|
import { assertDaemonOwnership, budgetObservationScope, releaseBudgetObservation, completeBudgetOperation } from "./managed-daemon.mjs";
|
|
9
9
|
import { readModelObservations, modelAttribution } from "./model-observations.mjs";
|
|
10
10
|
import { publishOperationProgress, publishOperationWaiting, withOperationProgress } from './operation-progress.mjs';
|
|
11
|
+
import { prepareDaemonRequest } from "./native-request-proof.mjs";
|
|
11
12
|
|
|
12
13
|
const productive = new Set(["session.create", "session.prompt", "session.start", "session.fork", "session.resume"]);
|
|
13
14
|
const controls = new Map();
|
|
@@ -301,7 +302,7 @@ export async function durableDaemonStart(options, action) {
|
|
|
301
302
|
// scope can reuse this exact adapter launch after retiring the old daemon.
|
|
302
303
|
const launch = { schema_id: "dd-flow/native-launch@1", executable: options.entryPath ?? null, args: process.argv.slice(2), cwd: process.cwd(), runtime_owner: process.env.DD_FLOW_RUNTIME_OWNER ?? null,
|
|
303
304
|
env: Object.fromEntries(["CODEX_HOME", "DD_FLOW_CONFIG_HOME", "DD_FLOW_HOME", "DD_FLOW_BIN", "DD_FLOW_RESOURCE_HOME"].map(key => [key, process.env[key] ?? null])) };
|
|
304
|
-
const request = { id: process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation: "daemon.start", params: { ...options, runtimeOwner: process.env.DD_FLOW_RUNTIME_OWNER ?? null, resourceHome: process.env.DD_FLOW_RESOURCE_HOME ?? null, launch } };
|
|
305
|
+
const request = prepareDaemonRequest({ id: process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation: "daemon.start", params: { ...options, runtimeOwner: process.env.DD_FLOW_RUNTIME_OWNER ?? null, resourceHome: process.env.DD_FLOW_RESOURCE_HOME ?? null, launch } });
|
|
305
306
|
return await journalDispatch(root, request, () => action(options));
|
|
306
307
|
}
|
|
307
308
|
|
|
@@ -314,13 +315,13 @@ async function journalDispatch(root, request, action) {
|
|
|
314
315
|
const daemon = await read(path.join(root, "daemon.json"));
|
|
315
316
|
const startup = request.operation === "daemon.start";
|
|
316
317
|
const daemonId = daemon?.daemon_id ?? daemon?.config?.daemonId ?? null;
|
|
317
|
-
await writeJsonAtomic(temporary, { schema_id: "dd-flow/daemon-operation@1", operation_id: request.id, operation: request.operation, session_id: request.params?.sessionId ?? null, daemon_id: startup ? null : daemonId, owner_id: daemon?.config?.runtime_owner?.owner_id ?? null, generation: dispatchGenerations.get(root) ?? 0, ...(startup ? { predecessor_daemon_id: daemonId, launch: request.params?.launch } : {}), params_sha256: fingerprint, requested_at: new Date().toISOString() });
|
|
318
|
+
await writeJsonAtomic(temporary, { schema_id: "dd-flow/daemon-operation@1", operation_id: request.id, operation: request.operation, session_id: request.params?.sessionId ?? null, daemon_id: startup ? null : daemonId, owner_id: daemon?.config?.runtime_owner?.owner_id ?? null, generation: dispatchGenerations.get(root) ?? 0, ...(startup ? { predecessor_daemon_id: daemonId, launch: request.params?.launch } : {}), params_sha256: fingerprint, ...(request.invocation_sha256 ? { invocation_sha256: request.invocation_sha256 } : {}), requested_at: new Date().toISOString() });
|
|
318
319
|
try {
|
|
319
320
|
await link(temporary, path.join(directory, "requested.json"));
|
|
320
321
|
} catch (error) {
|
|
321
322
|
if (error.code !== "EEXIST") throw error;
|
|
322
323
|
const saved = await inspectDaemonOperation(root, request.id);
|
|
323
|
-
if (saved.params_sha256 !== fingerprint) throw Object.assign(new Error("operation id was reused with different parameters"), { code: "operation_conflict", details: { operation_id: request.id } });
|
|
324
|
+
if (saved.params_sha256 !== fingerprint || (saved.invocation_sha256 ?? null) !== (request.invocation_sha256 ?? null)) throw Object.assign(new Error("operation id was reused with different parameters or invocation"), { code: "operation_conflict", details: { operation_id: request.id } });
|
|
324
325
|
if (saved.state === "completed") return saved.result;
|
|
325
326
|
if (["failed", "interrupted"].includes(saved.state)) throw reportedError(saved.error, "provider operation failed");
|
|
326
327
|
throw Object.assign(new Error("provider operation has no confirmed terminal result; inspect the existing operation instead of resending it"), { code: "operation_observation_lost", details: { operation_id: request.id, receipt_directory: directory } });
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { managedFlowEnv } from './managed-flow-env.mjs';
|
|
1
2
|
import { SETUP_STARTUP_MS, startupObserver, observationDetails } from './setup-progress.mjs';
|
|
2
3
|
import { callDaemonObserved } from './daemon-observation.mjs';
|
|
3
4
|
import { operationProgressReporter } from './operation-progress.mjs';
|
|
5
|
+
import { prepareDaemonRequest } from "./native-request-proof.mjs";
|
|
4
6
|
import { captureDispatchGuard, cancelPendingDispatch } from "./dispatch-fence.mjs";
|
|
5
|
-
import { errorRecord } from "./operation-errors.mjs";
|
|
7
|
+
import { errorRecord, isProvenShellCorrection } from "./operation-errors.mjs";
|
|
6
8
|
import { ToolObservations, agyToolObservation, agyTranscriptObservations } from "./tool-observations.mjs";
|
|
7
9
|
import { constants } from "node:fs";
|
|
8
10
|
import { fileURLToPath } from "node:url";
|
|
@@ -18,6 +20,7 @@ import { durableDaemonDispatch, completeDaemonShutdown, assertDaemonDispatch, as
|
|
|
18
20
|
import path from "node:path";
|
|
19
21
|
import { observeModel } from "./model-observations.mjs";
|
|
20
22
|
import { AGY_VERSION_TIMEOUT_MS, AgyError, agyTerminalFailure, assertProfile, executable, observedProfile, runAgy, usageSnapshot } from "./dd-agy.mjs";
|
|
23
|
+
import { settledNativeTree } from "./native-children.mjs";
|
|
21
24
|
import { prepareRuntimeOwner, cleanupFailedStart, cleanupFailedDaemonStart, confirmDaemonProcess, confirmDaemonStopped, finishDaemonProcess, scheduleDaemonProcessHeartbeat, registerDaemonProcess, stopProcessGroup } from "./managed-daemon.mjs";
|
|
22
25
|
import { readNativeLines, streamNativeDiagnostics, nativeObservationError, admitNativeRequestBuffer } from "./native-streams.mjs";
|
|
23
26
|
|
|
@@ -58,7 +61,7 @@ async function writeJson(file, value) { const temporary = `${file}.${process.pid
|
|
|
58
61
|
async function readState(dir) { try { return JSON.parse(await readFile(locations(dir).state, "utf8")); } catch (error) { if (error.code === "ENOENT") return null; throw error; } }
|
|
59
62
|
async function removeSocket(paths) { try { if (!(await lstat(paths.socket)).isSocket()) throw new DaemonError("unsafe_socket", "refusing to replace a non-socket daemon path"); await unlink(paths.socket); } catch (error) { if (error.code !== "ENOENT") throw error; } }
|
|
60
63
|
const shell = value => `'${String(value).replaceAll("'", `'"'"'`)}'`;
|
|
61
|
-
export function sanitizedEnv(config) { const env = { ...process.env, TMPDIR: config.temporary, DD_AGY_HOOK_NODE: process.execPath, DD_AGY_HOOK_ENTRY: config.entryPath, DD_AGY_STATE_DIR: config.stateDir, DD_AGY_DAEMON_ID: config.daemonId }; for (const key of ["GEMINI_API_KEY","GOOGLE_API_KEY","ANTHROPIC_API_KEY","OPENAI_API_KEY"
|
|
64
|
+
export function sanitizedEnv(config) { const env = { ...process.env, TMPDIR: config.temporary, DD_AGY_HOOK_NODE: process.execPath, DD_AGY_HOOK_ENTRY: config.entryPath, DD_AGY_STATE_DIR: config.stateDir, DD_AGY_DAEMON_ID: config.daemonId }; for (const key of ["GEMINI_API_KEY","GOOGLE_API_KEY","ANTHROPIC_API_KEY","OPENAI_API_KEY"]) env[key] = undefined; return { ...env, ...managedFlowEnv(config) }; }
|
|
62
65
|
const errorPayload = errorRecord;
|
|
63
66
|
async function forwardUsage(config, sessionId, result, tools, descendants) {
|
|
64
67
|
if (!config.ddFlowBin || !config.projectRoot) return;
|
|
@@ -164,7 +167,7 @@ export async function qualifyAgyHooks(projectRoot, { stateDir = null, install =
|
|
|
164
167
|
}
|
|
165
168
|
|
|
166
169
|
export async function callDaemon(stateDir, operation, params = {}, timeoutMs = 30_000, requestId = null) {
|
|
167
|
-
const request = { schema_id: REQUEST_SCHEMA, id: requestId ?? process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation, params };
|
|
170
|
+
const request = prepareDaemonRequest({ schema_id: REQUEST_SCHEMA, id: requestId ?? process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation, params });
|
|
168
171
|
return await callDaemonObserved({ stateDir, socket: locations(stateDir).socket, request, responseSchema: RESPONSE_SCHEMA, harness: 'agy', timeoutMs });
|
|
169
172
|
}
|
|
170
173
|
|
|
@@ -339,7 +342,9 @@ export class Runtime {
|
|
|
339
342
|
if (!this.init) this.startupError ??= agyTerminalFailure(event.result, event.terminal_metadata);
|
|
340
343
|
this.receivedTerminalMetadata = event.terminal_metadata;
|
|
341
344
|
}
|
|
342
|
-
this.observeProviderActivity(event);
|
|
345
|
+
this.observeProviderActivity(event);
|
|
346
|
+
if (event.event === "result" && this.init && !this.startupError) { await this.finishTurn(event.result ?? {}, event.terminal_metadata, event); continue; }
|
|
347
|
+
await this.journal("provider_event", { event }); if (event.event === "init") { this.init = { conversation_id: event.conversation_id, ...(event.init ?? {}) }; if (!this.init.conversation_id) throw new DaemonError("agy_init_missing", "Antigravity init has no conversation ID"); const requested = { provider: this.config.provider, model: this.config.model, reasoning: this.config.reasoning, mode: this.config.mode, permission_mode: "always-proceed" }; this.profile = assertProfile(requested, observedProfile(this.init, requested)); await observeModel({ journal: this.config.journal, harness: "antigravity-cli", sessionId: this.init.conversation_id, requested, observed: this.profile.observed, source: "native.init" }); await this.persist({ shutdown_state: "running", active_tree: false }); readyResolve(this.init); } else if (event.event === "step_update") this.observeStep(event.step_update ?? {}); else if (event.event === "result") { if (this.startupError) throw this.startupError; await this.finishTurn(event.result ?? {}); } } }
|
|
343
348
|
observeStep(step) {
|
|
344
349
|
const sessionId = step.conversation_id ?? this.init?.conversation_id, observation = this.sessionObservations.get(sessionId) ?? {};
|
|
345
350
|
const fresh = Number.isInteger(step.step_index) && step.step_index > (observation.last_step_index ?? -1) && step.step_index > (observation.step_floor ?? -1);
|
|
@@ -376,7 +381,7 @@ export class Runtime {
|
|
|
376
381
|
}
|
|
377
382
|
}
|
|
378
383
|
}
|
|
379
|
-
async finishTurn(result, retainedMetadata = null) {
|
|
384
|
+
async finishTurn(result, retainedMetadata = null, providerEvent = null) {
|
|
380
385
|
if (result.status === "RUNNING") { await this.persist({ active_tree: true }); return; }
|
|
381
386
|
if (!["SUCCESS", "ERROR", "CANCELLED"].includes(result.status)) throw new DaemonError("agy_terminal_result_invalid", "Antigravity result has no recognized terminal status", false, { provider_result: result });
|
|
382
387
|
if (result.conversation_id && result.conversation_id !== this.init?.conversation_id) {
|
|
@@ -389,40 +394,51 @@ export class Runtime {
|
|
|
389
394
|
return;
|
|
390
395
|
}
|
|
391
396
|
const current = this.active;
|
|
392
|
-
const terminalMetadata = retainedMetadata ?? this.receivedTerminalMetadata ?? (this.lastTerminalFailure && this.lastTerminalFailure.details?.provider_result?.error === result.error
|
|
397
|
+
const terminalMetadata = { received_at: new Date().toISOString(), ...(retainedMetadata ?? this.receivedTerminalMetadata ?? (this.lastTerminalFailure && this.lastTerminalFailure.details?.provider_result?.error === result.error
|
|
393
398
|
&& this.lastTerminalFailure.details.provider_session_id === (result.conversation_id || this.init?.conversation_id || null)
|
|
394
399
|
&& (current?.previousError === result.error || this.lastResult?.status === "ERROR" && this.lastResult.error === result.error) ? this.lastTerminalFailure.details
|
|
395
400
|
: { observed_at: new Date().toISOString(), provider_session_id: result.conversation_id || this.init?.conversation_id || null, operation_id: current?.operationId ?? null,
|
|
396
|
-
turn_generation: current?.generation ?? null, journal_locator: this.paths.journal, native_source: "agy.result" });
|
|
401
|
+
turn_generation: current?.generation ?? null, journal_locator: this.paths.journal, native_source: "agy.result" })) };
|
|
397
402
|
this.receivedTerminalMetadata = null;
|
|
398
403
|
// The ordered stream returns one result per input. Model usage counters
|
|
399
404
|
// are not request IDs: native command rejections can report zero turns.
|
|
400
405
|
// prompt() drains earlier events before accepting another input.
|
|
401
406
|
if (!current && this.lastResult) { await this.journal("stale_terminal_observed", { result }); return; }
|
|
402
|
-
await this.captureChildTools();
|
|
403
407
|
this.lastResult = result; this.markTerminalActivity(result);
|
|
404
408
|
const rootStop = this.sessionObservations.get(this.init?.conversation_id)?.stop;
|
|
405
409
|
const pendingTerminal = current && result.status === "SUCCESS";
|
|
406
|
-
if (
|
|
410
|
+
if (current) { current.terminalResult = result; current.terminalMetadata = terminalMetadata; current.terminalPersisted = false; }
|
|
407
411
|
if (pendingTerminal && rootStop?.fullyIdle === true) for (const [id, descendant] of this.descendants) if (descendant.status === "unknown") this.descendants.set(id, { ...descendant, status: "settled_by_root", settlement_evidence: "root_fully_idle_stop" });
|
|
408
|
-
|
|
409
|
-
|
|
412
|
+
this.state.terminal_observation_pending = true;
|
|
413
|
+
try {
|
|
414
|
+
await this.persist({ active_tree: true, last_result: result, last_terminal_metadata: terminalMetadata });
|
|
415
|
+
if (current) current.terminalPersisted = true;
|
|
416
|
+
if (providerEvent) await this.journal("provider_event", { event: providerEvent });
|
|
417
|
+
await this.captureChildTools();
|
|
418
|
+
} catch (error) { return this.failTerminalObservation(current, result, terminalMetadata, error); }
|
|
410
419
|
try { this.usageIngest = await forwardUsage(this.config, result.conversation_id ?? this.init.conversation_id, result, this.toolSnapshot(), [...this.descendants.values()]); }
|
|
411
|
-
catch (error) { this.usageIngest = { status: "failed", error: error.message ?? String(error) }; await this.journal("usage_ingest_failed", this.usageIngest); }
|
|
420
|
+
catch (error) { this.usageIngest = { status: "failed", error: error.message ?? String(error) }; try { await this.journal("usage_ingest_failed", this.usageIngest); } catch (storage) { return this.failTerminalObservation(current, result, terminalMetadata, storage); } }
|
|
421
|
+
try { await this.persist({ terminal_observation_pending: false }); }
|
|
422
|
+
catch (error) { this.state.terminal_observation_pending = true; return this.failTerminalObservation(current, result, terminalMetadata, error); }
|
|
423
|
+
this.state.terminal_observation_pending = false;
|
|
412
424
|
if (!current) return;
|
|
413
425
|
if (this.active !== current) return;
|
|
414
426
|
if (result.status === "ERROR" || result.status === "CANCELLED") {
|
|
415
427
|
this.active = null;
|
|
416
|
-
|
|
417
|
-
|
|
428
|
+
const settled = this.receipt().settled;
|
|
429
|
+
this.lastTerminalFailure = agyTerminalFailure(result, { ...terminalMetadata, native_turn_items: { observed: settled, possible_effects: true, pending: !settled }, provider_error_scope: current.previousError && current.previousError === result.error ? "repeated_conversation_error" : "terminal_result", usage_ingest: this.usageIngest });
|
|
430
|
+
try { await this.persist({ active_tree: !settled, last_terminal_failure: errorRecord(this.lastTerminalFailure) }); }
|
|
431
|
+
catch (error) { return this.failTerminalObservation(current, result, terminalMetadata, error); }
|
|
418
432
|
return current.reject(this.lastTerminalFailure);
|
|
419
433
|
}
|
|
420
|
-
await this.completePendingTurn();
|
|
434
|
+
try { await this.completePendingTurn(); }
|
|
435
|
+
catch (error) { return this.failTerminalObservation(current, result, terminalMetadata, error); }
|
|
421
436
|
}
|
|
422
437
|
async completePendingTurn() {
|
|
423
438
|
await this.observeHookFailures();
|
|
424
439
|
const current = this.active;
|
|
425
|
-
if (
|
|
440
|
+
if (current?.observationError) throw current.observationError;
|
|
441
|
+
if (current?.terminalResult?.status !== "SUCCESS" || current.terminalResult !== this.lastResult) return;
|
|
426
442
|
await this.persist({ active_tree: !this.receipt().settled });
|
|
427
443
|
// Hooks can invalidate the tree while persistence is pending. Never
|
|
428
444
|
// publish a proof captured before that asynchronous boundary.
|
|
@@ -432,9 +448,20 @@ export class Runtime {
|
|
|
432
448
|
this.active = null;
|
|
433
449
|
current.resolve(receipt);
|
|
434
450
|
}
|
|
451
|
+
failTerminalObservation(current, result, metadata, cause) {
|
|
452
|
+
this.state.terminal_observation_pending = true;
|
|
453
|
+
const details = { ...metadata, native_outcome: result, settled: false, terminal_persisted: current?.terminalPersisted === true, observation_error: errorRecord(cause), native_turn_items: { observed: false, possible_effects: true, pending: true } };
|
|
454
|
+
const error = ["ERROR", "CANCELLED"].includes(result.status)
|
|
455
|
+
? agyTerminalFailure(result, details)
|
|
456
|
+
: new DaemonError("native_outcome_observation_failed", "Antigravity terminal was received but mandatory observation failed", false, details);
|
|
457
|
+
error.cause = cause;
|
|
458
|
+
if (result.status !== "SUCCESS") this.lastTerminalFailure = error;
|
|
459
|
+
if (current) { current.observationError = error; current.reject(error); }
|
|
460
|
+
throw error;
|
|
461
|
+
}
|
|
435
462
|
receipt(result = this.lastResult) {
|
|
436
463
|
if (this.state.last_terminal_failure && !this.lastTerminalFailure) this.lastTerminalFailure = this.state.last_terminal_failure;
|
|
437
|
-
const terminalMetadata = this.lastTerminalFailure && this.lastTerminalFailure.details?.provider_result?.error === result?.error
|
|
464
|
+
const terminalMetadata = this.active?.terminalResult === result ? this.active.terminalMetadata : this.state.last_result === result ? this.state.last_terminal_metadata : this.lastTerminalFailure && this.lastTerminalFailure.details?.provider_result?.error === result?.error
|
|
438
465
|
&& this.lastTerminalFailure.details.provider_session_id === (result?.conversation_id || this.init?.conversation_id || null) ? this.lastTerminalFailure.details : null;
|
|
439
466
|
const assistantText = typeof result?.response === "string" ? result.response : typeof result?.text === "string" ? result.text : null;
|
|
440
467
|
const root = this.init?.conversation_id; const observation = this.sessionObservations.get(root);
|
|
@@ -444,7 +471,8 @@ export class Runtime {
|
|
|
444
471
|
// non-idle Stop still wins, and every discovered child must be terminal.
|
|
445
472
|
const rootSettled = observation?.stop?.fullyIdle !== false;
|
|
446
473
|
const terminalPending = this.active?.terminalResult === result;
|
|
447
|
-
|
|
474
|
+
const settled = Boolean(!this.state.terminal_observation_pending && !this.active?.observationError && !this.state.unclaimed_activity && (!this.active || terminalPending) && result && ["SUCCESS", "ERROR", "CANCELLED"].includes(result.status) && treeSettled && rootSettled);
|
|
475
|
+
return { harness: "antigravity-cli", runtime_family: "antigravity", provider_session_id: root ?? null, adapter_session_id: root ?? null, cwd: this.config.cwd, profile: this.profile, result, ...(terminalMetadata ? { terminal_metadata: terminalMetadata, ...(terminalMetadata.turn_id ? { terminal_turn_id: terminalMetadata.turn_id } : {}) } : {}), ...(assistantText === null ? {} : { assistant_text: assistantText }), usage: usageSnapshot(result ?? {}, this.toolSnapshot()), usage_ingest: this.usageIngest, descendants: [...this.descendants.values()], ...settledNativeTree(root, [...this.descendants.values()], settled, !this.state.unclaimed_activity && (!this.active || terminalPending) && rootSettled && ["SUCCESS", "ERROR", "CANCELLED"].includes(result?.status)), transcript_path: observation?.transcript_path ?? null, settled };
|
|
448
476
|
}
|
|
449
477
|
async zeroUsage() { await forwardUsage(this.config, this.init.conversation_id, { usage: {} }, this.toolSnapshot(), []); }
|
|
450
478
|
async prompt(text, assertDispatch = captureDispatchGuard(this), operationId = null, livenessTimeoutMs = 1_800_000) {
|
|
@@ -498,9 +526,14 @@ export class Runtime {
|
|
|
498
526
|
checking = true; const cursor = this.progress?.cursor;
|
|
499
527
|
void this.completePendingTurn().then(() => {
|
|
500
528
|
if (this.active !== current || this.progress?.cursor !== cursor || !clock.sample(this.progress)) return;
|
|
529
|
+
if (current.terminalResult) return this.failTerminalObservation(current, current.terminalResult, current.terminalMetadata, new Error("Native tree settlement was not confirmed within the productive silence window"));
|
|
501
530
|
current.reject(new DaemonError("operation_observation_lost", "Antigravity native outcome is unknown after the productive silence window", true, { operation_id: operationId, turn_generation: current.generation, native_outcome: "unknown", last_activity_at: this.lastActivityAt ?? null }));
|
|
502
531
|
}).catch(error => {
|
|
503
|
-
if (this.active === current && this.progress?.cursor === cursor)
|
|
532
|
+
if (this.active === current && this.progress?.cursor === cursor) {
|
|
533
|
+
if (current.observationError) current.reject(current.observationError);
|
|
534
|
+
else if (current.terminalResult) { try { this.failTerminalObservation(current, current.terminalResult, current.terminalMetadata, error); } catch { /* reply owns the typed failure */ } }
|
|
535
|
+
else current.reject(new DaemonError("operation_observation_lost", "Antigravity quiet reconciliation could not confirm the native outcome", true, { operation_id: operationId, turn_generation: current.generation, native_outcome: "unknown", observation_error: errorRecord(error) }));
|
|
536
|
+
}
|
|
504
537
|
}).finally(() => { checking = false; });
|
|
505
538
|
}, Math.max(10, Math.min(1_000, livenessTimeoutMs / 4)));
|
|
506
539
|
try {
|
|
@@ -536,9 +569,7 @@ export class Runtime {
|
|
|
536
569
|
}
|
|
537
570
|
async rejectHook(error, event, payload, current = this.active) {
|
|
538
571
|
if (current && this.active !== current) return;
|
|
539
|
-
const correctable = current && event === "PreToolUse" && error
|
|
540
|
-
&& error.details?.effect === "no_effect" && error.details?.recoverable === true
|
|
541
|
-
&& error.details?.disposition === "pre_cli_shell_refusal" && error.details?.native_pre_cli_refusal === true;
|
|
572
|
+
const correctable = current && event === "PreToolUse" && isProvenShellCorrection(error);
|
|
542
573
|
if (correctable && current.hookCorrectionGeneration !== current.generation) {
|
|
543
574
|
// The request was correlated with this still-active Turn by
|
|
544
575
|
// observeHookFailures. Persist before allowing native same-Turn recovery.
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import { SETUP_STARTUP_MS } from './setup-progress.mjs';
|
|
5
5
|
|
|
6
6
|
import { checkObservedProfile } from "./model-observations.mjs";
|
|
7
|
+
import { classifyProviderError, safeProviderError } from "./provider-overload-policy.mjs";
|
|
7
8
|
|
|
8
9
|
const DEFAULT_MODEL = "gemini-3.1-pro-high";
|
|
9
10
|
export const AGY_VERSION_TIMEOUT_MS = 30_000;
|
|
@@ -13,11 +14,21 @@ export class AgyError extends Error {
|
|
|
13
14
|
}
|
|
14
15
|
|
|
15
16
|
export function agyTerminalFailure(result, metadata = {}) {
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
const native = typeof result.error === "object" && result.error ? result.error : { message: result.error ?? "Antigravity returned ERROR" };
|
|
18
|
+
const category = classifyProviderError(native);
|
|
19
|
+
const legacy = { provider_quota_exhausted: "agy_provider_quota_exhausted", provider_limit_unknown: "agy_provider_limit_unknown", provider_auth_failed: "agy_provider_account", provider_failed: "agy_provider_failed" };
|
|
20
|
+
let code = result.status === "CANCELLED" ? "agy_turn_cancelled" : legacy[category] ?? category;
|
|
21
|
+
// A local generation/usage count is not a native request identity.
|
|
22
|
+
const identity = result.turn_id ?? result.request_id;
|
|
23
|
+
const turn = typeof identity === "string" && identity ? identity : null;
|
|
24
|
+
const proofMissing = result.status === "ERROR" && ["provider_capacity_transient", "provider_rate_limited"].includes(category) && !turn;
|
|
25
|
+
if (proofMissing) code = "provider_overload_evidence_unavailable";
|
|
26
|
+
return new AgyError(code, String(native.message ?? "Antigravity returned ERROR"), code === "provider_capacity_transient" || code === "provider_rate_limited", {
|
|
27
|
+
provider_result: result, ...metadata, provider_error: safeProviderError(native), native_source: "agy.result", terminal_status: result.status === "ERROR" ? "failed" : "cancelled",
|
|
28
|
+
...(turn ? { turn_id: turn, native_turn_id: turn } : {}),
|
|
29
|
+
...(proofMissing ? { provider_category: category, reason: "native_turn_identity_unavailable" } : {}),
|
|
30
|
+
will_retry: native.willRetry === true, native_retry_active: native.willRetry === true
|
|
31
|
+
});
|
|
21
32
|
}
|
|
22
33
|
|
|
23
34
|
export function executable(bin, args = []) {
|
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
import { managedFlowEnv } from './managed-flow-env.mjs';
|
|
1
2
|
import { SETUP_STARTUP_MS, startupObserver, observationDetails } from './setup-progress.mjs';
|
|
2
3
|
import { callDaemonObserved } from './daemon-observation.mjs';
|
|
3
4
|
import { admitNativeRequestBuffer } from "./native-streams.mjs";
|
|
5
|
+
import { prepareDaemonRequest } from "./native-request-proof.mjs";
|
|
4
6
|
import { captureDispatchGuard, cancelPendingDispatch } from "./dispatch-fence.mjs";
|
|
5
7
|
import { createHash, randomUUID } from "node:crypto";
|
|
6
8
|
import { chmod, lstat, mkdir, open, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
7
9
|
import net from "node:net";
|
|
8
10
|
import { durableDaemonDispatch, completeDaemonShutdown, assertDaemonDispatch, assertDaemonRestartable, trackDaemonConnections, retireDaemonEndpoint, retireFailedDaemon } from "./daemon-operations.mjs";
|
|
9
11
|
import { ObservationClock } from "./observation-clock.mjs";
|
|
10
|
-
import { parseCapacityOperation } from "./
|
|
12
|
+
import { parseCapacityOperation } from "./provider-overload-policy.mjs";
|
|
11
13
|
import path from "node:path";
|
|
12
14
|
import { spawn } from "node:child_process";
|
|
13
15
|
import { waitForSettlement } from "./session-settlement.mjs";
|
|
14
16
|
import { errorRecord } from "./operation-errors.mjs";
|
|
15
|
-
import { CodexBridge, cancelSessionWithBridge, createSessionWithBridge, inspectSessionWithBridge, promptSessionWithBridge, startSessionWithBridge } from "./dd-codex.mjs";
|
|
17
|
+
import { CODEX_REQUEST_TIMEOUT_MS, LATE_RESPONSE_GRACE_MS, CodexBridge, cancelSessionWithBridge, createSessionWithBridge, inspectSessionWithBridge, promptSessionWithBridge, startSessionWithBridge } from "./dd-codex.mjs";
|
|
16
18
|
import { assertDaemonOwnership, prepareRuntimeOwner, cleanupFailedDaemonStart, confirmDaemonProcess, confirmDaemonStopped, finishDaemonProcess, scheduleDaemonProcessHeartbeat, registerDaemonProcess, startManagedBridge, stopProcessGroup } from "./managed-daemon.mjs";
|
|
17
19
|
|
|
20
|
+
export function codexBridgeEnv(config, daemonId) { return { ...config.env, ...managedFlowEnv(config, daemonId) }; }
|
|
21
|
+
|
|
18
22
|
const requestSchema = "dd-codex/daemon-request@1";
|
|
19
23
|
const responseSchema = "dd-codex/daemon-response@1";
|
|
20
24
|
const stateSchema = "dd-codex/daemon-state@1";
|
|
@@ -72,13 +76,15 @@ export async function cancelCodexTree(bridge, options, { remember = () => {}, ac
|
|
|
72
76
|
return { harness: "codex-desktop", provider_session_id: options.sessionId, adapter_session_id: options.sessionId, cancelled: true, settled: true, tree_session_ids: [...sessions], cleanup_errors: settlement.cleanup_errors, tree_observations: settlement.observations.map(item => ({ provider_session_id: item.provider_session_id, status: item.status, settled: item.settled })) };
|
|
73
77
|
}
|
|
74
78
|
|
|
75
|
-
export async function callDaemon(stateDir, operation, params = {}, timeoutMs = 30_000) {
|
|
76
|
-
const request = { schema_id: requestSchema, id: process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation, params };
|
|
79
|
+
export async function callDaemon(stateDir, operation, params = {}, timeoutMs = operation === "session.create" ? params.timeoutMs ?? CODEX_REQUEST_TIMEOUT_MS + LATE_RESPONSE_GRACE_MS : 30_000) {
|
|
80
|
+
const request = prepareDaemonRequest({ schema_id: requestSchema, id: process.env.DD_EVAL_OPERATION_ID ?? randomUUID(), operation, params });
|
|
77
81
|
return await callDaemonObserved({ stateDir, socket: locations(stateDir).socket, request, responseSchema: responseSchema, harness: 'codex', timeoutMs });
|
|
78
82
|
}
|
|
79
83
|
|
|
80
84
|
export async function startDaemon(options) {
|
|
81
|
-
|
|
85
|
+
if (!options.noFlow && Boolean(options.ddFlowHome) !== Boolean(options.ddFlowBin)) throw Object.assign(new Error("--dd-flow-home and --dd-flow-bin must be provided together"), { code: "flow_context_incomplete" });
|
|
86
|
+
if (options.noFlow) options = { ...options, ddFlowHome: undefined, ddFlowBin: undefined };
|
|
87
|
+
const paths = locations(options.stateDir); const cwd = absolute(options.cwd, "--cwd"); const config = { cwd, journal: absolute(options.journal, "--journal"), bin: options.bin ?? null, ddFlowBin: options.ddFlowBin ? absolute(options.ddFlowBin, "--dd-flow-bin") : null, ddFlowHome: options.ddFlowHome ? absolute(options.ddFlowHome, "--dd-flow-home") : null, projectRoot: options.projectRoot ? absolute(options.projectRoot, "--project-root") : cwd, resourceHome: !options.noFlow && process.env.DD_FLOW_RESOURCE_HOME ? absolute(process.env.DD_FLOW_RESOURCE_HOME, "DD_FLOW_RESOURCE_HOME") : null, env: options.ddFlowHome ? { DD_FLOW_HOME: absolute(options.ddFlowHome, "--dd-flow-home"), ...(options.ddFlowBin ? { DD_FLOW_BIN: absolute(options.ddFlowBin, "--dd-flow-bin") } : {}) } : {} };
|
|
82
88
|
await prepareRuntimeOwner(config, paths.dir);
|
|
83
89
|
await mkdir(paths.dir, { recursive: true, mode: 0o700 }); await chmod(paths.dir, 0o700);
|
|
84
90
|
let previous = await readState(paths.state); assertDaemonRestartable(previous);
|
|
@@ -95,7 +101,7 @@ export async function stopDaemon(options) { const timeoutMs = options.timeoutMs
|
|
|
95
101
|
|
|
96
102
|
export async function serveDaemon(stateDir) {
|
|
97
103
|
const paths = locations(stateDir); const state = await readState(paths.state); if (!state || state.schema_id !== stateSchema) throw Object.assign(new Error("daemon state missing"), { code: "daemon_state_missing" });
|
|
98
|
-
const bridge = new CodexBridge({ ...state.config, env: { ...state.config.
|
|
104
|
+
const bridge = new CodexBridge({ ...state.config, env: { ...codexBridgeEnv(state.config, state.daemon_id), CODEX_HOME: process.env.CODEX_HOME, DD_FLOW_CODEX_STATE_DIR: paths.dir } }); await startManagedBridge({ config: state.config, state, bridge, kind: "codex-provider", publish: snapshot => writeState(paths.state, snapshot) }); const sessions = new Set(state.sessions ?? []); let active = null; let server; let persist = Promise.resolve();
|
|
99
105
|
scheduleDaemonProcessHeartbeat(state.config, state.resource_process);
|
|
100
106
|
const save = (patch = {}) => { Object.assign(state, patch, { pid: process.pid, updated_at: new Date().toISOString(), sessions: [...sessions] }); const snapshot = structuredClone(state); persist = persist.catch(() => {}).then(() => writeState(paths.state, snapshot)); return persist; };
|
|
101
107
|
const dispatch = async (operation, params, operationId) => {
|