@deksden-com/dd-flow-cli 0.9.0-beta.37 → 0.9.0-beta.38

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 CHANGED
@@ -1,5 +1,11 @@
1
1
  # @deksden-com/dd-flow-cli
2
2
 
3
+ ## 0.9.0-beta.38
4
+
5
+ ### Patch Changes
6
+
7
+ - 44e3c80: Allow control operations to recheck failed provider cleanup after a leaderless process group exits naturally. Coalesce concurrent finalization retries, preserve the original exit and process lease, and keep live or unproven groups blocked without sending them signals.
8
+
3
9
  ## 0.9.0-beta.37
4
10
 
5
11
  ### Patch Changes
@@ -1031,6 +1037,7 @@ record` command with the bounded 15-probe contract.
1031
1037
  - 16f68a3: Add router-native engine snapshot commands and routed project-command dispatch.
1032
1038
 
1033
1039
  Also include the runtime/dashboard compatibility wave needed by the current Memory Bank canon:
1040
+
1034
1041
  - target-based dashboard `open`/`refresh` commands and related-command help;
1035
1042
  - persisted FIFO lane waiters and merge wait-acquire specialization;
1036
1043
  - `migration plan/report/verify` evidence helpers for controlled `mb-upgrade` runtime migrations;
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "cli_package": "@deksden-com/dd-flow-cli",
3
- "cli_version": "0.9.0-beta.37",
4
- "cli_commit": "04f94a5faa271bc0e837d6d3020f3a3668835e17",
5
- "built_at": "2026-09-08T02:59:50.109Z",
3
+ "cli_version": "0.9.0-beta.38",
4
+ "cli_commit": "e1d723e620ee5aeec961c2bee1de1e72fcfb71a9",
5
+ "built_at": "2026-09-08T03:57:03.109Z",
6
6
  "built_with_canon": {
7
7
  "version": "4.0.6",
8
8
  "commit": "c6fc50cb3b5526ea0162ee4454d1ee36f17be2da",
@@ -212,12 +212,16 @@ export class Runtime {
212
212
  if (this.active) { this.active.reject(error); this.active = null; }
213
213
  const patch = beforeInit ? { shutdown_state: "failed", startup_error: errorPayload(error), provider_exit: { code, signal }, active_tree: false } : { provider_exit: { code, signal }, active_tree: interrupted };
214
214
  await providerRegistered;
215
- try {
216
- await stopProcessGroup(providerChild);
217
- await this.persist(patch);
218
- await finishDaemonProcess(this.config, providerProcess, beforeInit || interrupted ? "failed" : "stopped", beforeInit || interrupted ? "provider_interrupted" : "provider_stopped");
219
- } catch (cleanup) { await this.persist({ shutdown_state: "cleanup_failed", active_tree: true, cleanup_error: errorPayload(cleanup) }); throw cleanup; }
220
- finally { if (beforeInit) this.server?.close(); }
215
+ this.retryProviderFinalization = async (graceMs = 1_000) => {
216
+ try {
217
+ await stopProcessGroup(providerChild, graceMs);
218
+ await this.persist(patch);
219
+ await finishDaemonProcess(this.config, providerProcess, beforeInit || interrupted ? "failed" : "stopped", beforeInit || interrupted ? "provider_interrupted" : "provider_stopped");
220
+ this.retryProviderFinalization = null;
221
+ } catch (cleanup) { await this.persist({ shutdown_state: "cleanup_failed", active_tree: true, cleanup_error: errorPayload(cleanup) }); throw cleanup; }
222
+ finally { if (beforeInit) this.server?.close(); }
223
+ };
224
+ await this.retryProviderFinalization();
221
225
  }).then(resolve, reject);
222
226
  });
223
227
  });
@@ -328,13 +332,25 @@ export class Runtime {
328
332
  await observeModel({ journal: this.config.journal, harness: "antigravity-cli", sessionId: conversationId, parentSessionId: parent, requested: this.config, observed, source: "native.hook", evidence: payload.model ? "configured" : "unavailable", reason: payload.model ? null : "hook_omits_current_model" });
329
333
  const eventId = createHash("sha256").update(JSON.stringify({ daemon: this.config.daemonId, event, conversationId, turn_generation: this.turnGeneration, fully_idle: payload.fullyIdle ?? null, termination_reason: payload.terminationReason ?? null, execution: payload.executionNum ?? null, step: payload.stepIdx ?? null, tool: payload.toolCall?.name ?? null, args: payload.toolCall?.args ?? null })).digest("hex"); await this.persist(completed ? { active_tree: false } : {}); await this.journal("hook", { stale, hook_event: event, event_id: eventId, conversation_id: conversationId, turn_generation: this.turnGeneration, execution_num: execution, step_index: step, termination_reason: payload.terminationReason ?? null, fully_idle: payload.fullyIdle ?? null }); completed?.resolve(settled); return { event_id: eventId, daemon_id: this.config.daemonId, parent_conversation_id: parent, profile: observed, requested_profile: { provider: this.config.provider, model: this.config.model, reasoning: this.config.reasoning, mode: this.config.mode }, project_root: this.config.projectRoot, dd_flow_bin: this.config.ddFlowBin, dd_flow_home: this.config.ddFlowHome };
330
334
  }
331
- async cancel() { cancelPendingDispatch(this); if (!this.child) return { ...this.receipt(), settled: Boolean(this.exited) }; if (!this.exited) { try { process.kill(-this.child.pid, "SIGINT"); } catch (error) { if (error.code !== "ESRCH") throw error; } const deadline = Date.now() + 5000; while (!this.exited && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 100)); if (!this.exited) await stopProcessGroup(this.child, 5_000); } await this.providerFinalization; await this.persist({ active_tree: false }); return { ...this.receipt(), cancelled: true, settled: Boolean(this.exited) };
335
+ async finalizeProviderForControl() {
336
+ const pending = this.providerFinalization;
337
+ try { await pending; }
338
+ catch (error) {
339
+ // A leaderless group may have exited naturally since the last check.
340
+ // Only control may recheck it; startup never retries failed cleanup.
341
+ if (this.providerFinalization !== pending) return await this.providerFinalization;
342
+ if (error.code !== "process_group_ownership_unknown" || !this.retryProviderFinalization) throw error;
343
+ this.providerFinalization = this.retryProviderFinalization(5_000);
344
+ await this.providerFinalization;
345
+ }
346
+ }
347
+ async cancel() { cancelPendingDispatch(this); if (!this.child) return { ...this.receipt(), settled: Boolean(this.exited) }; if (!this.exited) { try { process.kill(-this.child.pid, "SIGINT"); } catch (error) { if (error.code !== "ESRCH") throw error; } const deadline = Date.now() + 5000; while (!this.exited && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 100)); if (!this.exited) await stopProcessGroup(this.child, 5_000); } await this.finalizeProviderForControl(); await this.persist({ active_tree: false }); return { ...this.receipt(), cancelled: true, settled: Boolean(this.exited) };
332
348
  }
333
349
  async close(cancelTree) { if (cancelTree) cancelPendingDispatch(this); if (!cancelTree && (this.active || this.state.active_tree || this.state.unclaimed_activity || (this.lastResult && !this.receipt().settled))) throw new DaemonError("tree_not_settled", "Antigravity root or child tree is still running"); if (cancelTree) await this.cancel(); else if (this.child && !this.exited) this.child.stdin.end(); const deadline = Date.now() + 5000; while (!this.exited && Date.now() < deadline) await new Promise(resolve => setTimeout(resolve, 100)); if (!this.exited) await this.cancel(); await this.providerFinalization; }
334
350
  async abortProvider(reason) {
335
351
  const child = this.child, providerProcess = this.providerProcess;
336
352
  await stopProcessGroup(child);
337
- await this.providerFinalization;
353
+ await this.finalizeProviderForControl();
338
354
  await finishDaemonProcess(this.config, providerProcess, "failed", reason);
339
355
  }
340
356
  async finishResource(state = "stopped", reason = "daemon_stopped") { await finishDaemonProcess(this.config, this.state.resource_process, state, reason); }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deksden-com/dd-flow-cli",
3
- "version": "0.9.0-beta.37",
3
+ "version": "0.9.0-beta.38",
4
4
  "description": "Mechanical runtime CLI for dd-flow workflows.",
5
5
  "type": "module",
6
6
  "bin": {