@deksden-com/dd-flow-cli 0.9.0-beta.134 → 0.9.0-beta.136

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.
Files changed (161) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +33 -0
  3. package/dist/build-info.json +7 -7
  4. package/dist/cli/command-inputs.js +1 -0
  5. package/dist/cli/command-metadata.js +144 -0
  6. package/dist/cli/command-option-descriptions.js +186 -0
  7. package/dist/cli/completion-cli.js +70 -0
  8. package/dist/cli/completion.js +57 -0
  9. package/dist/cli/error-output.js +52 -0
  10. package/dist/cli/executor-onboarding.js +71 -0
  11. package/dist/cli/harnesses.js +84 -0
  12. package/dist/cli/models.js +39 -0
  13. package/dist/cli/operator-profiles.js +61 -0
  14. package/dist/cli/output-options.js +35 -0
  15. package/dist/cli/response-file.js +69 -0
  16. package/dist/cli/run-cli.js +5 -0
  17. package/dist/cli/setup.js +147 -0
  18. package/dist/harness-runtime/OPENCODE-LICENSE.txt +24 -0
  19. package/dist/harness-runtime/bin/dd-opencode.mjs +1 -1
  20. package/dist/harness-runtime/lib/codex-capacity-policy.mjs +13 -0
  21. package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +193 -39
  22. package/dist/harness-runtime/lib/dd-opencode.mjs +295 -100
  23. package/dist/harness-runtime/lib/delegation-instructions.mjs +3 -3
  24. package/dist/harness-runtime/lib/managed-daemon.mjs +1 -1
  25. package/dist/harness-runtime/lib/native-hook-command.d.mts +2 -2
  26. package/dist/harness-runtime/lib/native-hook-command.mjs +4 -4
  27. package/dist/harness-runtime/lib/opencode-plugin.mjs +60 -0
  28. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-1y4a697q.js +81 -0
  29. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-2ny4vxct.js +92 -0
  30. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-6mptkzbc.js +0 -0
  31. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-7x67cf1q.js +52 -0
  32. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9rqn6x4v.js +16 -0
  33. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-9vdz0zwn.js +1661 -0
  34. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ecs5ftka.js +1466 -0
  35. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-frbwqjmf.js +145 -0
  36. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gne7h7mq.js +50 -0
  37. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-gx9wnkzr.js +105 -0
  38. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-m2eywc8w.js +0 -0
  39. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-nwcpakzx.js +12 -0
  40. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-q4g3afnw.js +623 -0
  41. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-qav6mfdz.js +0 -0
  42. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-sxt88q69.js +12 -0
  43. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-t1xa31vm.js +39 -0
  44. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ve4aws36.js +103 -0
  45. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vmytr4q8.js +4 -0
  46. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vt9jbch8.js +36 -0
  47. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-vyas3vgt.js +0 -0
  48. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-wjyeq25y.js +30 -0
  49. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-xgnj2w4v.js +20 -0
  50. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-y2etg5bs.js +9 -0
  51. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-ydhz1zrh.js +238 -0
  52. package/dist/harness-runtime/vendor/opencode-client/chunks/service-probe-z6qdwcsf.js +62 -0
  53. package/dist/harness-runtime/vendor/opencode-client/contract.d.ts +1 -0
  54. package/dist/harness-runtime/vendor/opencode-client/contract.js +12 -0
  55. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.d.ts +2806 -0
  56. package/dist/harness-runtime/vendor/opencode-client/effect/api/api.js +0 -0
  57. package/dist/harness-runtime/vendor/opencode-client/effect/api.d.ts +4 -0
  58. package/dist/harness-runtime/vendor/opencode-client/effect/api.js +0 -0
  59. package/dist/harness-runtime/vendor/opencode-client/effect/client.d.ts +2530 -0
  60. package/dist/harness-runtime/vendor/opencode-client/effect/client.js +15 -0
  61. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.d.ts +7 -0
  62. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client-error.js +6 -0
  63. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.d.ts +2529 -0
  64. package/dist/harness-runtime/vendor/opencode-client/effect/generated/client.js +8 -0
  65. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.d.ts +2 -0
  66. package/dist/harness-runtime/vendor/opencode-client/effect/generated/index.js +12 -0
  67. package/dist/harness-runtime/vendor/opencode-client/effect/index.d.ts +35 -0
  68. package/dist/harness-runtime/vendor/opencode-client/effect/index.js +75 -0
  69. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.d.ts +20 -0
  70. package/dist/harness-runtime/vendor/opencode-client/effect/rpc.js +11 -0
  71. package/dist/harness-runtime/vendor/opencode-client/effect/service.d.ts +90 -0
  72. package/dist/harness-runtime/vendor/opencode-client/effect/service.js +187 -0
  73. package/dist/harness-runtime/vendor/opencode-client/package.json +84 -0
  74. package/dist/harness-runtime/vendor/opencode-client/promise/api.d.ts +21 -0
  75. package/dist/harness-runtime/vendor/opencode-client/promise/api.js +0 -0
  76. package/dist/harness-runtime/vendor/opencode-client/promise/client.d.ts +252 -0
  77. package/dist/harness-runtime/vendor/opencode-client/promise/client.js +14 -0
  78. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.d.ts +8 -0
  79. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client-error.js +6 -0
  80. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.d.ts +259 -0
  81. package/dist/harness-runtime/vendor/opencode-client/promise/generated/client.js +7 -0
  82. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.d.ts +3 -0
  83. package/dist/harness-runtime/vendor/opencode-client/promise/generated/index.js +79 -0
  84. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.d.ts +8932 -0
  85. package/dist/harness-runtime/vendor/opencode-client/promise/generated/types.js +70 -0
  86. package/dist/harness-runtime/vendor/opencode-client/promise/index.d.ts +6 -0
  87. package/dist/harness-runtime/vendor/opencode-client/promise/index.js +83 -0
  88. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.d.ts +32 -0
  89. package/dist/harness-runtime/vendor/opencode-client/promise/rpc.js +7 -0
  90. package/dist/harness-runtime/vendor/opencode-client/promise/service.d.ts +24 -0
  91. package/dist/harness-runtime/vendor/opencode-client/promise/service.js +187 -0
  92. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.d.ts +12 -0
  93. package/dist/harness-runtime/vendor/opencode-client/pty-handoff.js +14 -0
  94. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.d.ts +20 -0
  95. package/dist/harness-runtime/vendor/opencode-client/rpc-runtime.js +14 -0
  96. package/dist/harness-runtime/vendor/opencode-client/service-contender.d.ts +37 -0
  97. package/dist/harness-runtime/vendor/opencode-client/service-contender.js +10 -0
  98. package/dist/harness-runtime/vendor/opencode-client/service-probe.d.ts +70 -0
  99. package/dist/harness-runtime/vendor/opencode-client/service-probe.js +16 -0
  100. package/dist/harness-runtime/vendor/opencode-client/service-timing.d.ts +12 -0
  101. package/dist/harness-runtime/vendor/opencode-client/service-timing.js +10 -0
  102. package/dist/harness-runtime/vendor/opencode-client/service-version.d.ts +2 -0
  103. package/dist/harness-runtime/vendor/opencode-client/service-version.js +6 -0
  104. package/dist/harness-runtime/vendor/opencode-client/service.d.ts +52 -0
  105. package/dist/harness-runtime/vendor/opencode-client/service.js +1 -0
  106. package/dist/harness-runtime/vendor/opencode-client/shared-events.d.ts +11 -0
  107. package/dist/harness-runtime/vendor/opencode-client/shared-events.js +8 -0
  108. package/dist/harness-runtime/vendor/opencode-client/solid/connection.d.ts +37 -0
  109. package/dist/harness-runtime/vendor/opencode-client/solid/connection.js +10 -0
  110. package/dist/harness-runtime/vendor/opencode-client/solid/data.d.ts +211 -0
  111. package/dist/harness-runtime/vendor/opencode-client/solid/data.js +18 -0
  112. package/dist/harness-runtime/vendor/opencode-client/solid/index.d.ts +3 -0
  113. package/dist/harness-runtime/vendor/opencode-client/solid/index.js +32 -0
  114. package/dist/harness-runtime/vendor/opencode-client/solid/pty.d.ts +22 -0
  115. package/dist/harness-runtime/vendor/opencode-client/solid/pty.js +8 -0
  116. package/dist/harness-runtime/vendor/opencode-plugin.mjs +3 -0
  117. package/dist/services/cli-operation-classifier.js +4 -0
  118. package/dist/services/cli-upgrade-allowlist.js +27 -0
  119. package/dist/services/discovery/agy-discovery.js +2 -0
  120. package/dist/services/discovery/codex-discovery.js +2 -0
  121. package/dist/services/discovery/droid-discovery.js +2 -0
  122. package/dist/services/discovery/grok-discovery.js +2 -0
  123. package/dist/services/discovery/opencode-discovery.js +2 -0
  124. package/dist/services/discovery/static.js +31 -0
  125. package/dist/services/discovery/zcode-discovery.js +2 -0
  126. package/dist/services/engines.js +23 -25
  127. package/dist/services/eval-snapshots.js +1 -1
  128. package/dist/services/executor-onboarding.js +56 -0
  129. package/dist/services/external-work-launch.js +1 -1
  130. package/dist/services/harness-discovery.js +29 -0
  131. package/dist/services/harness-doctor.js +75 -0
  132. package/dist/services/harness-probe-effects.js +51 -0
  133. package/dist/services/harness-version-probe.js +100 -0
  134. package/dist/services/hooks.js +1 -1
  135. package/dist/services/hybrid-contracts.js +455 -0
  136. package/dist/services/installation-lock.js +92 -0
  137. package/dist/services/managed-processes.js +30 -0
  138. package/dist/services/merge-server.js +1 -1
  139. package/dist/services/model-catalog.js +109 -0
  140. package/dist/services/model-discovery.js +46 -0
  141. package/dist/services/operator-profiles.js +236 -0
  142. package/dist/services/release-archive-producer.js +52 -0
  143. package/dist/services/release-archive.js +143 -0
  144. package/dist/services/release-cache.js +142 -0
  145. package/dist/services/release-compatibility.js +18 -0
  146. package/dist/services/release-download.js +67 -0
  147. package/dist/services/release-envelope.js +104 -0
  148. package/dist/services/release-manifest.js +45 -0
  149. package/dist/services/release-payload.js +114 -0
  150. package/dist/services/release-producer.js +63 -0
  151. package/dist/services/release-provenance.js +160 -0
  152. package/dist/services/release-registry.js +66 -0
  153. package/dist/services/release-source.js +194 -0
  154. package/dist/services/run-controller-recovery.js +2 -2
  155. package/dist/services/run-controller.js +3 -2
  156. package/dist/services/run-health.js +149 -0
  157. package/dist/services/runs.js +61 -13
  158. package/dist/services/setup.js +377 -0
  159. package/dist/storage/database.js +18 -3
  160. package/dist/storage/writer-contract.js +8 -0
  161. package/package.json +4 -1
