@devrouter/cli 0.6.6 → 0.6.8

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.
@@ -5592,7 +5592,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs16.default.rea
5592
5592
  const config = parseRepoConfigSource(raw, configPath);
5593
5593
  const requiredVersion = config.devrouter?.version;
5594
5594
  if (requiredVersion && !hasWarnedVersionMismatch) {
5595
- const cliVersion = true ? "0.6.6" : "0.0.0-dev";
5595
+ const cliVersion = true ? "0.6.8" : "0.0.0-dev";
5596
5596
  if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
5597
5597
  hasWarnedVersionMismatch = true;
5598
5598
  process.stderr.write(
@@ -7979,7 +7979,7 @@ function advanceAppReplacementAttempt(identity2, authority, stage, newPrimaryId)
7979
7979
  });
7980
7980
  }
7981
7981
  function installedCliVersion() {
7982
- return true ? "0.6.6" : "0.0.0-dev";
7982
+ return true ? "0.6.8" : "0.0.0-dev";
7983
7983
  }
7984
7984
  function compareCliVersions(left, right) {
7985
7985
  const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -14468,7 +14468,9 @@ function reliabilityRecovery(reason2, repoPath, variant) {
14468
14468
  `Run: devrouter ensure ${checkout}${variantOption} (still queued until capacity frees up)`
14469
14469
  ];
14470
14470
  default:
14471
- return [];
14471
+ return [
14472
+ `Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
14473
+ ];
14472
14474
  }
14473
14475
  }
14474
14476
  function refusedManagedStart(result) {
@@ -14493,7 +14495,10 @@ function readReliabilityStatus(options) {
14493
14495
  workspace: options.workspace ?? null,
14494
14496
  provider
14495
14497
  });
14496
- } catch {
14498
+ } catch (error) {
14499
+ options.drift.push(
14500
+ error instanceof ReliabilityJournalError ? error.cause : "journal-unreadable"
14501
+ );
14497
14502
  return void 0;
14498
14503
  }
14499
14504
  if (!record5) return void 0;
@@ -14913,6 +14918,12 @@ function collectManagedRuntimeStatus(options) {
14913
14918
  if (inspection.activeProcesses.some((process2) => !desiredProcesses.includes(process2))) {
14914
14919
  drift.push("one or more active processes are outside the selected profile");
14915
14920
  }
14921
+ const reliability = readReliabilityStatus({
14922
+ repoPath: options.repoPath,
14923
+ variant: state?.variant,
14924
+ drift,
14925
+ ...options.workspace !== void 0 ? { workspace: options.workspace } : {}
14926
+ });
14916
14927
  const positivelyStopped = !inspection.primaryActive && Object.values(inspection.baseStatuses).every(isStoppedOrMissingResourceStatus) && Object.values(inspection.serviceStatuses).every(isStoppedOrMissingResourceStatus) && activeApps.length === 0;
14917
14928
  const onlyDegradedIncident = state?.status === "degraded" && drift.length === 1;
14918
14929
  const requiredServicesReady = desiredServices.every(
@@ -14930,11 +14941,11 @@ function collectManagedRuntimeStatus(options) {
14930
14941
  services: inspection.activeServices,
14931
14942
  processes: inspection.activeProcesses
14932
14943
  };
14933
- const reliability = readReliabilityStatus({
14934
- repoPath: options.repoPath,
14935
- variant: state?.variant,
14936
- ...options.workspace !== void 0 ? { workspace: options.workspace } : {}
14937
- });
14944
+ if (status === "failed-transition" && reliability?.attention) {
14945
+ reliability.attention.recovery = [
14946
+ `Inspect: devrouter status --repo ${recoveryPath(options.repoPath)}; resolve the reported drift before retrying ensure.`
14947
+ ];
14948
+ }
14938
14949
  return {
14939
14950
  mode: "managed",
14940
14951
  status,
package/dist/devrouter.js CHANGED
@@ -4944,7 +4944,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs8.default.read
4944
4944
  const config = parseRepoConfigSource(raw, configPath);
4945
4945
  const requiredVersion = config.devrouter?.version;
4946
4946
  if (requiredVersion && !hasWarnedVersionMismatch) {
4947
- const cliVersion = true ? "0.6.6" : "0.0.0-dev";
4947
+ const cliVersion = true ? "0.6.8" : "0.0.0-dev";
4948
4948
  if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
4949
4949
  hasWarnedVersionMismatch = true;
4950
4950
  process.stderr.write(
@@ -7266,7 +7266,7 @@ function validateAppReplacementAttempt(value, identity2) {
7266
7266
  return attempt;
7267
7267
  }
7268
7268
  function installedCliVersion() {
7269
- return true ? "0.6.6" : "0.0.0-dev";
7269
+ return true ? "0.6.8" : "0.0.0-dev";
7270
7270
  }
7271
7271
  function compareCliVersions(left, right) {
7272
7272
  const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -17876,6 +17876,29 @@ function recoveryPath(repoPath) {
17876
17876
  if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(repoPath)) return repoPath;
17877
17877
  return `'${repoPath.replaceAll("'", "'\\''")}'`;
17878
17878
  }
17879
+ function managedRuntimeRecovery(runtime, repoPath) {
17880
+ const checkout = recoveryPath(repoPath);
17881
+ const historyCause = runtime.drift.find((entry) => Object.hasOwn(HISTORY_CAUSES, entry));
17882
+ if (historyCause) {
17883
+ return [
17884
+ historyCause === "journal-writer-newer" ? "Preserve lifecycle history and use a matching or newer devrouter CLI before retrying lifecycle commands." : "Preserve lifecycle history and inspect its unreadable or unsafe evidence before retrying lifecycle commands.",
17885
+ `Inspect: devrouter status --repo ${checkout} --json`
17886
+ ];
17887
+ }
17888
+ if (runtime.status === "failed-transition") {
17889
+ return [
17890
+ `Inspect: devrouter status --repo ${checkout}; resolve the reported drift before retrying ensure.`
17891
+ ];
17892
+ }
17893
+ const attention = runtime.reliability?.attention;
17894
+ if (attention?.recovery.length) return attention.recovery;
17895
+ if (attention || runtime.reliability?.operation?.drained === false) {
17896
+ return [
17897
+ `Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
17898
+ ];
17899
+ }
17900
+ return void 0;
17901
+ }
17879
17902
  function reliabilityRecovery(reason2, repoPath, variant) {
17880
17903
  const checkout = recoveryPath(repoPath);
17881
17904
  const variantOption = variant && variant !== "default" ? ` --variant ${variant}` : "";
@@ -17908,7 +17931,9 @@ function reliabilityRecovery(reason2, repoPath, variant) {
17908
17931
  `Run: devrouter ensure ${checkout}${variantOption} (still queued until capacity frees up)`
17909
17932
  ];
17910
17933
  default:
17911
- return [];
17934
+ return [
17935
+ `Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
17936
+ ];
17912
17937
  }
17913
17938
  }
17914
17939
  function refusedManagedStart(result) {
@@ -17933,7 +17958,10 @@ function readReliabilityStatus(options) {
17933
17958
  workspace: options.workspace ?? null,
17934
17959
  provider
17935
17960
  });
17936
- } catch {
17961
+ } catch (error) {
17962
+ options.drift.push(
17963
+ error instanceof ReliabilityJournalError ? error.cause : "journal-unreadable"
17964
+ );
17937
17965
  return void 0;
17938
17966
  }
17939
17967
  if (!record6) return void 0;
@@ -18348,6 +18376,12 @@ function collectManagedRuntimeStatus(options) {
18348
18376
  if (inspection.activeProcesses.some((process2) => !desiredProcesses.includes(process2))) {
18349
18377
  drift.push("one or more active processes are outside the selected profile");
18350
18378
  }
18379
+ const reliability = readReliabilityStatus({
18380
+ repoPath: options.repoPath,
18381
+ variant: state?.variant,
18382
+ drift,
18383
+ ...options.workspace !== void 0 ? { workspace: options.workspace } : {}
18384
+ });
18351
18385
  const positivelyStopped = !inspection.primaryActive && Object.values(inspection.baseStatuses).every(isStoppedOrMissingResourceStatus) && Object.values(inspection.serviceStatuses).every(isStoppedOrMissingResourceStatus) && activeApps.length === 0;
18352
18386
  const onlyDegradedIncident = state?.status === "degraded" && drift.length === 1;
18353
18387
  const requiredServicesReady = desiredServices.every(
@@ -18365,11 +18399,11 @@ function collectManagedRuntimeStatus(options) {
18365
18399
  services: inspection.activeServices,
18366
18400
  processes: inspection.activeProcesses
18367
18401
  };
18368
- const reliability = readReliabilityStatus({
18369
- repoPath: options.repoPath,
18370
- variant: state?.variant,
18371
- ...options.workspace !== void 0 ? { workspace: options.workspace } : {}
18372
- });
18402
+ if (status === "failed-transition" && reliability?.attention) {
18403
+ reliability.attention.recovery = [
18404
+ `Inspect: devrouter status --repo ${recoveryPath(options.repoPath)}; resolve the reported drift before retrying ensure.`
18405
+ ];
18406
+ }
18373
18407
  return {
18374
18408
  mode: "managed",
18375
18409
  status,
@@ -18397,7 +18431,7 @@ function collectManagedRuntimeStatus(options) {
18397
18431
  ...state?.transitionPhase ? { transitionPhase: state.transitionPhase } : {}
18398
18432
  };
18399
18433
  }
18400
- var EMPTY_RESOURCES;
18434
+ var HISTORY_CAUSES, EMPTY_RESOURCES;
18401
18435
  var init_managed_runtime_status = __esm({
18402
18436
  "src/core/managed-runtime-status.ts"() {
18403
18437
  "use strict";
@@ -18413,6 +18447,20 @@ var init_managed_runtime_status = __esm({
18413
18447
  init_reliability_output();
18414
18448
  init_workspace();
18415
18449
  init_workspace_runtime();
18450
+ HISTORY_CAUSES = {
18451
+ "journal-directory-unreadable": true,
18452
+ "journal-directory-unsafe": true,
18453
+ "journal-entry-unsupported": true,
18454
+ "journal-enumeration-limit": true,
18455
+ "journal-enumeration-timeout": true,
18456
+ "journal-unreadable": true,
18457
+ "journal-entry-unsafe": true,
18458
+ "journal-invalid": true,
18459
+ "journal-writer-newer": true,
18460
+ "journal-identity-mismatch": true,
18461
+ "journal-unstable": true,
18462
+ "journal-enumeration-failed": true
18463
+ };
18416
18464
  EMPTY_RESOURCES = {
18417
18465
  apps: [],
18418
18466
  services: [],
@@ -25492,14 +25540,15 @@ async function collectRouterStatus(repoPath) {
25492
25540
  );
25493
25541
  } else if (repo?.valid) {
25494
25542
  const repoArgument = `'${repo.path.replaceAll("'", `'\\''`)}'`;
25543
+ const recovery = repo.managedRuntime ? managedRuntimeRecovery(repo.managedRuntime, repo.path) : void 0;
25495
25544
  if (repo.managedRuntime?.mode === "managed") {
25496
- nextSteps.push(`Run: devrouter ensure ${repoArgument}`);
25545
+ nextSteps.push(...recovery ?? [`Run: devrouter ensure ${repoArgument}`]);
25497
25546
  } else {
25498
25547
  nextSteps.push(`Run: dev app ls --repo ${repo.path}`);
25499
25548
  nextSteps.push("Run: dev app run <name> --repo <path> --yes");
25500
25549
  }
25501
25550
  nextSteps.push("Run: dev ls");
25502
- if (repo.managedRuntime?.mountNesting?.status === "unwound") {
25551
+ if (!recovery && repo.managedRuntime?.mountNesting?.status === "unwound") {
25503
25552
  nextSteps.push(
25504
25553
  `Run: devrouter stop ${repoArgument} and then devrouter ensure ${repoArgument} to re-apply the unwound nested mount`
25505
25554
  );
@@ -25943,7 +25992,7 @@ function probeInstalledCliVersion(executable) {
25943
25992
  }
25944
25993
  function buildCliPathCheck(options = {}) {
25945
25994
  const id5 = "global.cli-path";
25946
- const runningVersion = options.runningVersion ?? (true ? "0.6.6" : "0.0.0-dev");
25995
+ const runningVersion = options.runningVersion ?? (true ? "0.6.8" : "0.0.0-dev");
25947
25996
  if (runningVersion === "0.0.0-dev") {
25948
25997
  return {
25949
25998
  id: id5,
@@ -26765,6 +26814,7 @@ async function buildDoctorReport(options = {}) {
26765
26814
  });
26766
26815
  if (repo.managedRuntime) {
26767
26816
  const managedRuntime = repo.managedRuntime;
26817
+ const recovery = managedRuntimeRecovery(managedRuntime, repo.path);
26768
26818
  const repoArgument = `'${repo.path.replaceAll("'", `'\\''`)}'`;
26769
26819
  const variantOption = managedRuntime.activeVariant && managedRuntime.activeVariant !== "default" ? ` --variant ${managedRuntime.activeVariant}` : "";
26770
26820
  const level = managedRuntime.mode === "legacy" || managedRuntime.status === "ready" ? "ok" : managedRuntime.status === "starting" || managedRuntime.status === "stopped" ? "warn" : "error";
@@ -26779,7 +26829,7 @@ async function buildDoctorReport(options = {}) {
26779
26829
  level,
26780
26830
  summary: summary2,
26781
26831
  ...details ? { details } : {},
26782
- suggestion: managedRuntime.mode === "legacy" ? void 0 : managedRuntime.status === "failed-transition" ? `Inspect: devrouter status --repo ${repoArgument}; resolve the reported drift before retrying ensure.` : managedRuntime.status === "ready" ? void 0 : `Run: devrouter ensure ${repoArgument}${variantOption}`
26832
+ suggestion: managedRuntime.mode === "legacy" ? void 0 : recovery ? recovery.join(" ") : managedRuntime.status === "ready" ? void 0 : `Run: devrouter ensure ${repoArgument}${variantOption}`
26783
26833
  });
26784
26834
  const mountNesting = managedRuntime.mountNesting;
26785
26835
  if (mountNesting && mountNesting.status !== "not-applicable") {
@@ -26797,7 +26847,7 @@ async function buildDoctorReport(options = {}) {
26797
26847
  (entry) => `unwound=${entry.destination} (source ${entry.source} inside ${entry.nestedWithin})`
26798
26848
  )
26799
26849
  ].join("; "),
26800
- suggestion: `Run: devrouter stop ${repoArgument} and then devrouter ensure ${repoArgument}${variantOption} to restart the exact container, which re-applies the nested mount.`
26850
+ suggestion: recovery ? void 0 : `Run: devrouter stop ${repoArgument} and then devrouter ensure ${repoArgument}${variantOption} to restart the exact container, which re-applies the nested mount.`
26801
26851
  });
26802
26852
  } else if (mountNesting.status === "unverified") {
26803
26853
  addCheck(checks, {
@@ -26808,7 +26858,7 @@ async function buildDoctorReport(options = {}) {
26808
26858
  `container=${container}`,
26809
26859
  `reason=${mountNesting.reason ?? "unknown"}`
26810
26860
  ].join("; "),
26811
- suggestion: `Run: devrouter exec ${repoArgument} -- cat /proc/self/mountinfo to read the container's own mount table.`
26861
+ suggestion: recovery ? void 0 : `Run: devrouter exec ${repoArgument} -- cat /proc/self/mountinfo to read the container's own mount table.`
26812
26862
  });
26813
26863
  } else {
26814
26864
  addCheck(checks, {
@@ -26842,7 +26892,7 @@ async function buildDoctorReport(options = {}) {
26842
26892
  suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
26843
26893
  });
26844
26894
  }
26845
- const cliVersion = true ? "0.6.6" : "0.0.0-dev";
26895
+ const cliVersion = true ? "0.6.8" : "0.0.0-dev";
26846
26896
  const configVersion = config.devrouter?.version;
26847
26897
  const installedKnown = cliVersion !== "0.0.0-dev";
26848
26898
  const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
@@ -27078,6 +27128,7 @@ var init_doctor = __esm({
27078
27128
  init_capacity_store();
27079
27129
  init_docker();
27080
27130
  init_host_routes();
27131
+ init_managed_runtime_status();
27081
27132
  init_reliability_operation_store();
27082
27133
  init_repo_config();
27083
27134
  init_devcontainer_diagnostics();
@@ -42521,7 +42572,7 @@ var init_version = __esm({
42521
42572
 
42522
42573
  // src/cli.ts
42523
42574
  var import_commander = require("commander");
42524
- var CLI_VERSION = true ? "0.6.6" : "0.0.0-dev";
42575
+ var CLI_VERSION = true ? "0.6.8" : "0.0.0-dev";
42525
42576
  var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
42526
42577
  function withErrorHandling(action2) {
42527
42578
  return async (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devrouter/cli",
3
- "version": "0.6.6",
3
+ "version": "0.6.8",
4
4
  "description": "Local dev routing CLI with shared Traefik reverse proxy",
5
5
  "author": "Roland Schlaefli",
6
6
  "homepage": "https://github.com/rschlaefli/devrouter#readme",
@@ -0,0 +1,48 @@
1
+ # Upgrade to devrouter 0.6.7
2
+
3
+ Status and doctor keep failed-transition recovery advice consistent, including
4
+ combined status insights and unwound-mount diagnostics. Inspect the exact checkout
5
+ and resolve the reported transition before retrying ensure; the warning is not
6
+ permission to stop/restart an unproved population. Existing readiness, startup,
7
+ repair, ownership, levels and literal checkout argument rules remain.
8
+ No configuration schema or lifecycle contract changes are introduced.
9
+
10
+ ## Task
11
+
12
+ Within approved installation/adaptation scope, select the integrity-verified exact
13
+ package, update `devrouter.version` in `.devrouter.yml` and refresh existing agent
14
+ guidance through `devrouter repo agents`. Verify the actual selected executable,
15
+ PATH copies and participating package/source/harness/controller pins. Ask each
16
+ participating owner which executable can access this host's Devrouter state;
17
+ PATH inventory alone does not prove coordinated adoption.
18
+
19
+ Before the first 0.6.7 lifecycle write, active participating clients must use a
20
+ compatible qualified reader/writer. Older 0.6.6 refuses its newer-writer journals
21
+ through direct read, update and global enumeration even without a schema change.
22
+ Inactive older pins stay unused until compatible adoption is verified. Unknown
23
+ participation holds activation. Do not use an older reader as a downgrade recovery
24
+ route after new writes. Preserve all journal bytes, writer stamps and durable
25
+ initialization/replacement receipts; never erase state or loosen version/hash
26
+ fences to bypass refusal or rearm a consumed attempt.
27
+
28
+ Installation and release notices supply no consumer startup, repair, replacement,
29
+ initialization, reset or extra-attempt authority. Each owner retains exact runtime,
30
+ data and neighbour limits. Failed-transition inspection is a diagnostic action;
31
+ it does not prove application readiness or prescribe an automatic retry.
32
+
33
+ ## Validation
34
+
35
+ 1. Verify registry integrity, selected package/member bytes, executable version
36
+ and the existing local guidance. Run native checks for actual consumer edits.
37
+ 2. Use `devrouter status --repo <checkout> --json` and existing diagnostic results
38
+ for authorized inspection. Compare the actual obstruction and next-action
39
+ preconditions before any separately authorized lifecycle command.
40
+ 3. Any separately authorized runtime work ends with canonical stop and exact
41
+ provider/container/route/worker proof unless the user keeps it running.
42
+
43
+ ## Report
44
+
45
+ Report exact selected package/executable identities, participating-client adoption,
46
+ remaining unknowns and relevant checks. Record any actual runtime terminal with
47
+ its producing evidence. Package proof does not establish receiving-host adoption,
48
+ consumer recovery, broader guidance parity or retained-maintenance acceptance.
@@ -0,0 +1,53 @@
1
+ # Upgrade to devrouter 0.6.8
2
+
3
+ Managed status reports unreadable lifecycle history as drift. Newer-writer history
4
+ requires a matching or newer reader while preserving the journal; other unreadable
5
+ history requires inspection. Status and doctor prioritize that remedy, failed
6
+ transition inspection, durable operation attention and live-owner guidance before
7
+ ordinary startup or nested-mount restart advice. Ordinary readable-history drift
8
+ retains normal ensure guidance. No configuration schema, command surface,
9
+ dependency, ownership or admission guard changes are introduced.
10
+
11
+ ## Task
12
+
13
+ Within approved installation/adaptation scope, select the integrity-verified exact
14
+ package, update `devrouter.version` in `.devrouter.yml` and refresh existing agent
15
+ guidance through `devrouter repo agents`. Verify selected/PATH executables and
16
+ concrete package, source, harness and controller pins sharing the affected journal
17
+ namespace or mixed caller chain. Owners confirm compatible adoption or explicit
18
+ non-use; a PATH listing alone does not prove participation. Independent remote
19
+ state is a separate adoption boundary. Unknown affected participation holds
20
+ activation. Do not alter dormant harness checks or replay consumed attempts.
21
+
22
+ A new reader accepts older supported history. Older 0.6.7 readers refuse actual
23
+ 0.6.8-written journals through direct read, update, enumeration and admission even
24
+ without a schema change. Installing alone writes no lifecycle journal. Before
25
+ any separately authorized new lifecycle write, coordinate affected clients; keep
26
+ inactive older pins unused until compatibility is established. After newer writes,
27
+ use a matching or newer CLI and preserve all journal bytes and durable
28
+ initialization/replacement receipts. Never erase, downgrade or replay history to
29
+ bypass refusal or rearm an attempt.
30
+
31
+ Publication, installation and notices authorize no consumer startup, repair,
32
+ replacement, initialization, reset or extra attempt. Inspection is read-only
33
+ and does not establish application readiness. A live owner must finish or be
34
+ explicitly cancelled within its own authority before another operation.
35
+
36
+ ## Validation
37
+
38
+ 1. Verify registry integrity, selected package/member bytes and executable
39
+ versions. Run native checks for actual consumer edits; preserve journals and
40
+ receipts when only selecting a CLI.
41
+ 2. Use `devrouter status --repo <checkout> --json` and existing diagnostic evidence
42
+ within authorized inspection scope. Check the reported reason and actual
43
+ next-command preconditions; do not infer permission from generic advice.
44
+ 3. Any separately authorized runtime work ends with canonical stop and exact
45
+ worker, provider, container and route proof unless the user keeps it running.
46
+
47
+ ## Report
48
+
49
+ Report selected package/executable identities, affected-client adoption or holds,
50
+ remaining unknowns and relevant checks. Any consumer recovery claim needs its
51
+ actual useful-work, retained-data, neighbour and stopped-terminal evidence.
52
+ Synthetic qualification and package identity alone do not prove receiving-host
53
+ adoption, consumer recovery or retained-maintenance acceptance.