@deksden-com/dd-flow-cli 0.9.0-beta.11 → 0.9.0-beta.110
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 +520 -0
- package/README.md +68 -0
- package/dist/build-info.json +8 -8
- package/dist/cli/command-inputs.js +305 -0
- package/dist/cli/help.js +89 -13
- package/dist/cli/hook-ingress.js +77 -0
- package/dist/cli/input-preparation.js +116 -0
- package/dist/cli/native-hook-ingress.js +48 -0
- package/dist/cli/run-cli.js +1465 -384
- package/dist/cli.js +8 -2
- package/dist/harness-runtime/DD-ZCODE.md +99 -0
- package/dist/harness-runtime/bin/dd-agy.mjs +52 -0
- package/dist/harness-runtime/bin/dd-codex.mjs +26 -0
- package/dist/harness-runtime/bin/dd-droid.mjs +33 -0
- package/dist/harness-runtime/bin/dd-grok.mjs +30 -0
- package/dist/harness-runtime/bin/dd-opencode.mjs +21 -0
- package/dist/harness-runtime/bin/dd-zcode.mjs +83 -0
- package/dist/harness-runtime/lib/agy-hooks.d.mts +1 -0
- package/dist/harness-runtime/lib/agy-hooks.mjs +9 -0
- package/dist/harness-runtime/lib/daemon-operations.mjs +226 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.d.mts +6 -0
- package/dist/harness-runtime/lib/dd-agy-daemon.mjs +500 -0
- package/dist/harness-runtime/lib/dd-agy.mjs +59 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.d.mts +1 -0
- package/dist/harness-runtime/lib/dd-codex-daemon.mjs +149 -0
- package/dist/harness-runtime/lib/dd-codex.mjs +563 -0
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +125 -0
- package/dist/harness-runtime/lib/dd-droid.mjs +475 -0
- package/dist/harness-runtime/lib/dd-grok-daemon.mjs +388 -0
- package/dist/harness-runtime/lib/dd-grok.mjs +174 -0
- package/dist/harness-runtime/lib/dd-opencode-daemon.mjs +219 -0
- package/dist/harness-runtime/lib/dd-opencode.mjs +98 -0
- package/dist/harness-runtime/lib/dd-zcode-daemon.mjs +645 -0
- package/dist/harness-runtime/lib/dd-zcode.mjs +982 -0
- package/dist/harness-runtime/lib/delegation-instructions.d.mts +13 -0
- package/dist/harness-runtime/lib/delegation-instructions.mjs +144 -0
- package/dist/harness-runtime/lib/dispatch-fence.mjs +14 -0
- package/dist/harness-runtime/lib/driver-recovery.mjs +129 -0
- package/dist/harness-runtime/lib/droid-observation.mjs +66 -0
- package/dist/harness-runtime/lib/managed-daemon.mjs +327 -0
- package/dist/harness-runtime/lib/model-observations.mjs +77 -0
- package/dist/harness-runtime/lib/native-hook-command.d.mts +3 -0
- package/dist/harness-runtime/lib/native-hook-command.mjs +108 -0
- package/dist/harness-runtime/lib/observation-clock.mjs +36 -0
- package/dist/harness-runtime/lib/operation-context.mjs +5 -0
- package/dist/harness-runtime/lib/operation-errors.mjs +19 -0
- package/dist/harness-runtime/lib/process-json.mjs +71 -0
- package/dist/harness-runtime/lib/process-snapshot.mjs +10 -0
- package/dist/harness-runtime/lib/runner-events.mjs +200 -0
- package/dist/harness-runtime/lib/runner-lock.mjs +42 -0
- package/dist/harness-runtime/lib/session-settlement.mjs +30 -0
- package/dist/harness-runtime/lib/tool-observations.d.mts +17 -0
- package/dist/harness-runtime/lib/tool-observations.mjs +153 -0
- package/dist/harness-runtime/lib/zcode-usage.mjs +54 -0
- package/dist/protocol/local-files.js +18 -9
- package/dist/runtime/context.js +2 -2
- package/dist/schemas/agent-profile.schema.json +1 -1
- package/dist/schemas/code-review-result.schema.json +1 -1
- package/dist/schemas/code-work-batch.schema.json +3 -3
- package/dist/schemas/code-work-result.schema.json +3 -3
- package/dist/schemas/plan-review-result.schema.json +2 -2
- package/dist/schemas/run-control-receipt.schema.json +99 -0
- package/dist/schemas/run-control-request.schema.json +36 -0
- package/dist/schemas/vnext-protocol-plan.schema.json +2 -2
- package/dist/services/canon.js +11 -8
- package/dist/services/cleanup.js +132 -39
- package/dist/services/cli-operation-classifier.js +22 -24
- package/dist/services/code-checks.js +589 -106
- package/dist/services/codex-hook-delivery.js +28 -0
- package/dist/services/command-context.js +80 -0
- package/dist/services/config.js +11 -8
- package/dist/services/continuation-outcome.js +20 -0
- package/dist/services/controller-fanout.js +173 -0
- package/dist/services/dashboard.js +103 -31
- package/dist/services/engines.js +121 -76
- package/dist/services/eval-snapshots.js +994 -97
- package/dist/services/execution-policy.js +181 -0
- package/dist/services/external-work-launch.js +166 -0
- package/dist/services/harness-adapter.js +147 -24
- package/dist/services/harness-config.js +2 -0
- package/dist/services/hooks.js +702 -327
- package/dist/services/lanes.js +78 -65
- package/dist/services/lifecycle-command.js +113 -18
- package/dist/services/lifecycle-contract.js +30 -0
- package/dist/services/lifecycle-invocations.js +1379 -0
- package/dist/services/managed-daemon-binding.js +38 -0
- package/dist/services/managed-processes.js +302 -34
- package/dist/services/merge-queue.js +228 -149
- package/dist/services/merge-server.js +66 -28
- package/dist/services/migrations.js +37 -16
- package/dist/services/native-daemon-history.js +49 -0
- package/dist/services/native-session-control.js +39 -0
- package/dist/services/plan-runtime.js +26 -11
- package/dist/services/plans.js +28 -25
- package/dist/services/projects.js +20 -15
- package/dist/services/prompts.js +25 -16
- package/dist/services/protocols.js +160 -86
- package/dist/services/recovery-observation-budget.js +61 -0
- package/dist/services/recovery-snapshot-database.js +142 -0
- package/dist/services/repair-intents.js +40 -0
- package/dist/services/review-copy.js +136 -0
- package/dist/services/run-control-receipt.js +56 -0
- package/dist/services/run-control-worker.js +351 -0
- package/dist/services/run-control.js +888 -0
- package/dist/services/run-controller-adapter.js +231 -0
- package/dist/services/run-controller-capture.js +167 -0
- package/dist/services/run-controller-process.js +180 -0
- package/dist/services/run-controller-recovery.js +221 -0
- package/dist/services/run-controller-state.js +36 -0
- package/dist/services/run-controller.js +798 -0
- package/dist/services/run-engine-bindings.js +1 -1
- package/dist/services/run-fork.js +142 -0
- package/dist/services/run-observations.js +112 -0
- package/dist/services/run-projection.js +22 -64
- package/dist/services/run-recovery-runtime.js +80 -0
- package/dist/services/run-recovery.js +345 -0
- package/dist/services/runs.js +536 -181
- package/dist/services/runtime-budget.js +413 -0
- package/dist/services/runtime-command.js +43 -0
- package/dist/services/runtime-scope-capture.js +52 -0
- package/dist/services/runtime-scope-control.js +460 -0
- package/dist/services/runtime-scope-resume.js +577 -0
- package/dist/services/runtime-scope-stop.js +159 -0
- package/dist/services/runtime-scope-worker.js +242 -0
- package/dist/services/runtime-service.js +97 -0
- package/dist/services/schema-validation.js +10 -8
- package/dist/services/scope-writer-cleanup.js +26 -0
- package/dist/services/sessions.js +35 -69
- package/dist/services/stage-blocker.js +17 -7
- package/dist/services/stage-context.js +50 -19
- package/dist/services/stage-lifecycle.js +100 -103
- package/dist/services/stage-pause.js +88 -75
- package/dist/services/stage-report-renderer.js +116 -6
- package/dist/services/stage-work-graph.js +35 -0
- package/dist/services/usage.js +35 -98
- package/dist/services/vnext-code-review.js +197 -84
- package/dist/services/vnext-code.js +278 -251
- package/dist/services/vnext-execution-profile.js +5 -3
- package/dist/services/vnext-fanout.js +172 -17
- package/dist/services/vnext-merge.js +345 -111
- package/dist/services/vnext-plan-review.js +171 -111
- package/dist/services/vnext-plan.js +180 -87
- package/dist/services/vnext-protocolize.js +320 -74
- package/dist/services/vnext-specify.js +115 -77
- package/dist/services/work-registry.js +1001 -187
- package/dist/services/workspace-bootstrap.js +76 -0
- package/dist/services/workspace-files.js +83 -0
- package/dist/services/worktrees.js +88 -36
- package/dist/shared/entity-references.js +8 -0
- package/dist/shared/errors.js +12 -0
- package/dist/storage/database.js +692 -35
- package/dist/storage/foreign-key-transaction.js +39 -0
- package/dist/storage/immutable-input.js +45 -0
- package/dist/storage/import-guard.js +102 -0
- package/dist/storage/native-cleanup.js +52 -0
- package/dist/storage/paths.js +17 -4
- package/dist/storage/projection-lock.js +73 -0
- package/dist/storage/work-references.js +23 -0
- package/dist/storage/writer-contract.js +77 -0
- package/dist/storage/writer-migration.js +85 -0
- package/package.json +24 -13
- package/tools/repair-paused-run-status.mjs +84 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
import { AppError, isAppError } from "../shared/errors.js";
|
|
5
|
+
import { validateSchema } from "../services/schema-validation.js";
|
|
6
|
+
export function prepareError(error, input = {}) {
|
|
7
|
+
if (isAppError(error)) {
|
|
8
|
+
// A malformed user input is safely correctable. A broken schema registry,
|
|
9
|
+
// binding, or storage is not; do not disguise infrastructure damage as a
|
|
10
|
+
// retryable command typo.
|
|
11
|
+
const inputErrorCodes = new Set([
|
|
12
|
+
"usage", "validation", "schema_validation", "invalid_json", "not_found",
|
|
13
|
+
"path_escape", "input_file_missing", "input_file_not_regular", "input_file_unreadable",
|
|
14
|
+
"response_file_parent_invalid", "response_file_invalid", "context_checksum_mismatch", "invalid_run_config_state", "invalid_work_state", "invalid_stage_state", "runtime_budget_invalid", "runtime_scope_manifest_invalid", "runtime_scope_resume_invalid",
|
|
15
|
+
"fork_path_conflict", "fork_output_not_empty", "fork_checkpoint_invalid", "fork_engine_unavailable", "snapshot_missing",
|
|
16
|
+
"repair_check_declaration_missing", "review_repair_check_required", "review_check_reference_unknown", "semantic_status_inconsistent", "migration_report_invalid", "controller_context_missing", "snapshot_output_inside_runtime"
|
|
17
|
+
]);
|
|
18
|
+
if (!inputErrorCodes.has(error.code) && error.details.phase !== "prepare")
|
|
19
|
+
throw error;
|
|
20
|
+
throw new AppError(error.code, error.message, 2, {
|
|
21
|
+
...error.details,
|
|
22
|
+
phase: "prepare",
|
|
23
|
+
effect: error.details.effect ?? "no_effect",
|
|
24
|
+
recoverable: error.details.recoverable ?? true,
|
|
25
|
+
...input
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
const code = error?.code;
|
|
29
|
+
if (typeof input.file !== "string" || !["ENOENT", "EACCES", "EPERM", "EISDIR", "ENOTDIR", "ELOOP", "ENAMETOOLONG"].includes(code ?? ""))
|
|
30
|
+
throw error;
|
|
31
|
+
throw new AppError("input_file_unreadable", `Cannot read input file${typeof input.file === "string" ? `: ${input.file}` : ""}`, 2, {
|
|
32
|
+
phase: "prepare", effect: "no_effect", recoverable: true, ...input, cause: code ?? String(error)
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
export function prepareTextFile(file, label = "input file") {
|
|
36
|
+
const prepared = prepareFileBytes(file, label);
|
|
37
|
+
return { file: prepared.file, text: prepared.bytes.toString("utf8") };
|
|
38
|
+
}
|
|
39
|
+
export function prepareFileBytes(file, label = "input file") {
|
|
40
|
+
const absolute = path.resolve(file);
|
|
41
|
+
let descriptor;
|
|
42
|
+
try {
|
|
43
|
+
descriptor = fs.openSync(absolute, fs.constants.O_RDONLY | fs.constants.O_NONBLOCK);
|
|
44
|
+
const stat = fs.fstatSync(descriptor);
|
|
45
|
+
if (!stat.isFile()) {
|
|
46
|
+
throw new AppError("input_file_not_regular", `${label} must be a readable regular file: ${absolute}`, 2, { file: absolute, label });
|
|
47
|
+
}
|
|
48
|
+
return { file: absolute, bytes: fs.readFileSync(descriptor) };
|
|
49
|
+
}
|
|
50
|
+
catch (error) {
|
|
51
|
+
if (error?.code === "ENOENT") {
|
|
52
|
+
throw new AppError("input_file_missing", `${label} does not exist: ${absolute}`, 2, {
|
|
53
|
+
phase: "prepare", effect: "no_effect", recoverable: true, file: absolute, label
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return prepareError(error, { file: absolute, label });
|
|
57
|
+
}
|
|
58
|
+
finally {
|
|
59
|
+
if (descriptor !== undefined)
|
|
60
|
+
fs.closeSync(descriptor);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
export function prepareJsonText(text, input) {
|
|
64
|
+
try {
|
|
65
|
+
return { file: input.file, text, value: JSON.parse(text) };
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// Keep the established public code so agents can recognise this as a
|
|
69
|
+
// safe correction-and-retry condition.
|
|
70
|
+
throw new AppError("invalid_json", `Invalid JSON in ${input.label ?? "input"}: ${input.file}`, 2, {
|
|
71
|
+
phase: "prepare", effect: "no_effect", recoverable: true, file: input.file, label: input.label ?? "input",
|
|
72
|
+
cause: "Invalid JSON syntax", input_sha256: crypto.createHash("sha256").update(text).digest("hex")
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export function prepareJsonFile(file, label = "input JSON") {
|
|
77
|
+
const prepared = prepareTextFile(file, label);
|
|
78
|
+
return prepareJsonText(prepared.text, { file: prepared.file, label });
|
|
79
|
+
}
|
|
80
|
+
export function prepareJsonSchema(file, label, schema) {
|
|
81
|
+
const prepared = prepareJsonFile(file, label);
|
|
82
|
+
try {
|
|
83
|
+
validateSchema({ ...schema, file: prepared.file, data: prepared.value });
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
return prepareError(error, { file: prepared.file, label });
|
|
87
|
+
}
|
|
88
|
+
return prepared;
|
|
89
|
+
}
|
|
90
|
+
/** Read-only destination check; execution still handles filesystem races. */
|
|
91
|
+
export function prepareOutputFile(value) { return prepareOutput(value, false); }
|
|
92
|
+
export function prepareOutputDirectory(value) { return prepareOutput(value, true); }
|
|
93
|
+
function prepareOutput(value, directory) {
|
|
94
|
+
const file = path.resolve(value);
|
|
95
|
+
try {
|
|
96
|
+
let ancestor = directory ? file : path.dirname(file);
|
|
97
|
+
while (!fs.existsSync(ancestor) && path.dirname(ancestor) !== ancestor)
|
|
98
|
+
ancestor = path.dirname(ancestor);
|
|
99
|
+
if (!fs.statSync(ancestor).isDirectory())
|
|
100
|
+
throw new AppError("validation", "Output parent must be a directory", 2);
|
|
101
|
+
fs.accessSync(ancestor, fs.constants.W_OK | fs.constants.X_OK);
|
|
102
|
+
if (fs.existsSync(file)) {
|
|
103
|
+
const stat = fs.statSync(file);
|
|
104
|
+
if (directory ? !stat.isDirectory() : !stat.isFile())
|
|
105
|
+
throw new AppError("validation", directory ? "Output must name a directory" : "Output must name a regular file", 2);
|
|
106
|
+
fs.accessSync(file, fs.constants.W_OK | (directory ? fs.constants.X_OK : 0));
|
|
107
|
+
}
|
|
108
|
+
return file;
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
const code = error?.code;
|
|
112
|
+
if (["ENOENT", "EACCES", "EPERM", "ENOTDIR", "ELOOP", "ENAMETOOLONG"].includes(code ?? ""))
|
|
113
|
+
return prepareError(new AppError("validation", "Output destination is not writable or has an invalid parent", 2, { cause: code }), { file, parameter: "output" });
|
|
114
|
+
return prepareError(error, { file, parameter: "output" });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { AppError, errorRecord } from "../shared/errors.js";
|
|
2
|
+
import { parseCommandArgs } from "../services/lifecycle-command.js";
|
|
3
|
+
/** These ingress commands consume a prepared store; they never prepare it. */
|
|
4
|
+
export function isNativeHookIngress(args) {
|
|
5
|
+
return args[2] === "handle" && ((args[1] === "event" && ["agy", "grok", "droid", "opencode", "zcode"].includes(args[0] ?? ""))
|
|
6
|
+
|| args[0] === "zcode" && args[1] === "hook");
|
|
7
|
+
}
|
|
8
|
+
export async function dispatchNativeHook(args, stdin, env) {
|
|
9
|
+
const parsed = parseCommandArgs(args.slice(3));
|
|
10
|
+
const projectRoot = parsed.options.get("project-root")?.[0];
|
|
11
|
+
if (!isNativeHookIngress(args) || parsed.positional.length || !projectRoot || projectRoot === "__dd_flow_flag__")
|
|
12
|
+
throw new AppError("usage", "Native hook requires --project-root", 2);
|
|
13
|
+
for (const [name, values] of parsed.options)
|
|
14
|
+
if (!["project-root", "json"].includes(name) || values.length !== 1 || name === "json" && values[0] !== "__dd_flow_flag__")
|
|
15
|
+
throw new AppError("usage", `Invalid native hook option: ${name}`, 2);
|
|
16
|
+
const [hooks, { createContext }, { resolveDdFlowHome }] = await Promise.all([
|
|
17
|
+
import("../services/hooks.js"), import("../runtime/context.js"), import("../storage/paths.js")
|
|
18
|
+
]);
|
|
19
|
+
let opened;
|
|
20
|
+
// Reuse the actual envelope validators and shell parser. They return for
|
|
21
|
+
// unrelated tools before their first DB access, without duplicating policy.
|
|
22
|
+
const context = {
|
|
23
|
+
env, ddFlowHome: resolveDdFlowHome(env), now: () => new Date().toISOString(),
|
|
24
|
+
get db() { return (opened ??= createContext(env, "hook")).db; }
|
|
25
|
+
};
|
|
26
|
+
const handler = args[0] === "agy" ? hooks.handleAgyEvent : args[0] === "grok" ? hooks.handleGrokEvent
|
|
27
|
+
: args[0] === "droid" ? hooks.handleDroidEvent : args[0] === "opencode" ? hooks.handleOpenCodeEvent
|
|
28
|
+
: args[1] === "hook" ? hooks.handleZcodeHook : hooks.handleZcodeEvent;
|
|
29
|
+
try {
|
|
30
|
+
return await handler(context, { projectRoot, stdin });
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
opened?.db.close?.();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export async function runNativeHookIngress(args) {
|
|
37
|
+
try {
|
|
38
|
+
const { readNativeHookInput, hookBudget } = await import("../harness-runtime/lib/native-hook-command.mjs");
|
|
39
|
+
const stdin = await readNativeHookInput(process.stdin, hookBudget());
|
|
40
|
+
process.stdout.write(`${JSON.stringify(await dispatchNativeHook(args, stdin, process.env))}\n`);
|
|
41
|
+
return 0;
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const record = errorRecord(error);
|
|
45
|
+
process.stderr.write(`${JSON.stringify({ ok: false, error: record })}\n`);
|
|
46
|
+
return record.exitCode;
|
|
47
|
+
}
|
|
48
|
+
}
|