@@ -0,0 +1,52 @@
1
+ import { hasHelpIntent } from "./help.js";
2
+ import { commandHelpTopic } from "./command-metadata.js";
3
+ import { writeJson } from "../shared/json.js";
4
+ export function writePreparationError(io, args, error) {
5
+ const literal = args.indexOf("--");
6
+ const options = literal < 0 ? args : args.slice(0, literal);
7
+ const payload = { ok: false, error };
8
+ const help = hasHelpIntent(args);
9
+ let json = false;
10
+ for (let index = 0; index < options.length; index++) {
11
+ if (help && options[index] === "--option") {
12
+ index++;
13
+ continue;
14
+ }
15
+ if (options[index] === "--json")
16
+ json = true;
17
+ }
18
+ // Retain the hook's machine-only contract even when transport validation fails.
19
+ if (json || args.slice(0, 3).join(" ") === "codex hook handle")
20
+ writeJson(io.stderr, payload);
21
+ else
22
+ io.stderr.write(renderHumanError(payload, args));
23
+ }
24
+ export function renderHumanError(payload, args) {
25
+ const lines = [`dd-flow: ${payload.error.message}`];
26
+ const details = recordObject(payload.error.details);
27
+ const compatibility = recordObject(details?.compatibility);
28
+ const remediation = recordObject(details?.remediation);
29
+ if (compatibility) {
30
+ lines.push(`Compatibility: ${String(compatibility.verdict ?? "unknown")} (${String(compatibility.engine_resolution ?? "unknown")})`);
31
+ if (compatibility.blocked_operation)
32
+ lines.push(`Blocked operation: ${String(compatibility.blocked_operation)}`);
33
+ if (compatibility.install_hint)
34
+ lines.push(`Install compatible engine: ${String(compatibility.install_hint)}`);
35
+ }
36
+ if (remediation?.mb_upgrade_mode)
37
+ lines.push(`Upgrade mode: ${String(remediation.mb_upgrade_mode)}`);
38
+ if (details?.preferred_command)
39
+ lines.push(`Preferred command: ${String(details.preferred_command)}`);
40
+ const related = Array.isArray(details?.related_commands) ? details.related_commands.map(String) : [];
41
+ if (related.length > 0) {
42
+ lines.push("", "Related commands:");
43
+ for (const command of related)
44
+ lines.push(` ${command}`);
45
+ }
46
+ const topic = commandHelpTopic(args, "");
47
+ lines.push(`See: dd-flow${topic ? ` ${topic}` : ""} --help`);
48
+ return `${lines.join("\n")}\n`;
49
+ }
50
+ function recordObject(value) {
51
+ return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
52
+ }
@@ -0,0 +1,71 @@
1
+ import { createInterface } from "node:readline";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { prepareOperatorProfile, prepareProfileCreation, readOperatorProfileInput } from "../services/operator-profiles.js";
4
+ /** One explicit choice; prompts go to stderr so stdout remains machine-readable. */
5
+ export async function askExecutorChoice(settings, io) {
6
+ const ids = settings.profiles.map(entry => entry.id);
7
+ io.stderr.write(`Executor profiles: ${ids.length ? ids.join(", ") : "none configured"}\n`);
8
+ io.stderr.write("Choose a profile ID/alias, file:/absolute/profile.json, create, or skip. No model is selected automatically.\n");
9
+ const terminal = createInterface({ input: io.stdin, output: io.stderr });
10
+ const lines = terminal[Symbol.asyncIterator]();
11
+ const cancelled = () => new AppError("onboarding_cancelled", "Executor onboarding was cancelled", 1, { effect: "no_effect" });
12
+ terminal.on("SIGINT", () => terminal.close());
13
+ const ask = async (prompt) => {
14
+ io.stderr.write(prompt);
15
+ const line = await lines.next();
16
+ if (line.done)
17
+ throw cancelled();
18
+ const answer = line.value.trim();
19
+ if (answer.length > 4096)
20
+ throw new AppError("usage", "Executor choice exceeds the input limit", 2, { effect: "no_effect" });
21
+ return answer;
22
+ };
23
+ try {
24
+ const answer = await ask("Executor: ");
25
+ if (answer === "skip")
26
+ return { skip: true };
27
+ if (answer === "create") {
28
+ io.stderr.write("Enter explicit profile settings; this does not probe providers or verify model access. Nothing is saved by this dialog.\n");
29
+ const input = { schema_id: "dd-flow/agent-profile@1" };
30
+ for (const [key, prompt] of [
31
+ ["id", "Profile ID: "], ["harness", "Harness (codex/zcode/agy/opencode/grok/droid): "],
32
+ ["provider", "Provider ID: "], ["model", "Model ID: "], ["reasoning", "Reasoning setting: "],
33
+ ["mode", "Mode setting: "], ["permission", "Permission (allow/deny): "]
34
+ ])
35
+ input[key] = await ask(prompt);
36
+ const profile = prepareOperatorProfile(input);
37
+ if (settings.profiles.some(entry => entry.id === profile.id) || Object.hasOwn(settings.aliases, profile.id)) {
38
+ throw new AppError("profile_id_conflict", "New profile ID collides with an existing profile or alias", 2, { effect: "no_effect" });
39
+ }
40
+ if (await ask("Use this profile for this operation? Type yes: ") !== "yes")
41
+ throw cancelled();
42
+ const save = await ask("Save this profile globally during installation? Type yes or no: ");
43
+ if (save !== "yes" && save !== "no")
44
+ throw cancelled();
45
+ if (save === "yes") {
46
+ const defaultChoice = await ask("Set it as global default? Type yes or no: ");
47
+ if (defaultChoice !== "yes" && defaultChoice !== "no")
48
+ throw cancelled();
49
+ return { profile, profileCreation: prepareProfileCreation(settings, profile, defaultChoice === "yes") };
50
+ }
51
+ return { profile };
52
+ }
53
+ if (answer.startsWith("file:")) {
54
+ const file = answer.slice(5);
55
+ if (!file.startsWith("/") && !/^[A-Za-z]:[\\/]/.test(file))
56
+ throw new AppError("usage", "Profile file must be an absolute path", 2, { effect: "no_effect" });
57
+ return { profile: readOperatorProfileInput(file) };
58
+ }
59
+ if (!answer)
60
+ throw new AppError("agent_profile_missing", "An explicit executor choice is required", 1, { effect: "no_effect" });
61
+ return { profileId: answer };
62
+ }
63
+ catch (error) {
64
+ if (error instanceof AppError)
65
+ throw error;
66
+ throw cancelled();
67
+ }
68
+ finally {
69
+ terminal.close();
70
+ }
71
+ }
@@ -0,0 +1,84 @@
1
+ import { prepareCommandRoute } from "./command-inputs.js";
2
+ import { writePreparationError } from "./error-output.js";
3
+ import { parseOutputOptions } from "./output-options.js";
4
+ import { optionalOption, optionalPositiveNumber } from "./argument-values.js";
5
+ import { discoverHarnesses, harnessCatalog } from "../services/harness-discovery.js";
6
+ import { AppError, errorRecord } from "../shared/errors.js";
7
+ import { probeHarnessVersion } from "../services/harness-version-probe.js";
8
+ import { probeHarnessDoctor } from "../services/harness-doctor.js";
9
+ import { prepareResponseDestination, writeResponseFile } from "./response-file.js";
10
+ import path from "node:path";
11
+ import { validateModelScope } from "../services/model-discovery.js";
12
+ /** Home-free ingress: process diagnostics require explicit effect admission. */
13
+ export async function runHarnessesCli(args, env, io = { stdout: process.stdout, stderr: process.stderr }) {
14
+ let json = false;
15
+ try {
16
+ const output = parseOutputOptions(args);
17
+ json = output.json;
18
+ if (output.responseFile)
19
+ prepareResponseDestination(output.responseFile);
20
+ const route = prepareCommandRoute(output.args);
21
+ const family = route.key === "harnesses show" ? route.parsed.positional[0] : optionalOption(route.parsed, "harness");
22
+ if (family && !harnessCatalog.entries.some(entry => entry.id === family))
23
+ throw new AppError("usage", "Unknown harness; see dd-flow harnesses --help", 2, { effect: "no_effect" });
24
+ const provider = optionalOption(route.parsed, "provider"), account = optionalOption(route.parsed, "account-sha256");
25
+ const observationFile = optionalOption(route.parsed, "model-observation-file");
26
+ let modelScope;
27
+ if (provider !== undefined || account !== undefined || observationFile !== undefined) {
28
+ if (!provider || !account)
29
+ throw new AppError("usage", "Doctor model observations require both --provider and --account-sha256", 2, { effect: "no_effect", help: "harnesses doctor" });
30
+ modelScope = { harness: family, provider, account_sha256: account };
31
+ validateModelScope(modelScope);
32
+ if (observationFile) {
33
+ if (output.responseFile && path.resolve(observationFile) === path.resolve(output.responseFile))
34
+ throw new AppError("usage", "Model observation and command response destinations must differ", 2, { effect: "no_effect" });
35
+ prepareResponseDestination(observationFile);
36
+ }
37
+ }
38
+ const discovery = discoverHarnesses({ env, ...(family ? { harness: family } : {}),
39
+ ...(optionalOption(route.parsed, "executable") ? { executable: optionalOption(route.parsed, "executable") } : {}) });
40
+ let probe;
41
+ let modelObservation;
42
+ let observationPublication;
43
+ if (route.key === "harnesses doctor") {
44
+ const selected = discovery.entries[0]?.candidates.find(candidate => candidate.selected);
45
+ if (!selected)
46
+ throw new AppError("harness_selection_required", "Doctor requires one installed executable; use --executable for ambiguous installations", 1, { effect: "no_effect" });
47
+ const stateDir = optionalOption(route.parsed, "state-dir"), nativeExecutable = optionalOption(route.parsed, "native-executable");
48
+ const timeoutMs = optionalPositiveNumber(route.parsed, "timeout-ms", true);
49
+ probe = await probeHarnessDoctor({ harness: family, executable: selected.path, env,
50
+ ...(stateDir !== undefined ? { stateDir } : {}), ...(nativeExecutable !== undefined ? { nativeExecutable } : {}),
51
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
52
+ scope: { processes: route.parsed.options.has("allow-processes"), services: route.parsed.options.has("allow-services"),
53
+ credentials: route.parsed.options.has("allow-credentials"), writes: route.parsed.options.has("allow-writes") } });
54
+ if (modelScope) {
55
+ modelObservation = { scope: modelScope, observed_at: new Date().toISOString(),
56
+ status: probe.reported_models.length ? "listed" : "unavailable", complete: false, models: [...probe.reported_models] };
57
+ if (observationFile) {
58
+ const published = writeResponseFile(modelObservation, { responseFile: observationFile });
59
+ observationPublication = { path: observationFile, status: published.response_file_error ? "unknown" : "published",
60
+ ...(published.response_file_error ? { error: published.response_file_error } : {}) };
61
+ }
62
+ }
63
+ }
64
+ else if (route.key === "harnesses probe-version") {
65
+ const selected = discovery.entries[0]?.candidates.find(candidate => candidate.selected);
66
+ if (!selected)
67
+ throw new AppError("harness_selection_required", "Version probe requires one installed executable; use --executable for ambiguous installations", 1, { effect: "no_effect" });
68
+ probe = await probeHarnessVersion({ harness: family, executable: selected.path, env,
69
+ ...(optionalPositiveNumber(route.parsed, "timeout-ms", true) === undefined ? {} : { timeoutMs: optionalPositiveNumber(route.parsed, "timeout-ms", true) }),
70
+ scope: { processes: route.parsed.options.has("allow-processes"), services: false,
71
+ credentials: route.parsed.options.has("allow-credentials"), writes: route.parsed.options.has("allow-writes") } });
72
+ }
73
+ const result = { ok: true, action: route.key.replaceAll(" ", "_"), catalog: harnessCatalog, discovery, ...(probe ? { probe } : {}),
74
+ ...(modelObservation ? { model_observation: modelObservation, observation_scope_binding: "operator_declared_unverified" } : {}),
75
+ ...(observationPublication ? { model_observation_publication: observationPublication } : {}) };
76
+ io.stdout.write(`${JSON.stringify(writeResponseFile(result, output), null, json ? undefined : 2)}\n`);
77
+ return 0;
78
+ }
79
+ catch (error) {
80
+ const record = errorRecord(error);
81
+ writePreparationError(io, args, record);
82
+ return record.exitCode;
83
+ }
84
+ }
@@ -0,0 +1,39 @@
1
+ import { prepareCommandRoute } from "./command-inputs.js";
2
+ import { optionalOption } from "./argument-values.js";
3
+ import { parseOutputOptions } from "./output-options.js";
4
+ import { prepareResponseDestination, writeResponseFile } from "./response-file.js";
5
+ import { listOperatorModels } from "../services/model-catalog.js";
6
+ import { AppError, errorRecord } from "../shared/errors.js";
7
+ import { writePreparationError } from "./error-output.js";
8
+ /** Model listing never opens an AppContext, starts a probe or reads credentials. */
9
+ export function runModelsCli(args, io = process) {
10
+ let json = false;
11
+ try {
12
+ const output = parseOutputOptions(args);
13
+ json = output.json;
14
+ if (output.responseFile)
15
+ prepareResponseDestination(output.responseFile);
16
+ const route = prepareCommandRoute(output.args);
17
+ if (!["models list", "models show"].includes(route.key))
18
+ throw new AppError("usage", "Unknown models command; see dd-flow models --help", 2, { effect: "no_effect" });
19
+ const input = {};
20
+ for (const [option, field] of [["harness", "harness"], ["provider", "provider"], ["account-sha256", "accountSha256"],
21
+ ["seed-file", "seedFile"], ["observation-file", "observationFile"]]) {
22
+ const value = optionalOption(route.parsed, option);
23
+ if (value !== undefined)
24
+ input[field] = value;
25
+ }
26
+ if (route.key === "models show")
27
+ input.model = route.parsed.positional[0];
28
+ const models = listOperatorModels(input);
29
+ if (route.key === "models show" && models.entries.length === 0)
30
+ throw new AppError("model_not_found", "Model is absent from the selected seed and scoped observation", 1, { effect: "no_effect", help: "models" });
31
+ io.stdout.write(`${JSON.stringify(writeResponseFile({ ok: true, action: route.key.replaceAll(" ", "_"), ...models }, output), null, json ? undefined : 2)}\n`);
32
+ return 0;
33
+ }
34
+ catch (error) {
35
+ const record = errorRecord(error);
36
+ writePreparationError(io, args, record);
37
+ return record.exitCode;
38
+ }
39
+ }
@@ -0,0 +1,61 @@
1
+ import { requiredOption, optionalOption } from "./argument-values.js";
2
+ import { AppError } from "../shared/errors.js";
3
+ import { errorRecord } from "../shared/errors.js";
4
+ import { prepareCommandRoute } from "./command-inputs.js";
5
+ import { parseOutputOptions } from "./output-options.js";
6
+ import { writePreparationError } from "./error-output.js";
7
+ import { resolveDdFlowHome } from "../storage/paths.js";
8
+ import { prepareResponseDestination, writeResponseFile } from "./response-file.js";
9
+ import { readOperatorProfiles, resolveOperatorProfile, mutateOperatorProfiles, readOperatorProfileInput } from "../services/operator-profiles.js";
10
+ /** Home-only entrypoint; does not create AppContext, project registration or runtime DB. */
11
+ export function dispatchOperatorProfiles(home, route) {
12
+ const action = route.command, parsed = route.parsed;
13
+ if (action === "list")
14
+ return { ok: true, action: "profiles_list", settings: readOperatorProfiles(home) };
15
+ if (action === "show") {
16
+ const settings = readOperatorProfiles(home), id = parsed.positional[0];
17
+ return { ok: true, action: "profiles_show", selected: id, revision: settings.revision, profile: resolveOperatorProfile(settings, id) };
18
+ }
19
+ let mutation;
20
+ if (action === "create")
21
+ mutation = { action, profile: readOperatorProfileInput(requiredOption(parsed, "file")), setDefault: parsed.options.has("set-default") };
22
+ else if (action === "edit")
23
+ mutation = { action, profile: readOperatorProfileInput(requiredOption(parsed, "file")) };
24
+ else if (action === "remove")
25
+ mutation = { action, id: parsed.positional[0] };
26
+ else if (action === "alias") {
27
+ const target = optionalOption(parsed, "target"), remove = parsed.options.has("remove");
28
+ if (Boolean(target) === remove)
29
+ throw new AppError("usage", "Use exactly one of --target ID or --remove; see dd-flow profiles alias --help", 2, { effect: "no_effect" });
30
+ mutation = { action, alias: parsed.positional[0], target: target ?? null };
31
+ }
32
+ else if (action === "set-default") {
33
+ const id = parsed.positional[0], clear = parsed.options.has("clear");
34
+ if (Boolean(id) === clear)
35
+ throw new AppError("usage", "Select one profile ID or --clear; see dd-flow profiles set-default --help", 2, { effect: "no_effect" });
36
+ mutation = { action, id: id ?? null };
37
+ }
38
+ else
39
+ throw new AppError("usage", "Unknown profiles command; use dd-flow profiles --help", 2, { effect: "no_effect" });
40
+ const settings = mutateOperatorProfiles(home, requiredOption(parsed, "expected-revision"), mutation);
41
+ return { ok: true, action: `profiles_${action}`, effect: "committed", settings };
42
+ }
43
+ /** Lightweight executable ingress; never imports the project/runtime business router. */
44
+ export function runOperatorProfilesCli(args, env, io = { stdout: process.stdout, stderr: process.stderr }) {
45
+ let json = false;
46
+ try {
47
+ const output = parseOutputOptions(args);
48
+ json = output.json;
49
+ if (output.responseFile)
50
+ prepareResponseDestination(output.responseFile);
51
+ const route = prepareCommandRoute(output.args);
52
+ const result = dispatchOperatorProfiles(resolveDdFlowHome(env), route);
53
+ io.stdout.write(`${JSON.stringify(writeResponseFile(result, output), null, json ? undefined : 2)}\n`);
54
+ return 0;
55
+ }
56
+ catch (error) {
57
+ const record = errorRecord(error);
58
+ writePreparationError(io, args, record);
59
+ return record.exitCode;
60
+ }
61
+ }
@@ -0,0 +1,35 @@
1
+ import { AppError } from "../shared/errors.js";
2
+ /** Shared execution transport grammar. Help resolves before this function. */
3
+ export function parseOutputOptions(args) {
4
+ const stripped = [];
5
+ let json = false, progressJsonl = false, responseFile = null;
6
+ for (let index = 0; index < args.length; index++) {
7
+ const arg = args[index];
8
+ if (arg === "--") {
9
+ stripped.push(...args.slice(index));
10
+ break;
11
+ }
12
+ if (arg === "--json") {
13
+ json = true;
14
+ continue;
15
+ }
16
+ if (arg === "--progress-jsonl") {
17
+ progressJsonl = true;
18
+ continue;
19
+ }
20
+ if (arg === "--response-file" || arg.startsWith("--response-file=")) {
21
+ if (responseFile !== null)
22
+ throw new AppError("usage", "--response-file may be supplied only once", 2);
23
+ const file = arg === "--response-file" ? args[++index] : arg.slice("--response-file=".length);
24
+ if (!file?.trim() || file.startsWith("--"))
25
+ throw new AppError("usage", "--response-file requires a path", 2);
26
+ responseFile = file;
27
+ continue;
28
+ }
29
+ stripped.push(arg);
30
+ }
31
+ if (responseFile && !json)
32
+ throw new AppError("usage", "--response-file requires --json", 2);
33
+ const hookJsonOnly = stripped[0] === "codex" && stripped[1] === "hook" && stripped[2] === "handle";
34
+ return { json: json || hookJsonOnly, progressJsonl, args: stripped, hookJsonOnly, responseFile };
35
+ }
@@ -0,0 +1,69 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { randomUUID } from "node:crypto";
4
+ import { AppError } from "../shared/errors.js";
5
+ /** Preflight does not create a parent, destination or runtime home. */
6
+ export function prepareResponseDestination(value) {
7
+ const file = path.resolve(value);
8
+ try {
9
+ const inspect = (target) => {
10
+ try {
11
+ return fs.lstatSync(target);
12
+ }
13
+ catch (error) {
14
+ if (error.code === "ENOENT")
15
+ return null;
16
+ throw error;
17
+ }
18
+ };
19
+ let parent = path.dirname(file);
20
+ let parentStat = inspect(parent);
21
+ while (!parentStat) {
22
+ const next = path.dirname(parent);
23
+ if (next === parent)
24
+ break;
25
+ parent = next;
26
+ parentStat = inspect(parent);
27
+ }
28
+ const targetStat = inspect(file);
29
+ if (!parentStat?.isDirectory() || targetStat && !targetStat.isFile())
30
+ throw new Error();
31
+ }
32
+ catch {
33
+ throw new AppError("response_file_invalid", "Response destination must be a regular file under a directory", 2, { parameter: "response-file", effect: "no_effect" });
34
+ }
35
+ }
36
+ /** Optional publication failure never changes the accepted operation outcome. */
37
+ export function writeResponseFile(payload, output) {
38
+ if (!output.responseFile)
39
+ return payload;
40
+ const file = path.resolve(output.responseFile), temporary = `${file}.tmp-${randomUUID()}`;
41
+ const visible = payload && typeof payload === "object" && !Array.isArray(payload) ? { ...payload } : { ok: true, result: payload };
42
+ let ownsTemporary = false;
43
+ try {
44
+ prepareResponseDestination(file);
45
+ fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
46
+ const fd = fs.openSync(temporary, "wx", 0o600);
47
+ ownsTemporary = true;
48
+ try {
49
+ fs.writeFileSync(fd, `${JSON.stringify(payload, null, 2)}\n`);
50
+ fs.fsyncSync(fd);
51
+ }
52
+ finally {
53
+ fs.closeSync(fd);
54
+ }
55
+ fs.renameSync(temporary, file);
56
+ }
57
+ catch {
58
+ return { ...visible, response_file: file, response_file_error: "Response publication failed; reconcile the accepted operation before retrying" };
59
+ }
60
+ finally {
61
+ try {
62
+ if (ownsTemporary && fs.existsSync(temporary))
63
+ fs.unlinkSync(temporary);
64
+ }
65
+ catch { /* Own temporary only; never mask the operation outcome. */ }
66
+ }
67
+ delete visible.worker_prompt_markdown;
68
+ return { ...visible, response_file: file };
69
+ }
@@ -70,6 +70,7 @@ import { vnextStageDirectory } from "../domain/stage-catalog.js";
70
70
  import { prepareCommandRoute } from "./command-inputs.js";
