@deksden-com/dd-flow-cli 0.9.0-beta.103 → 0.9.0-beta.104
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
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.104",
|
|
4
|
+
"cli_commit": "d8b1b96db830c5e56e8409dfc94837fb73638673",
|
|
5
|
+
"built_at": "2026-09-25T13:44:30.094Z",
|
|
6
6
|
"built_with_canon": {
|
|
7
7
|
"version": "4.1.1",
|
|
8
8
|
"commit": "678daa038287c948ada5b2d785a6dcc925c7b891",
|
package/dist/cli/run-cli.js
CHANGED
|
@@ -304,10 +304,16 @@ export async function runCli(args, io = defaultIo, env = process.env) {
|
|
|
304
304
|
let earlyContext;
|
|
305
305
|
try {
|
|
306
306
|
const command = quote(["dd-flow", ...output.args]);
|
|
307
|
-
const
|
|
308
|
-
|
|
307
|
+
const router = createRouterContext(env);
|
|
308
|
+
const event = observedLifecycleNativeEvent(router, command, env.DD_FLOW_DAEMON_ID);
|
|
309
|
+
// A correctable prepare rejection precedes the terminal command's
|
|
310
|
+
// single-use claim. Correlate its unique hook by the same lifecycle
|
|
311
|
+
// match key used at dispatch, including compound provider tool shells;
|
|
312
|
+
// otherwise a repaired retry sees two fresh, unclaimed events.
|
|
313
|
+
if (event || (error.details.phase === "prepare" && error.details.effect === "no_effect"
|
|
314
|
+
&& fs.existsSync(path.join(router.ddFlowHome, "db.sqlite")))) {
|
|
309
315
|
earlyContext = createContext({ ...env }, "hook");
|
|
310
|
-
observeLifecycleCommand(earlyContext, command, event)({ error });
|
|
316
|
+
observeLifecycleCommand(earlyContext, command, event ?? undefined)({ error });
|
|
311
317
|
}
|
|
312
318
|
}
|
|
313
319
|
catch (persistence) {
|
|
@@ -53,15 +53,20 @@ export async function prepareRuntimeOwner(config, stateDir, env = process.env) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export async function assertDaemonOwnership(stateDir, dispatch = {}, assertCurrent = () => {}) {
|
|
56
|
-
for (const lease of leases.values())
|
|
57
|
-
if (lease.error) throw lease.error;
|
|
58
|
-
if (Date.now() >= lease.expiresAt) throw Object.assign(new Error("managed process renewal is overdue"), { code: "process_ownership_unknown" });
|
|
59
|
-
}
|
|
56
|
+
for (const lease of leases.values()) if (!lease.stateDir && lease.error) throw lease.error;
|
|
60
57
|
const state = JSON.parse(await readFile(path.join(stateDir, "daemon.json"), "utf8"));
|
|
61
58
|
const owner = bindRuntimeOwner({ runtime_owner: state.config?.runtime_owner ?? null }, {});
|
|
62
59
|
if (!owner) return;
|
|
63
60
|
const record = state.resource_process;
|
|
64
61
|
if (owner.state_dir !== stateDir || !record?.id || !record.lease_token) throw Object.assign(new Error("owned daemon has no confirmed resource binding"), { code: "process_ownership_unknown" });
|
|
62
|
+
for (const lease of leases.values()) {
|
|
63
|
+
if (lease.stateDir !== stateDir) continue;
|
|
64
|
+
if (Date.now() >= lease.expiresAt) throw Object.assign(new Error("managed process renewal is overdue"), { code: "process_ownership_unknown", details: { process_id: lease.record.id, cause: lease.error ? errorRecord(lease.error) : null } });
|
|
65
|
+
// A failed renewal is not a lost lease. Reconfirm before productive work;
|
|
66
|
+
// never dispatch on the old lease merely because it has time remaining.
|
|
67
|
+
if (lease.error && !lease.lost) await heartbeatDaemonProcess(lease.config, lease.record);
|
|
68
|
+
if (lease.error) throw lease.error;
|
|
69
|
+
}
|
|
65
70
|
for (;;) {
|
|
66
71
|
assertCurrent();
|
|
67
72
|
const result = await runtimeProcess(state.config, "admission", { id: record.id, "lease-token": record.lease_token, owner: owner.owner_id, "state-dir": stateDir, "daemon-id": state.daemon_id ?? state.config?.daemonId, ...dispatch });
|
|
@@ -211,7 +216,7 @@ export async function heartbeatDaemonProcess(config, record) {
|
|
|
211
216
|
if (!record?.id || !record.lease_token) return;
|
|
212
217
|
let lease = leases.get(record.id);
|
|
213
218
|
if (!lease) {
|
|
214
|
-
lease = { pending: null, error: null, timer: null, lost: false, expiresAt: Date.now() + 300_000 };
|
|
219
|
+
lease = { pending: null, error: null, timer: null, lost: false, expiresAt: Date.now() + 300_000, stateDir: config.runtime_owner?.state_dir, config, record };
|
|
215
220
|
leases.set(record.id, lease);
|
|
216
221
|
lease.timer = setInterval(() => { void heartbeatDaemonProcess(config, record).catch(() => {}); }, 60_000);
|
|
217
222
|
lease.timer.unref();
|
|
@@ -228,7 +233,7 @@ export async function heartbeatDaemonProcess(config, record) {
|
|
|
228
233
|
lease.error = null;
|
|
229
234
|
lease.expiresAt = Date.now() + 300_000;
|
|
230
235
|
} catch (cause) {
|
|
231
|
-
lease.error = cause.code === "process_lease_lost" ? cause : Object.assign(new Error("cannot confirm managed process ownership"), { code: "process_ownership_unknown", cause, details: { process_id: record.id } });
|
|
236
|
+
lease.error = cause.code === "process_lease_lost" ? cause : Object.assign(new Error("cannot confirm managed process ownership"), { code: "process_ownership_unknown", cause, details: { process_id: record.id, cause: errorRecord(cause) } });
|
|
232
237
|
throw lease.error;
|
|
233
238
|
}
|
|
234
239
|
})();
|