@deksden-com/dd-flow-cli 0.9.0-beta.96 → 0.9.0-beta.97
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/dist/build-info.json +3 -3
- package/dist/harness-runtime/bin/dd-codex.mjs +2 -2
- package/dist/harness-runtime/bin/dd-droid.mjs +1 -1
- package/dist/harness-runtime/bin/dd-zcode.mjs +2 -2
- package/dist/harness-runtime/lib/dd-droid-daemon.mjs +1 -1
- package/dist/harness-runtime/lib/dd-droid.mjs +4 -4
- package/dist/harness-runtime/lib/dd-grok.mjs +1 -1
- package/dist/services/hooks.js +4 -3
- package/dist/services/native-session-control.js +1 -1
- package/dist/services/run-control.js +2 -2
- package/package.json +1 -1
package/dist/build-info.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"cli_package": "@deksden-com/dd-flow-cli",
|
|
3
|
-
"cli_version": "0.9.0-beta.
|
|
4
|
-
"cli_commit": "
|
|
5
|
-
"built_at": "2026-09-
|
|
3
|
+
"cli_version": "0.9.0-beta.97",
|
|
4
|
+
"cli_commit": "4d478c7dd9549a5b81ed5cd77d4f04befebf6f1c",
|
|
5
|
+
"built_at": "2026-09-22T15:35:15.503Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
7
|
"version": "4.1.1",
|
|
8
8
|
"commit": "678daa038287c948ada5b2d785a6dcc925c7b891",
|
|
@@ -3,8 +3,8 @@ import { durableDaemonStart, inspectDaemonOperation, interruptDaemonOperation, s
|
|
|
3
3
|
import { cancelSession, createSession, doctor, inspectSession, promptFromFile, promptSession, startSession } from "../lib/dd-codex.mjs";
|
|
4
4
|
import { callDaemon, serveDaemon, startDaemon, stopDaemon } from "../lib/dd-codex-daemon.mjs";
|
|
5
5
|
|
|
6
|
-
function parse(argv) { const positional = []; const options = {}; for (let i = 0; i < argv.length; i += 1) { const token = argv[i]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json", "cancel-tree"].includes(key)) { options[key] = true; continue; } const value = argv[++i]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value; } return { positional, options }; }
|
|
7
|
-
function common(options) { return { bin: options["codex-bin"], journal: options.journal, stateDir: options["state-dir"], cwd: options.cwd, sessionId: options["session-id"], turnId: options["turn-id"], model: options.model, reasoning: options.reasoning, ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], timeoutMs: options.timeout ? Number(options.timeout) * 1000 : undefined }; }
|
|
6
|
+
function parse(argv) { const positional = []; const options = {}; for (let i = 0; i < argv.length; i += 1) { const token = argv[i]; if (!token.startsWith("--")) { positional.push(token); continue; } const key = token.slice(2); if (["json", "cancel-tree", "no-flow"].includes(key)) { options[key] = true; continue; } const value = argv[++i]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value; } return { positional, options }; }
|
|
7
|
+
function common(options) { return { bin: options["codex-bin"], journal: options.journal, stateDir: options["state-dir"], cwd: options.cwd, sessionId: options["session-id"], turnId: options["turn-id"], model: options.model, reasoning: options.reasoning, ddFlowBin: options["dd-flow-bin"], ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], noFlow: options["no-flow"] === true, timeoutMs: options.timeout ? Number(options.timeout) * 1000 : undefined }; }
|
|
8
8
|
try {
|
|
9
9
|
const { positional, options } = parse(process.argv.slice(2)); const [family, command, modifier] = positional; const shared = common(options); let result;
|
|
10
10
|
if (family === "doctor") result = await doctor(shared);
|
|
@@ -27,7 +27,7 @@ try {
|
|
|
27
27
|
else if (family === "daemon" && command === "operation") result = await inspectDaemonOperation(config.stateDir, options["operation-id"]);
|
|
28
28
|
else if (family === "daemon" && command === "stop") result = await stopDaemon({ stateDir: config.stateDir, cancelTree: options["cancel-tree"] });
|
|
29
29
|
else if (family === "hook" && command === "handle") { const payload = JSON.parse(await input()); const eventId = randomUUID(); result = await callDaemon(config.stateDir, "hook.observe", { payload, eventId }, 25_000, eventId); }
|
|
30
|
-
else if (family === "session") { if (command === "fork") throw new Error("Droid fork is not qualified for this adapter"); const prompt = options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt; result = await callDaemon(config.stateDir, `session.${command === "status" ? "inspect" : command}`, { sessionId: options["session-id"], ...(prompt ? { prompt } : {}) }); }
|
|
30
|
+
else if (family === "session") { if (command === "fork") throw new Error("Droid fork is not qualified for this adapter"); const prompt = options["prompt-file"] ? await readFile(options["prompt-file"], "utf8") : options.prompt; result = await callDaemon(config.stateDir, `session.${command === "status" ? "inspect" : command}`, { sessionId: options["session-id"], ...(config.noFlow ? { noFlow: true } : {}), ...(prompt ? { prompt } : {}) }); }
|
|
31
31
|
else throw new Error("usage: dd-droid doctor | daemon start|status|operation|stop | session create|resume|prompt|inspect|cancel");
|
|
32
32
|
process.stdout.write(`${JSON.stringify(family === "hook" ? { ...(result.hookSpecificOutput ? { hookSpecificOutput: result.hookSpecificOutput } : {}), ...(typeof result.continue === "boolean" ? { continue: result.continue } : {}), ...(result.stopReason ? { stopReason: result.stopReason } : {}) } : { ok: true, ...result })}\n`);
|
|
33
33
|
} catch (error) { process.stderr.write(`${JSON.stringify({ ok: false, error: errorRecord(error) })}\n`); process.exitCode = process.argv[2] === "hook" ? 2 : 1; }
|
|
@@ -9,7 +9,7 @@ function parse(argv) {
|
|
|
9
9
|
for (let index = 0; index < argv.length; index += 1) {
|
|
10
10
|
const token = argv[index];
|
|
11
11
|
if (!token.startsWith("--")) { positional.push(token); continue; }
|
|
12
|
-
const key = token.slice(2); if (["json", "cancel-tree"].includes(key)) { options[key] = true; continue; }
|
|
12
|
+
const key = token.slice(2); if (["json", "cancel-tree", "no-flow"].includes(key)) { options[key] = true; continue; }
|
|
13
13
|
const value = argv[++index]; if (value === undefined) throw new Error(`--${key} requires a value`); options[key] = value;
|
|
14
14
|
}
|
|
15
15
|
return { positional, options };
|
|
@@ -29,7 +29,7 @@ function common(options) {
|
|
|
29
29
|
childSessionId: options["child-session-id"],
|
|
30
30
|
model: options.model, reasoning: options.reasoning, mode: options.mode,
|
|
31
31
|
permission: options.permission ?? "deny", ddFlowBin: options["dd-flow-bin"],
|
|
32
|
-
ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"],
|
|
32
|
+
ddFlowHome: options["dd-flow-home"], projectRoot: options["project-root"], noFlow: options["no-flow"] === true,
|
|
33
33
|
env: options["dd-flow-home"] ? { DD_FLOW_HOME: options["dd-flow-home"] } : undefined,
|
|
34
34
|
timeoutMs: seconds("timeout"),
|
|
35
35
|
livenessTimeoutMs: seconds("liveness-timeout"),
|
|
@@ -63,7 +63,7 @@ export async function serveDaemon(stateDir) {
|
|
|
63
63
|
const params = request.params ?? {}, operation = request.operation;
|
|
64
64
|
if (operation === "daemon.status") { let observationError; try { await runtime.refreshTopology(); } catch (error) { observationError = errorRecord(error); } return { observation_error: observationError ?? null, daemon_id: state.daemon_id, pid: process.pid, config: state.config, shutdown_state: state.shutdown_state, provider_ready: Boolean(runtime.child && !runtime.closed), active_operation: busy, active_tree: Boolean(runtime.active || runtime.workingState !== "idle" || runtime.topologyIncomplete || [...runtime.topology.values()].some(child => !["completed", "cancelled", "failed"].includes(child.status))), sessions: runtime.rootId ? [runtime.rootId] : [], provider_pid: runtime.closed ? null : runtime.child?.pid }; }
|
|
65
65
|
if (operation === "hook.observe") return await runtime.observeHook(params.payload, params.eventId);
|
|
66
|
-
if (operation === "session.inspect") return await runtime.inspect(params.sessionId);
|
|
66
|
+
if (operation === "session.inspect") return await runtime.inspect(params.sessionId, { ingestUsage: params.noFlow !== true });
|
|
67
67
|
if (operation === "session.cancel") {
|
|
68
68
|
runtime.requireIdentity(params.sessionId); const cleanup = await runtime.closeTree(true); let inspected;
|
|
69
69
|
try { inspected = await runtime.inspect(params.sessionId, { ignoreActive: true }); }
|
|
@@ -372,13 +372,13 @@ export class DroidRuntime {
|
|
|
372
372
|
}
|
|
373
373
|
return [...this.topology.values()];
|
|
374
374
|
}
|
|
375
|
-
async snapshotUsage(id) {
|
|
375
|
+
async snapshotUsage(id, { ingest = true } = {}) {
|
|
376
376
|
const native = await readDroidSession(this.paths.factory, id); if (!native) return { status: "unavailable", provider_session_id: id };
|
|
377
377
|
this.journaledTools ??= new Map();
|
|
378
378
|
journalToolObservations(this.config.journal, [...native.records.flatMap(record => droidToolObservations(record, id)), ...native.tool_calls.reasons.map(reason => ({ reason }))], this.journaledTools);
|
|
379
379
|
const measured = native.usage;
|
|
380
380
|
const payload = { provider_session_id: id, daemon_id: this.config.daemonId, observed_at: new Date().toISOString(), usage_scope: "physical_session", completeness: native.complete && measured ? "complete" : "partial", usage: measured, tool_calls: native.tool_calls, source: { path: native.transcript_path, sha256: native.source_sha256 } };
|
|
381
|
-
if (measured && this.config.ddFlowBin) await this.flow("usage", "ingest", payload);
|
|
381
|
+
if (ingest && measured && this.config.ddFlowBin) await this.flow("usage", "ingest", payload);
|
|
382
382
|
return { status: measured ? "measured" : "unavailable", ...payload };
|
|
383
383
|
}
|
|
384
384
|
async flow(family, command, payload) {
|
|
@@ -390,9 +390,9 @@ export class DroidRuntime {
|
|
|
390
390
|
child.on("error", error => { clearTimeout(timer); reject(error); }); child.on("close", code => { clearTimeout(timer); if (code !== 0) return reject(new DroidError("droid_flow_rejected", stderr || "dd-flow rejected Droid evidence")); try { resolve(JSON.parse(stdout)); } catch (error) { reject(error); } }); child.stdin.end(`${JSON.stringify(payload)}\n`);
|
|
391
391
|
});
|
|
392
392
|
}
|
|
393
|
-
async inspect(id, { ignoreActive = false } = {}) {
|
|
393
|
+
async inspect(id, { ignoreActive = false, ingestUsage = true } = {}) {
|
|
394
394
|
this.requireIdentity(id); await this.captureProcesses(); const children = await this.refreshTopology(); const source = await readDroidSession(this.paths.factory, id);
|
|
395
|
-
const usage = []; for (const sessionId of [id, ...children.map(child => child.provider_session_id)]) usage.push(await this.snapshotUsage(sessionId));
|
|
395
|
+
const usage = []; for (const sessionId of [id, ...children.map(child => child.provider_session_id)]) usage.push(await this.snapshotUsage(sessionId, { ingest: ingestUsage }));
|
|
396
396
|
const settled = !this.topologyIncomplete && (!this.active || ignoreActive) && (this.closed || this.workingState === "idle") && children.every(child => terminal(child.status));
|
|
397
397
|
return { harness: "droid-cli", runtime_family: "droid", session: { harness_id: "droid-cli", session_id: id }, provider_session_id: id, adapter_session_id: id, cwd: this.config.cwd, observed_profile: source?.settings ? await this.observeSettings(id, source.settings, { path: source.transcript_path, sha256: source.source_sha256 }) : this.observedProfile, observed_runtime: { droid: this.config.version, factory_protocol: this.protocol ?? DROID_PROTOCOL, dd_harness_contract: DROID_CONTRACT }, status: settled ? "idle" : "running", settled, descendants: children, transcript_path: source?.transcript_path ?? null, usage, result: this.lastResult, provider_pid: this.closed ? null : this.child?.pid ?? null };
|
|
398
398
|
}
|
|
@@ -82,7 +82,7 @@ async function inspect(bridge, sessionId, options) {
|
|
|
82
82
|
}
|
|
83
83
|
|
|
84
84
|
async function forwardUsage(options, providerSessionId, usage, toolCalls) {
|
|
85
|
-
if (!options.ddFlowBin || !usage || usage.unavailable) return;
|
|
85
|
+
if (options.noFlow || !options.ddFlowBin || !usage || usage.unavailable) return;
|
|
86
86
|
const measured = usage.usage && typeof usage.usage === "object" ? usage.usage : usage;
|
|
87
87
|
const input = JSON.stringify({ provider_session_id: providerSessionId, daemon_id: options.daemonId ?? null, observed_at: new Date().toISOString(), usage: measured, tool_calls: toolCalls, usage_scope: usageScope(options, providerSessionId), completeness: measured.usageIsIncomplete ? "partial" : "complete" });
|
|
88
88
|
const target = executable(options.ddFlowBin, ["grok", "usage", "ingest", "--project-root", absolute(options.projectRoot, "--project-root"), "--json"]);
|
package/dist/services/hooks.js
CHANGED
|
@@ -743,9 +743,10 @@ export function handleAgyEvent(context, input) {
|
|
|
743
743
|
throw new AppError("agy_session_identity_invalid", "Antigravity event is missing trusted physical identity", 1);
|
|
744
744
|
const rawInput = objectRecord(event.input);
|
|
745
745
|
const command = stringValue(rawInput.command) ?? stringValue(rawInput.cmd) ?? stringValue(rawInput.CommandLine);
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
746
|
+
const invalidStep = !Number.isSafeInteger(event.step_index) || Number(event.step_index) < 0;
|
|
747
|
+
const invalidExecution = event.execution_num !== undefined && (!Number.isSafeInteger(event.execution_num) || Number(event.execution_num) < 0);
|
|
748
|
+
if (event.phase === "before" && command && (lifecycleFacts(command) || continuationCommand(command)) && (invalidStep || invalidExecution)) {
|
|
749
|
+
throw new AppError("agy_native_call_identity_missing", "Participating Antigravity lifecycle calls require a native step identity and a valid execution identity when provided", 1, { phase: "prepare", effect: "no_effect", recoverable: false });
|
|
749
750
|
}
|
|
750
751
|
const translated = {
|
|
751
752
|
schema_id: "dd-flow/opencode-tool-event@1", source_harness: "antigravity-cli", phase: event.phase, event_id: eventId,
|
|
@@ -29,7 +29,7 @@ export function assertNativeCancellationReceipt(value, sessionId) {
|
|
|
29
29
|
/** Native observation is shared by RUN and non-Work EVAL owners. */
|
|
30
30
|
export async function inspectControlledNativeSession(input) {
|
|
31
31
|
input.assertCurrent();
|
|
32
|
-
const receipt = await runHarnessAdapter({ executable: input.executable, args: ["session", "inspect", "--session-id", input.sessionId, "--state-dir", input.stateDir, "--json"], env: input.env, operationId: input.operationId, timeoutMs: 30_000 });
|
|
32
|
+
const receipt = await runHarnessAdapter({ executable: input.executable, args: ["session", "inspect", "--session-id", input.sessionId, "--state-dir", input.stateDir, ...(input.settlementObservation ? ["--no-flow"] : []), "--json"], env: input.env, operationId: input.operationId, timeoutMs: 30_000 });
|
|
33
33
|
if (adapterSessionId(receipt) !== input.sessionId)
|
|
34
34
|
throw new AppError("controller_operation_mismatch", "Session observation belongs to another target", 1);
|
|
35
35
|
if (input.harness && receipt.harness !== undefined && receipt.harness !== input.harness)
|
|
@@ -474,7 +474,7 @@ async function reconcileOwnedSessions(context, input, interrupt, boundary) {
|
|
|
474
474
|
: { session_id: session.id, state_dir: session.state_dir, harness, status: "pending", reason: "shutdown_session_unproven" };
|
|
475
475
|
if (!interrupt) {
|
|
476
476
|
try {
|
|
477
|
-
const receipt = await inspectControlledNativeSession({ executable, sessionId: session.id, stateDir: session.state_dir, harness, env, operationId: `${observationId}:inspect:${crypto.randomUUID()}`, assertCurrent });
|
|
477
|
+
const receipt = await inspectControlledNativeSession({ executable, sessionId: session.id, stateDir: session.state_dir, harness, env, operationId: `${observationId}:inspect:${crypto.randomUUID()}`, assertCurrent, settlementObservation: true });
|
|
478
478
|
return { session_id: session.id, state_dir: session.state_dir, harness: harness ?? (typeof receipt.harness === "string" ? receipt.harness : null), status: receipt.settled === true ? "completed" : "pending", receipt };
|
|
479
479
|
}
|
|
480
480
|
catch (error) {
|
|
@@ -511,7 +511,7 @@ async function reconcileOwnedSessions(context, input, interrupt, boundary) {
|
|
|
511
511
|
return { operation_id: operationId, session_id: session.id, status: "outcome_unknown", error: cancellationError };
|
|
512
512
|
}
|
|
513
513
|
try {
|
|
514
|
-
const observed = await inspectControlledNativeSession({ executable, sessionId: session.id, stateDir: session.state_dir, harness, env, operationId: `${observationId}:inspect:${crypto.randomUUID()}`, assertCurrent });
|
|
514
|
+
const observed = await inspectControlledNativeSession({ executable, sessionId: session.id, stateDir: session.state_dir, harness, env, operationId: `${observationId}:inspect:${crypto.randomUUID()}`, assertCurrent, settlementObservation: true });
|
|
515
515
|
return { operation_id: operationId, session_id: session.id, status: observed.settled === true ? "completed" : "pending", receipt: observed, cancellation, reused: !inserted.changes, ...(cancellationError ? { cancellation_error: cancellationError } : {}) };
|
|
516
516
|
}
|
|
517
517
|
catch (error) {
|