@devrouter/cli 0.0.63 → 0.0.64
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/devrouter-lifecycle-worker.js +5 -3
- package/dist/devrouter.js +25 -21
- package/package.json +1 -1
- package/upgrade-prompts/0.0.64.md +34 -0
|
@@ -240,7 +240,9 @@ function tryReclaimStaleLock(lockPath, staleLinkPath, livenessCache) {
|
|
|
240
240
|
function acquireFileLock(lockPath, options) {
|
|
241
241
|
const processBirth = processBirthIdentity(process.pid);
|
|
242
242
|
if (!processBirth) {
|
|
243
|
-
throw new Error(
|
|
243
|
+
throw new Error(
|
|
244
|
+
`could not determine process identity for ${options.activity} lock: process inspection may be unavailable or sandbox-denied; run the canonical command in a permitted host context`
|
|
245
|
+
);
|
|
244
246
|
}
|
|
245
247
|
const ownerId = (0, import_node_crypto2.randomUUID)();
|
|
246
248
|
const owner = `${process.pid}:${Buffer.from(processBirth).toString("base64url")}:${ownerId}`;
|
|
@@ -4705,7 +4707,7 @@ function loadRepoConfig(repoPath, read = (file) => import_node_fs14.default.read
|
|
|
4705
4707
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
4706
4708
|
const requiredVersion = config.devrouter?.version;
|
|
4707
4709
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4708
|
-
const cliVersion = true ? "0.0.
|
|
4710
|
+
const cliVersion = true ? "0.0.64" : "0.0.0-dev";
|
|
4709
4711
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4710
4712
|
hasWarnedVersionMismatch = true;
|
|
4711
4713
|
process.stderr.write(
|
|
@@ -9442,7 +9444,7 @@ var cancelled = false;
|
|
|
9442
9444
|
var lockHeld = false;
|
|
9443
9445
|
var stopProjects = [];
|
|
9444
9446
|
var stopBaselineState;
|
|
9445
|
-
var
|
|
9447
|
+
var BUSY_LIFECYCLE_WAIT_MS = 30 * 60 * 1e3;
|
|
9446
9448
|
function matchesFence(record4, fence) {
|
|
9447
9449
|
return Object.entries(reliabilityFence(record4.state)).every(
|
|
9448
9450
|
([key, value]) => value === fence[key]
|
package/dist/devrouter.js
CHANGED
|
@@ -671,7 +671,9 @@ function tryReclaimStaleLock(lockPath, staleLinkPath, livenessCache) {
|
|
|
671
671
|
function acquireFileLock(lockPath, options) {
|
|
672
672
|
const processBirth = processBirthIdentity(process.pid);
|
|
673
673
|
if (!processBirth) {
|
|
674
|
-
throw new Error(
|
|
674
|
+
throw new Error(
|
|
675
|
+
`could not determine process identity for ${options.activity} lock: process inspection may be unavailable or sandbox-denied; run the canonical command in a permitted host context`
|
|
676
|
+
);
|
|
675
677
|
}
|
|
676
678
|
const ownerId = (0, import_node_crypto2.randomUUID)();
|
|
677
679
|
const owner = `${process.pid}:${Buffer.from(processBirth).toString("base64url")}:${ownerId}`;
|
|
@@ -2450,7 +2452,7 @@ function loadRepoConfig(repoPath, read = (file) => import_node_fs6.default.readF
|
|
|
2450
2452
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
2451
2453
|
const requiredVersion = config.devrouter?.version;
|
|
2452
2454
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
2453
|
-
const cliVersion = true ? "0.0.
|
|
2455
|
+
const cliVersion = true ? "0.0.64" : "0.0.0-dev";
|
|
2454
2456
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
2455
2457
|
hasWarnedVersionMismatch = true;
|
|
2456
2458
|
process.stderr.write(
|
|
@@ -7169,7 +7171,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
7169
7171
|
"- TLS: namespaced hosts (`web.<ws>.localhost`) are not covered by the `*.localhost` wildcard; devrouter auto-extends the mkcert cert SANs for active hosts when TLS is enabled.",
|
|
7170
7172
|
"- Lifecycle: after one-time setup, use `devrouter ensure .` for both primary and linked checkouts; never branch on checkout kind or use live verify as startup. Managed consumer images contain no devrouter package/helper: ensure delivers its matching helper at runtime and invokes an exact captured snapshot of the repository-owned post-start adapter. Keep `.devrouter.yml` as the only consumer-side version pin. Use `devrouter stop .` for a non-destructive pause, `devrouter stop . --delete` only for explicit exact-owner cleanup without removing the checkout, and `devrouter exec . -- <command...>` for container commands. Never substitute raw DevPod/Devsy mutations; they bypass the machine-global ownership lock, which serializes provider mutations in a fair arrival-order queue and lets contenders wait up to thirty minutes with throttled stderr progress before failing with the queue position or holder PID and true durations. `workspace up` creates linked worktrees; destructive worktree removal and GC remain ledger-scoped.",
|
|
7171
7173
|
"- After a drained interrupted ensure, manual exec can use an exactly proven retained Devsy runtime with the plain local Docker command. Revalidate identity for each tooling command until later preparation reconciles startup; preserve configuration, data and interrupted history. This does not repair absent stop baselines or provide OOM protection.",
|
|
7172
|
-
"- Busy exec
|
|
7174
|
+
"- Busy ensure and exec wait up to thirty minutes for a positively identified active lifecycle worker on the same checkout, with stderr progress. Do not stop healthy work to make room. Commands stay serial; timeout or cancellation before admission leaves prior work untouched. A lifecycle fence change cancels admission, and uncertain execution is never replayed.",
|
|
7173
7175
|
"- Ensure reconciles interrupted or never-dispatched ensure after positive worker drainage. Unknown arbitrary exec never replays; use explicit stop to reconcile that uncertainty. Preserve journals and generated configuration if evidence is unavailable. This does not prevent OOM or activate capacity-managed recovery.",
|
|
7174
7176
|
"- Devsy agent readiness: run `devrouter setup --yes --workspace-runtime devsy` once so Devrouter acquires and verifies the pinned agent in its own machine cache. `doctor` reports `ready`, `missing`, `stale`, or `invalid` without network access, and `ensure` fails before the provider queue when readiness is not `ready`. An explicit `DEVSY_AGENT_BINARY` remains authoritative and must match a pinned official asset.",
|
|
7175
7177
|
"- A managed adapter plus `postCreateCommand` requires `waitFor` exactly `postCreateCommand` or `postStartCommand`; managed selective config preserves lifecycle fields and changes only `runServices`.",
|
|
@@ -12158,7 +12160,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
12158
12160
|
const config = runtimeConfig.config;
|
|
12159
12161
|
loadedConfig = config;
|
|
12160
12162
|
loadedWorkspace = runtimeConfig.workspace;
|
|
12161
|
-
const cliVersion = true ? "0.0.
|
|
12163
|
+
const cliVersion = true ? "0.0.64" : "0.0.0-dev";
|
|
12162
12164
|
const configVersion = config.devrouter?.version;
|
|
12163
12165
|
if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
|
|
12164
12166
|
addCheck(checks, {
|
|
@@ -14050,9 +14052,9 @@ function reconcileDrained(record4) {
|
|
|
14050
14052
|
record4.worker = null;
|
|
14051
14053
|
}
|
|
14052
14054
|
}
|
|
14053
|
-
function
|
|
14055
|
+
function reportBusyLifecycleWait(kind, operationId, waitedMs) {
|
|
14054
14056
|
process.stderr.write(
|
|
14055
|
-
`Lifecycle
|
|
14057
|
+
`Lifecycle ${kind} ${operationId} is waiting for the existing worker (${Math.ceil(waitedMs / 1e3)}s).
|
|
14056
14058
|
`
|
|
14057
14059
|
);
|
|
14058
14060
|
}
|
|
@@ -14091,16 +14093,16 @@ async function superviseLifecycle(kind, repoPath, options = {}, command) {
|
|
|
14091
14093
|
}
|
|
14092
14094
|
const initial = readReliabilityOperation(identity2) ?? updateReliabilityOperation(identity2, (record4) => record4);
|
|
14093
14095
|
const expectedFence = reliabilityFence(initial.state);
|
|
14094
|
-
const deadline = Date.now() +
|
|
14096
|
+
const deadline = Date.now() + BUSY_LIFECYCLE_WAIT_MS;
|
|
14095
14097
|
const cancellation = { requested: false };
|
|
14096
14098
|
const removeSignals = installLifecycleWaitSignals(cancellation);
|
|
14097
14099
|
let lastProgress = -Infinity;
|
|
14098
14100
|
const assertWaiting = () => {
|
|
14099
14101
|
if (cancellation.requested)
|
|
14100
|
-
throw new Error(`Lifecycle
|
|
14102
|
+
throw new Error(`Lifecycle ${kind} ${ids.operationId} cancelled before dispatch.`);
|
|
14101
14103
|
if (Date.now() >= deadline)
|
|
14102
14104
|
throw new Error(
|
|
14103
|
-
`Lifecycle
|
|
14105
|
+
`Lifecycle ${kind} ${ids.operationId} admission timed out; command was not launched.`
|
|
14104
14106
|
);
|
|
14105
14107
|
};
|
|
14106
14108
|
try {
|
|
@@ -14126,15 +14128,17 @@ async function superviseLifecycle(kind, repoPath, options = {}, command) {
|
|
|
14126
14128
|
throw new Error(
|
|
14127
14129
|
"Existing lifecycle worker identity or completion is uncertain; preserve its evidence."
|
|
14128
14130
|
);
|
|
14129
|
-
if (kind !== "exec")
|
|
14130
|
-
throw new Error("A lifecycle worker is active; wait for its completion before ensure.");
|
|
14131
14131
|
const now = Date.now();
|
|
14132
|
-
if (now - lastProgress >=
|
|
14133
|
-
|
|
14132
|
+
if (now - lastProgress >= BUSY_LIFECYCLE_PROGRESS_MS) {
|
|
14133
|
+
reportBusyLifecycleWait(
|
|
14134
|
+
kind,
|
|
14135
|
+
ids.operationId,
|
|
14136
|
+
now - (deadline - BUSY_LIFECYCLE_WAIT_MS)
|
|
14137
|
+
);
|
|
14134
14138
|
lastProgress = now;
|
|
14135
14139
|
}
|
|
14136
14140
|
await new Promise(
|
|
14137
|
-
(resolve) => setTimeout(resolve, Math.min(
|
|
14141
|
+
(resolve) => setTimeout(resolve, Math.min(BUSY_LIFECYCLE_POLL_MS, deadline - now))
|
|
14138
14142
|
);
|
|
14139
14143
|
continue;
|
|
14140
14144
|
}
|
|
@@ -14176,16 +14180,16 @@ async function superviseLifecycle(kind, repoPath, options = {}, command) {
|
|
|
14176
14180
|
assertWaiting
|
|
14177
14181
|
);
|
|
14178
14182
|
} catch (error) {
|
|
14179
|
-
if (!(error instanceof LifecycleWorkerAdmissionBusyError)
|
|
14183
|
+
if (!(error instanceof LifecycleWorkerAdmissionBusyError)) throw error;
|
|
14180
14184
|
assertWaiting();
|
|
14181
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
14185
|
+
await new Promise((resolve) => setTimeout(resolve, BUSY_LIFECYCLE_POLL_MS));
|
|
14182
14186
|
}
|
|
14183
14187
|
}
|
|
14184
14188
|
} finally {
|
|
14185
14189
|
removeSignals();
|
|
14186
14190
|
}
|
|
14187
14191
|
}
|
|
14188
|
-
var import_node_path41, activeWorker, lockHeld,
|
|
14192
|
+
var import_node_path41, activeWorker, lockHeld, BUSY_LIFECYCLE_WAIT_MS, BUSY_LIFECYCLE_POLL_MS, BUSY_LIFECYCLE_PROGRESS_MS;
|
|
14189
14193
|
var init_reliability_lifecycle = __esm({
|
|
14190
14194
|
"src/core/reliability-lifecycle.ts"() {
|
|
14191
14195
|
"use strict";
|
|
@@ -14208,9 +14212,9 @@ var init_reliability_lifecycle = __esm({
|
|
|
14208
14212
|
init_workspace_runtime();
|
|
14209
14213
|
init_reliability_context();
|
|
14210
14214
|
lockHeld = false;
|
|
14211
|
-
|
|
14212
|
-
|
|
14213
|
-
|
|
14215
|
+
BUSY_LIFECYCLE_WAIT_MS = 30 * 60 * 1e3;
|
|
14216
|
+
BUSY_LIFECYCLE_POLL_MS = 250;
|
|
14217
|
+
BUSY_LIFECYCLE_PROGRESS_MS = 1e4;
|
|
14214
14218
|
}
|
|
14215
14219
|
});
|
|
14216
14220
|
|
|
@@ -18902,7 +18906,7 @@ var init_version = __esm({
|
|
|
18902
18906
|
|
|
18903
18907
|
// src/cli.ts
|
|
18904
18908
|
var import_commander = require("commander");
|
|
18905
|
-
var CLI_VERSION = true ? "0.0.
|
|
18909
|
+
var CLI_VERSION = true ? "0.0.64" : "0.0.0-dev";
|
|
18906
18910
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
18907
18911
|
function withErrorHandling(action2) {
|
|
18908
18912
|
return async (...args) => {
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Upgrade to devrouter 0.0.64
|
|
2
|
+
|
|
3
|
+
This patch lets canonical ensure wait for healthy lifecycle work on the same
|
|
4
|
+
checkout and clarifies process-inspection permission failures.
|
|
5
|
+
|
|
6
|
+
## Task
|
|
7
|
+
|
|
8
|
+
Install the published patch and update `.devrouter.yml` devrouter.version to
|
|
9
|
+
0.0.64. No schema migration or runtime restart is required. Refresh distributed
|
|
10
|
+
agent guidance through the existing repository workflow.
|
|
11
|
+
|
|
12
|
+
## Validation
|
|
13
|
+
|
|
14
|
+
Confirm the installed version. On an authorized runtime, invoke ensure while a
|
|
15
|
+
bounded tooling command is active. Verify waiting, preserved tooling exit status
|
|
16
|
+
and successful ensure after completion when the lifecycle fence stays unchanged.
|
|
17
|
+
Verify the exact runtime stops with zero routes and retained data when finished.
|
|
18
|
+
A waiting exec refreshes runtime proof before admission; ensure establishes its
|
|
19
|
+
runtime inside the worker. Stop or another fence change cancels the waiting
|
|
20
|
+
invocation. Never replay an uncertain command.
|
|
21
|
+
|
|
22
|
+
## Limits
|
|
23
|
+
|
|
24
|
+
Waiting is bounded to thirty minutes, with no FIFO guarantee or persistent queue.
|
|
25
|
+
Permission diagnostics direct agents to a permitted host context; they do not
|
|
26
|
+
repair operating-system permissions or authorize lock removal. This patch does
|
|
27
|
+
not solve network exhaustion, activate capacity admission, or claim complete OOM
|
|
28
|
+
protection or autonomous agent recovery.
|
|
29
|
+
|
|
30
|
+
## Report
|
|
31
|
+
|
|
32
|
+
Report installed version, exact checkout/provider, command outcomes, retained
|
|
33
|
+
runtime/data evidence and final runtime/route state. Separate published source,
|
|
34
|
+
synthetic checks and live consumer acceptance.
|