71
71
  import { parseLifecycleCommand } from "../services/lifecycle-command.js";
72
72
  import { dispatchRuntimeProcess, prepareRuntimeProcess } from "./runtime-process.js";
73
+ import { reconcileFlowRunHealth } from "../services/run-health.js";
73
74
  import { fenceRuntimeBudget, runtimeBudgetStatus, prepareRuntimeScopeControl, prepareRuntimeScopeFence } from "../services/runtime-budget.js";
74
75
  import { stopRuntimeScope } from "../services/runtime-scope-stop.js";
75
76
  import { launchRuntimeScopeControl, launchRuntimeScopeResume, prepareRuntimeScopeReconciliation, prepareRuntimeScopeServing, reconcileRuntimeScopeControl, serveRuntimeScopeControl } from "../services/runtime-scope-worker.js";
@@ -505,6 +506,8 @@ function resolveProjectRootBeforeRouting(args, env, deadlineAt) {
505
506
  function databaseModeForCommand(args, classification) {
506
507
  if (isNativeHookIngress(args))
507
508
  return "hook";
509
+ if (args[0] === "run" && args[1] === "reconcile")
510
+ return args.includes("--apply") ? "reconcile" : "read_existing";
508
511
  if (isRuntimeMaintenance(args))
509
512
  return "read_existing";
510
513
  const [family, command] = args;
@@ -2474,6 +2477,8 @@ function recoveryResumeInput(parsed) {
2474
2477
  return { projectRoot: requiredOption(parsed, "project-root"), runId: requiredPosition(parsed, 1, "run-id"), recoveryId: requiredOption(parsed, "recovery-id"), daemonId: requiredOption(parsed, "daemon-id"), harness: requiredOption(parsed, "harness"), nativeSessionId: requiredOption(parsed, "native-session-id") };
2475
2478
  }
2476
2479
  function dispatchRun(context, command, parsed, prepared = {}) {
2480
+ if (command === "reconcile")
2481
+ return reconcileFlowRunHealth(context, { runId: parsed.positional[0], projectRoot: optionalOption(parsed, "project-root"), apply: hasOption(parsed, "apply"), noProgressMs: optionalNumber(parsed, "no-progress-ms") });
2477
2482
  if (command === "recovery") {
2478
2483
  const action = requiredPosition(parsed, 0, "recovery action");
2479
2484
  const projectRoot = requiredOption(parsed, "project-root");
@@ -0,0 +1,147 @@
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
+ /** Lightweight global diagnostic ingress; never creates a runtime context. */
19
+ export async function runSetupCli(args, env, io = { stdout: process.stdout, stderr: process.stderr, stdin: process.stdin }) {
20
+ let json = false;
21
+ try {
22
+ const output = parseOutputOptions(args);
23
+ json = output.json;
24
+ if (output.responseFile)
25
+ prepareResponseDestination(output.responseFile);
26
+ const route = prepareCommandRoute(output.args);
27
+ const humanProgress = !output.json && !output.progressJsonl;
28
+ const reportHumanProgress = (message) => {
29
+ // Diagnostic delivery cannot turn a completed installation into failure.
30
+ try {
31
+ io.stderr.write(`setup: ${message}\n`);
32
+ }
33
+ catch { /* Best-effort human progress only. */ }
34
+ };
35
+ const home = resolveDdFlowHome(env);
36
+ let result;
37
+ if (route.key === "setup status")
38
+ result = { ok: true, action: "setup_status", observed_cli: getCliVersionReport().cli, ...readSetupStatus(home) };
39
+ else if (route.key === "setup" || route.key === "setup update") {
40
+ const parsed = route.parsed;
41
+ const source = optionalOption(parsed, "canon-source"), version = optionalOption(parsed, "canon-version");
42
+ const registryFile = optionalOption(parsed, "release-registry");
43
+ if (source && (version || registryFile))
44
+ throw new AppError("usage", "--canon-source is exclusive with --canon-version and --release-registry; see dd-flow setup --help", 2, { effect: "no_effect" });
45
+ const channel = (optionalOption(parsed, "channel") ?? "stable");
46
+ const selection = source ? null : readRegistryRelease(registryFile ?? env.DD_FLOW_RELEASE_REGISTRY ?? path.join(home, "release-registry.json"), channel, version);
47
+ const profile = optionalOption(parsed, "profile"), skip = parsed.options.has("skip-agent-setup");
48
+ const intentFile = optionalOption(parsed, "save-profile-intent");
49
+ if (intentFile && skip)
50
+ throw new AppError("usage", "--save-profile-intent conflicts with --skip-agent-setup", 2, { effect: "no_effect" });
51
+ let profileCreation = intentFile ? readProfileCreationIntent(intentFile) : undefined;
52
+ const stdin = io.stdin ?? process.stdin;
53
+ const nonInteractive = parsed.options.has("non-interactive") || output.json || output.progressJsonl
54
+ || !stdin.isTTY || !io.stderr.isTTY;
55
+ const profileFile = optionalOption(parsed, "profile-file");
56
+ const requestId = requiredOption(parsed, "request-id");
57
+ const retained = profile === undefined && profileFile === undefined && !intentFile && !skip ? readRetainedSetupExecutor(home, requestId) : null;
58
+ if (retained?.profileCreation)
59
+ profileCreation = retained.profileCreation;
60
+ const choice = { ...(profile !== undefined ? { profileId: profile } : {}),
61
+ ...(profileFile !== undefined ? { profileFile } : {}),
62
+ ...(retained?.executor ? { profile: retained.executor } : profileCreation && profile === undefined && profileFile === undefined ? { profile: profileCreation.profile } : {}),
63
+ skip: skip || retained !== null && retained.executor === null };
64
+ let deferred = hasDeferredSetupOnboarding(home, requestId);
65
+ let selected;
66
+ if (!deferred) {
67
+ try {
68
+ selected = selectOnboardingExecutor(choice, () => readOperatorProfiles(home), { allowSkip: true });
69
+ }
70
+ catch (error) {
71
+ if (!(error instanceof AppError) || error.code !== "agent_profile_missing" || nonInteractive
72
+ || profile !== undefined || profileFile !== undefined || intentFile || skip)
73
+ throw error;
74
+ deferred = true;
75
+ }
76
+ }
77
+ else if (profile !== undefined || profileFile !== undefined || intentFile || skip) {
78
+ // Explicit continuation inputs still fail before downloading or replaying.
79
+ selected = selectOnboardingExecutor(choice, () => readOperatorProfiles(home), { allowSkip: true });
80
+ }
81
+ const observedCli = getCliVersionReport().cli;
82
+ const compatibility = createReleaseCompatibility({ channel,
83
+ catalogVersions: installedCatalogVersions, routerVersion: observedCli.version });
84
+ const producers = readTrustedReleaseProducers(requiredOption(parsed, "trust-file"));
85
+ const bundle = await readReleaseBundle(source ?? selection.envelope_url, producers, compatibility, {
86
+ ...(selection ? { expectedVersion: selection.version } : {}),
87
+ ...((output.progressJsonl || humanProgress) ? { onProgress: (progress) => {
88
+ if (output.progressJsonl)
89
+ io.stdout.write(`${JSON.stringify({ type: "setup_download_progress", request_id: requestId, ...progress })}\n`);
90
+ else if (progress.received_bytes === progress.expected_bytes)
91
+ reportHumanProgress(`${progress.artifact} archive received (${progress.received_bytes} bytes); integrity validation follows`);
92
+ } } : {})
93
+ });
94
+ if (selection && bundle.authenticated.manifest.version !== selection.version)
95
+ 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" });
96
+ const installed = installAuthenticatedRelease(home, { requestId, action: route.key === "setup update" ? "update" : "install",
97
+ envelope: bundle.envelope, trustedProducers: producers, compatibility, canonArchive: bundle.canonArchive, engineArchive: bundle.engineArchive,
98
+ ...(deferred ? { deferredOnboarding: true } : { executor: selected.profile, ...(profileCreation ? { profileCreation } : {}) }),
99
+ ...((output.progressJsonl || humanProgress) ? { onCheckpoint: phase => {
100
+ if (output.progressJsonl)
101
+ io.stdout.write(`${JSON.stringify({ type: "setup_progress", request_id: requestId, phase })}\n`);
102
+ else
103
+ reportHumanProgress({ prepared: "verified release request retained", canon_cached: "canon cache verified", engine_cached: "engine cache verified",
104
+ profiles_saved: "profile settings saved", committed: "installation committed; runtime qualification remains unknown" }[phase]);
105
+ } } : {}) });
106
+ if (humanProgress && installed.replayed)
107
+ reportHumanProgress("exact request replay verified; retained selection was not reactivated");
108
+ if (deferred) {
109
+ const saved = readSetupOnboarding(home, requestId);
110
+ const explicit = profile !== undefined || profileFile !== undefined || intentFile !== undefined || skip;
111
+ const deferredChoice = saved && !explicit ? { ...(saved.executor ? { profile: saved.executor } : { skip: true }),
112
+ ...(saved.profileCreation ? { profileCreation: saved.profileCreation } : {}) } : choice;
113
+ try {
114
+ selected ??= await onboardExecutor(deferredChoice, () => readOperatorProfiles(home), { allowSkip: true, nonInteractive }, settings => askExecutorChoice(settings, { stdin, stderr: io.stderr }));
115
+ const consent = commitSetupOnboarding(home, requestId, { executor: selected.profile,
116
+ ...(profileCreation ?? selected.profileCreation ? { profileCreation: profileCreation ?? selected.profileCreation } : {}) });
117
+ installed.executor = consent.executor;
118
+ if (humanProgress)
119
+ reportHumanProgress("executor onboarding committed after installation");
120
+ }
121
+ catch (error) {
122
+ if (error instanceof AppError) {
123
+ error.details.installation = "committed";
124
+ error.details.request_id = requestId;
125
+ error.details.next_action = "Replay the same setup request to resume executor onboarding; installation remains retained";
126
+ }
127
+ throw error;
128
+ }
129
+ }
130
+ result = { ...installed, action: route.key === "setup update" ? "setup_update" : "setup_install", observed_cli: observedCli,
131
+ executor: installed.executor ? { profile_id: installed.executor.id, revision: hybridDigest(installed.executor), readiness: "unknown_requires_qualification" } : { profile_id: null, readiness: "not_configured" },
132
+ ...readSetupStatus(home) };
133
+ }
134
+ else
135
+ throw new AppError("usage", "Unknown setup command; see dd-flow setup --help", 2, { effect: "no_effect" });
136
+ io.stdout.write(`${JSON.stringify(writeResponseFile(result, output), null, json ? undefined : 2)}\n`);
137
+ return 0;
138
+ }
139
+ catch (error) {
140
+ const record = errorRecord(error);
141
+ writePreparationError(io, args, record);
142
+ if (!json && error instanceof AppError && error.details.installation === "committed") {
143
+ io.stderr.write("setup: installation remains committed; replay the same request to resume executor onboarding\n");
144
+ }
145
+ return record.exitCode;
146
+ }
147
+ }
@@ -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.
@@ -7,7 +7,7 @@ import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-open
7
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
8
  const prompt = async options => options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt;
9
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, variant: options.variant, agent: options.agent, authPath: options["auth-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;
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, variant: options.variant, agent: options.agent, 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
11
  if (family === "daemon" && command === "start") result = await durableDaemonStart({ ...common, entryPath: process.argv[1] }, startDaemon);
12
12
  else if (family === "daemon" && command === "serve") { await serveDaemon(common.stateDir); process.exit(0); }
13
13
  else if (family === "daemon" && command === "status") result = await callDaemon(common.stateDir, "daemon.status");