@deksden-com/dd-flow-cli 0.9.0-beta.51 → 0.9.0-beta.52

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.52
4
+
5
+ ### Patch Changes
6
+
7
+ - Distinguish released workspace leases from physical processes during stage-boundary capture, RUN settlement and runtime-scope stop/drain. Preserve active-lease, child-process, physical-identity and exact registration checks instead of waiting forever for a PID on a logical gate.
8
+
3
9
  ## 0.9.0-beta.51
4
10
 
5
11
  ### Patch Changes
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "cli_package": "@deksden-com/dd-flow-cli",
3
- "cli_version": "0.9.0-beta.51",
4
- "cli_commit": "66660a1dc362cce527bfc33bd2e8124aff6a33c1",
5
- "built_at": "2026-09-11T23:08:17.146Z",
3
+ "cli_version": "0.9.0-beta.52",
4
+ "cli_commit": "9f8e20f5aab016e2e7246b8939af9e4ad91e37dc",
5
+ "built_at": "2026-09-12T14:24:25.044Z",
6
6
  "built_with_canon": {
7
7
  "version": "4.1.0",
8
8
  "commit": "ef349bf47cba1c987468e51d73a0dbadbd48dc1f",
@@ -175,6 +175,13 @@ export function claimExpiredManagedProcesses(context, ownerId) {
175
175
  throw error;
176
176
  }
177
177
  }
178
+ /** Workspace gates are leases, not spawned processes. Children retain their own registrations. */
179
+ export function managedLeaseReleased(record) {
180
+ const metadata = parseMetadata(record.metadata_json);
181
+ return record.kind === "workspace-gate" && record.pid === null && record.pid_started_at === null
182
+ && metadata.process_group_id == null && metadata.role === "check_gate"
183
+ && ["stopped", "failed"].includes(record.state) && Boolean(record.finished_at);
184
+ }
178
185
  export function managedProcessStatus(context) {
179
186
  return registry(context).all("SELECT * FROM managed_processes ORDER BY updated_at DESC, id");
180
187
  }
@@ -9,7 +9,7 @@ import path from "node:path";
9
9
  import { adapterSessionId, runHarnessAdapter } from "./harness-adapter.js";
10
10
  import { runtimeHarness } from "./execution-policy.js";
11
11
  import { harnessKey } from "./harness-config.js";
12
- import { finishManagedProcess, managedProcessBinding, managedProcessRuntimeHome, managedProcessStatus, processIsAlive, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
12
+ import { finishManagedProcess, managedLeaseReleased, managedProcessBinding, managedProcessRuntimeHome, managedProcessStatus, processIsAlive, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
13
13
  import { reconcileUnfinishedChecks } from "./code-checks.js";
14
14
  import { controlStatusReceipt } from "./run-control-receipt.js";
15
15
  import { assertNativeCancellationReceipt, cancelControlledNativeSession, inspectControlledNativeSession } from "./native-session-control.js";
@@ -473,6 +473,10 @@ async function reconcileOwnedSessions(context, input, interrupt, boundary) {
473
473
  }
474
474
  }));
475
475
  const processResults = Promise.all(processTargets.map(async ({ home, record }) => {
476
+ if (managedLeaseReleased(record))
477
+ return { process_id: record.id, kind: record.kind, status: "completed", receipt: { source: "managed_lease_released", ...managedProcessBinding(record, home), finished_at: record.finished_at } };
478
+ if (record.kind === "workspace-gate")
479
+ return { process_id: record.id, kind: record.kind, status: "pending", reason: "managed_lease_unsettled" };
476
480
  if (!record.pid || !record.pid_started_at)
477
481
  return { process_id: record.id, kind: record.kind, status: "pending", reason: "managed_process_identity_unknown" };
478
482
  if (!interrupt && processTreeIsAlive(record))
@@ -4,7 +4,7 @@ import path from "node:path";
4
4
  import { createContext } from "../runtime/context.js";
5
5
  import { getResourceDatabase } from "../storage/database.js";
6
6
  import { AppError } from "../shared/errors.js";
7
- import { finishManagedProcess, managedProcessBinding, managedProcessStatus, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
7
+ import { finishManagedProcess, managedLeaseReleased, managedProcessBinding, managedProcessStatus, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
8
8
  import { requestRuntimeScopeControl, runtimeBudgetStatus, scopeLocalProcessRole, validateRuntimeScopeManifest } from "./runtime-budget.js";
9
9
  import { nativeInventoryVersion, recordRunControlIntent, retainedDaemonOperations, runControlStatus } from "./run-control.js";
10
10
  import { requestRunControl } from "./run-control-worker.js";
@@ -125,7 +125,7 @@ export function retainScopeDrain(context, control, processes, runs, native, prob
125
125
  }
126
126
  export function scopeRunProcessEvidence(record, runs, registryHome) {
127
127
  const metadata = JSON.parse(record.metadata_json);
128
- if (!record.pid || !record.pid_started_at || !record.project_id || !record.run_id || !metadata.dd_flow_home)
128
+ if ((!managedLeaseReleased(record) && (!record.pid || !record.pid_started_at)) || !record.project_id || !record.run_id || !metadata.dd_flow_home)
129
129
  return null;
130
130
  for (const run of runs) {
131
131
  if (run.runtime_home !== metadata.dd_flow_home || run.project_id !== record.project_id || run.run_id !== record.run_id)
@@ -3,7 +3,7 @@ import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import { AppError } from "../shared/errors.js";
5
5
  import { runHarnessAdapter } from "./harness-adapter.js";
6
- import { managedProcessBinding, managedProcessStatus, processIsAlive, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
6
+ import { managedLeaseReleased, managedProcessBinding, managedProcessStatus, processIsAlive, processTreeIsAlive, resourceHome, stopManagedProcess } from "./managed-processes.js";
7
7
  import { fenceRuntimeBudget, runtimeBudgetStatus, scopeLocalProcessRole } from "./runtime-budget.js";
8
8
  import { retainedDaemonOperations } from "./run-control.js";
9
9
  import { historicalDaemonSettlement } from "./native-daemon-history.js";
@@ -62,6 +62,10 @@ export async function stopRuntimeScope(context, scopeId, requestId) {
62
62
  for (const record of runtimeBudgetStatus(context, scopeId).processes) {
63
63
  if (covered.has(record.id))
64
64
  continue;
65
+ if (managedLeaseReleased(record)) {
66
+ nodes.push({ process_id: record.id, settled: true });
67
+ continue;
68
+ }
65
69
  const metadata = JSON.parse(record.metadata_json);
66
70
  // RUN control owns active controllers/checks. Adopt only its already-finished
67
71
  // physical registrations here; death alone is not a completed RUN operation.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deksden-com/dd-flow-cli",
3
- "version": "0.9.0-beta.51",
3
+ "version": "0.9.0-beta.52",
4
4
  "description": "Mechanical runtime CLI for dd-flow workflows.",
5
5
  "type": "module",
6
6
  "bin": {