@devrouter/cli 0.1.1 → 0.1.3

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.
@@ -23,8 +23,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  ));
24
24
 
25
25
  // src/core/devpod-exec.ts
26
- var import_node_child_process29 = require("child_process");
27
- var import_node_crypto22 = require("crypto");
26
+ var import_node_child_process30 = require("child_process");
27
+ var import_node_crypto23 = require("crypto");
28
28
 
29
29
  // src/core/devpod-environment.ts
30
30
  var import_node_child_process3 = require("child_process");
@@ -1164,7 +1164,11 @@ function listDevpodWorkspacesRaw(options = {}) {
1164
1164
  }
1165
1165
  if (result.error || result.status !== 0) {
1166
1166
  const details = [result.error?.message, result.stdout, result.stderr].filter(Boolean).join("\n").trim();
1167
- throw new Error(`devpod list failed: ${details || "devpod is not installed or unavailable"}`);
1167
+ const failure = new Error(
1168
+ `devpod list failed: ${details || "devpod is not installed or unavailable"}`
1169
+ );
1170
+ if (result.error) failure.code = result.error.code;
1171
+ throw failure;
1168
1172
  }
1169
1173
  let parsed;
1170
1174
  try {
@@ -1303,9 +1307,11 @@ function listDevsyWorkspaces() {
1303
1307
  );
1304
1308
  if (result.status !== 0) {
1305
1309
  const details = [result.error?.message, result.stdout, result.stderr].filter(Boolean).join("\n").trim();
1306
- throw new Error(
1310
+ const failure = new Error(
1307
1311
  `devsy workspace list failed: ${details || "devsy is not installed or unavailable"}`
1308
1312
  );
1313
+ if (result.error) failure.code = result.error.code;
1314
+ throw failure;
1309
1315
  }
1310
1316
  let parsed;
1311
1317
  try {
@@ -1775,25 +1781,23 @@ function readWorkspaceRuntimeConfig() {
1775
1781
  }
1776
1782
  return config;
1777
1783
  }
1784
+ function readRegistrySnapshot(runtime, read2, snapshots) {
1785
+ try {
1786
+ return read2();
1787
+ } catch (error) {
1788
+ if (error?.code === "ENOENT") return void 0;
1789
+ snapshots.unavailable.push(runtime);
1790
+ snapshots.errors[runtime] = error instanceof Error ? error.message : String(error);
1791
+ return void 0;
1792
+ }
1793
+ }
1778
1794
  function getWorkspaceRegistrySnapshots() {
1779
1795
  if (cachedSnapshots) return cachedSnapshots;
1780
1796
  const snapshots = { unavailable: [], errors: {} };
1781
- if (isRuntimeInstalled("devsy")) {
1782
- try {
1783
- snapshots.devsy = listDevsyWorkspaces();
1784
- } catch (error) {
1785
- snapshots.unavailable.push("devsy");
1786
- snapshots.errors.devsy = error instanceof Error ? error.message : String(error);
1787
- }
1788
- }
1789
- if (isRuntimeInstalled("devpod")) {
1790
- try {
1791
- snapshots.devpod = listDevpodWorkspacesRaw();
1792
- } catch (error) {
1793
- snapshots.unavailable.push("devpod");
1794
- snapshots.errors.devpod = error instanceof Error ? error.message : String(error);
1795
- }
1796
- }
1797
+ const devsy = readRegistrySnapshot("devsy", listDevsyWorkspaces, snapshots);
1798
+ if (devsy !== void 0) snapshots.devsy = devsy;
1799
+ const devpod = readRegistrySnapshot("devpod", listDevpodWorkspacesRaw, snapshots);
1800
+ if (devpod !== void 0) snapshots.devpod = devpod;
1797
1801
  cachedSnapshots = snapshots;
1798
1802
  return snapshots;
1799
1803
  }
@@ -1954,7 +1958,7 @@ function selectDevpodWorkspace(workspaces, repoPath) {
1954
1958
  }
1955
1959
 
1956
1960
  // src/core/devsy-exec.ts
1957
- var import_node_child_process28 = require("child_process");
1961
+ var import_node_child_process29 = require("child_process");
1958
1962
 
1959
1963
  // src/core/devsy-exec-proof.ts
1960
1964
  var import_node_fs7 = __toESM(require("fs"));
@@ -4040,11 +4044,19 @@ function absentRegistrationIdentity(state) {
4040
4044
  resetWorkspaceRuntimeCaches();
4041
4045
  if (resolveWorkspaceRuntimeOrDefault(state.repoPath) !== "devsy")
4042
4046
  throw new Error("Stop provider changed.");
4043
- if (!state.workspace || !isLinkedWorktree(state.repoPath))
4044
- throw new Error("Absent stop requires a linked workspace.");
4045
- const record5 = readWorkspaceOwnership(state.repoPath, state.workspace);
4046
- if (!record5 || record5.workspace !== state.workspace || record5.devpodId !== state.devpodId || !sameWorkspacePath(record5.worktreePath, state.repoPath) || resolveWorktreeWorkspace(state.repoPath) !== state.workspace || inspectWorkspaceOwnership(record5, listGitWorktrees(state.repoPath), void 0).ownerStatus !== "present")
4047
- throw new Error("Absent stop workspace ownership changed.");
4047
+ const linked = isLinkedWorktree(state.repoPath);
4048
+ if (linked !== (state.workspace !== void 0))
4049
+ throw new Error("Absent stop requires the exact workspace identity.");
4050
+ let identity2;
4051
+ if (linked) {
4052
+ const workspace = state.workspace;
4053
+ const record5 = readWorkspaceOwnership(state.repoPath, workspace);
4054
+ if (!record5 || record5.workspace !== workspace || record5.devpodId !== state.devpodId || !sameWorkspacePath(record5.worktreePath, state.repoPath) || resolveWorktreeWorkspace(state.repoPath) !== workspace || inspectWorkspaceOwnership(record5, listGitWorktrees(state.repoPath), void 0).ownerStatus !== "present")
4055
+ throw new Error("Absent stop workspace ownership changed.");
4056
+ identity2 = { kind: "linked", record: record5, gitCommonDir: resolveGitCommonDir(state.repoPath) };
4057
+ } else {
4058
+ identity2 = { kind: "primary", repoPath: state.repoPath, devpodId: state.devpodId };
4059
+ }
4048
4060
  for (const entries of [
4049
4061
  listDevsyWorkspaces(),
4050
4062
  listDevpodWorkspacesRaw({ allowMissingExecutable: true })
@@ -4054,7 +4066,7 @@ function absentRegistrationIdentity(state) {
4054
4066
  ))
4055
4067
  throw new Error("Absent stop requires both provider registrations to remain absent.");
4056
4068
  }
4057
- return { record: record5, gitCommonDir: resolveGitCommonDir(state.repoPath) };
4069
+ return identity2;
4058
4070
  }
4059
4071
  function replacementObservation(state) {
4060
4072
  resetWorkspaceRuntimeCaches();
@@ -4164,7 +4176,7 @@ function proveManagedStop(state) {
4164
4176
  const identityKeys = ["context", "providerId", "uid", "sourcePath", "sourceContainer"];
4165
4177
  const current = identityOf(owner.workspace);
4166
4178
  const changed = identityKeys.filter((key) => baseline[key] !== current[key]);
4167
- if (changed.length === 0 && state.workspace !== void 0 && isLinkedWorktree(state.repoPath) && inspectManagedStopContainers(baseline.project, baseline.endpoint).length === 0) {
4179
+ if (changed.length === 0 && inspectManagedStopContainers(baseline.project, baseline.endpoint).length === 0) {
4168
4180
  proveAbsentPopulationStop(state, baseline, current);
4169
4181
  return { status: "proven-absent", containers: [] };
4170
4182
  }
@@ -4327,12 +4339,13 @@ function reliabilityFence(state) {
4327
4339
  }
4328
4340
 
4329
4341
  // src/core/reliability-operation-store.ts
4330
- var import_node_crypto8 = require("crypto");
4342
+ var import_node_crypto9 = require("crypto");
4331
4343
  var import_node_fs17 = __toESM(require("fs"));
4332
4344
  var import_node_path21 = __toESM(require("path"));
4333
4345
  var import_node_util4 = require("util");
4334
4346
 
4335
4347
  // src/core/capacity-store.ts
4348
+ var import_node_crypto7 = require("crypto");
4336
4349
  var import_node_fs15 = __toESM(require("fs"));
4337
4350
  var import_node_path19 = __toESM(require("path"));
4338
4351
 
@@ -4393,11 +4406,13 @@ function evaluateCapacity(budgets, samples, charges, requested, nowMs, maxSample
4393
4406
  // src/core/capacity-store.ts
4394
4407
  var MAX_BYTES = 1048576;
4395
4408
  var CapacityHistoryError = class extends Error {
4396
- constructor(code) {
4409
+ constructor(code, cause = null, location = null) {
4397
4410
  super(
4398
4411
  code === "capacity-ledger-lost" ? "Capacity ledger history is lost; restore verified capacity-reservations.json." : "Capacity history cannot be proven; inspect the private lifecycle journals."
4399
4412
  );
4400
4413
  this.code = code;
4414
+ this.cause = cause;
4415
+ this.location = location;
4401
4416
  this.name = "CapacityHistoryError";
4402
4417
  }
4403
4418
  };
@@ -4554,9 +4569,10 @@ var CapacityStore = class {
4554
4569
  const buffer = Buffer.alloc(MAX_BYTES + 1);
4555
4570
  const count = import_node_fs15.default.readSync(descriptor, buffer, 0, buffer.length, 0);
4556
4571
  if (count > MAX_BYTES) throw new Error("Capacity reservation snapshot exceeds byte limit.");
4557
- const value = JSON.parse(buffer.subarray(0, count).toString("utf8"));
4572
+ const bytes2 = buffer.subarray(0, count);
4573
+ const value = JSON.parse(bytes2.toString("utf8"));
4558
4574
  validate(value);
4559
- this.ledgerGeneration = `${stat.dev}:${stat.ino}`;
4575
+ this.ledgerGeneration = this.generationIdentity(stat, bytes2);
4560
4576
  if (value.revision < minimumRevision) return { kind: "stale", revision: value.revision };
4561
4577
  this.observedLedger = true;
4562
4578
  return { kind: "intact", revision: value.revision, snapshot: value };
@@ -4609,20 +4625,30 @@ var CapacityStore = class {
4609
4625
  return snapshot;
4610
4626
  }
4611
4627
  commit(snapshot) {
4612
- this.write(this.file, serializeSnapshot(snapshot));
4628
+ const contents = serializeSnapshot(snapshot);
4629
+ this.write(this.file, contents);
4613
4630
  this.observedLedger = true;
4614
- this.rememberGeneration();
4631
+ this.rememberGeneration(contents);
4615
4632
  this.establish();
4616
4633
  }
4617
4634
  /** Remember the published snapshot identity for the next generation fence. */
4618
- rememberGeneration() {
4635
+ rememberGeneration(contents) {
4619
4636
  try {
4620
4637
  const stat = import_node_fs15.default.statSync(this.file);
4621
- this.ledgerGeneration = stat.isFile() ? `${stat.dev}:${stat.ino}` : void 0;
4638
+ this.ledgerGeneration = stat.isFile() ? this.generationIdentity(stat, contents) : void 0;
4622
4639
  } catch {
4623
4640
  this.ledgerGeneration = void 0;
4624
4641
  }
4625
4642
  }
4643
+ /**
4644
+ * File identity plus content digest. Deleting and recreating the snapshot can
4645
+ * reuse its inode number, so the inode alone cannot fence a replacement that
4646
+ * reuses a revision number.
4647
+ */
4648
+ generationIdentity(stat, contents) {
4649
+ const digest = (0, import_node_crypto7.createHash)("sha256").update(contents).digest("hex");
4650
+ return `${stat.dev}:${stat.ino}:${digest}`;
4651
+ }
4626
4652
  /**
4627
4653
  * Durable evidence that recorded history is gone, for a stop whose physical
4628
4654
  * cessation is already proven. The caller holds that proof; this writes no
@@ -4871,7 +4897,7 @@ var CapacityStore = class {
4871
4897
  };
4872
4898
 
4873
4899
  // src/core/controller-store.ts
4874
- var import_node_crypto7 = require("crypto");
4900
+ var import_node_crypto8 = require("crypto");
4875
4901
  var import_node_fs16 = __toESM(require("fs"));
4876
4902
  var import_node_path20 = __toESM(require("path"));
4877
4903
  var CONTROLLER_SNAPSHOT_BYTES = 1048576;
@@ -5173,7 +5199,7 @@ var ControllerStore = class {
5173
5199
  provenance(identity2) {
5174
5200
  if (identity2.version !== 2) throw new Error("Controller binding provenance is unavailable.");
5175
5201
  return {
5176
- digest: (0, import_node_crypto7.createHash)("sha256").update(JSON.stringify(["devrouter-controller-binding-v1", identity2.store, identity2.key])).digest("hex"),
5202
+ digest: (0, import_node_crypto8.createHash)("sha256").update(JSON.stringify(["devrouter-controller-binding-v1", identity2.store, identity2.key])).digest("hex"),
5177
5203
  enrolledEpoch: identity2.enrolledEpoch
5178
5204
  };
5179
5205
  }
@@ -5197,7 +5223,7 @@ var ControllerStore = class {
5197
5223
  if (!current || current.store !== captured.store || current.epoch !== captured.epoch || JSON.stringify(current.fingerprint) !== JSON.stringify(captured.fingerprint) || identity2?.version !== 2)
5198
5224
  throw new Error("Controller binding incarnation changed.");
5199
5225
  this.checkProvenance(current, identity2);
5200
- return (0, import_node_crypto7.createHmac)("sha256", Buffer.from(identity2.key, "hex")).update(JSON.stringify({ owner, config })).digest("hex");
5226
+ return (0, import_node_crypto8.createHmac)("sha256", Buffer.from(identity2.key, "hex")).update(JSON.stringify({ owner, config })).digest("hex");
5201
5227
  };
5202
5228
  }
5203
5229
  read() {
@@ -5250,7 +5276,7 @@ var ControllerStore = class {
5250
5276
  const identity2 = existing?.version === 2 ? existing : {
5251
5277
  version: 2,
5252
5278
  store,
5253
- key: (0, import_node_crypto7.randomBytes)(32).toString("hex"),
5279
+ key: (0, import_node_crypto8.randomBytes)(32).toString("hex"),
5254
5280
  enrolledEpoch: epoch
5255
5281
  };
5256
5282
  if (existing?.version !== 2)
@@ -5296,7 +5322,7 @@ var ControllerStore = class {
5296
5322
  if (!previous) {
5297
5323
  previous = {
5298
5324
  version: 2,
5299
- store: (0, import_node_crypto7.randomUUID)(),
5325
+ store: (0, import_node_crypto8.randomUUID)(),
5300
5326
  epoch: 0,
5301
5327
  revision: 0,
5302
5328
  parkingRevision: 0,
@@ -5347,7 +5373,7 @@ function retain(session, previous) {
5347
5373
 
5348
5374
  // src/core/reliability-operation-store.ts
5349
5375
  function installedCliVersion() {
5350
- return true ? "0.1.1" : "0.0.0-dev";
5376
+ return true ? "0.1.3" : "0.0.0-dev";
5351
5377
  }
5352
5378
  function compareCliVersions(left, right) {
5353
5379
  const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -5370,7 +5396,7 @@ function identityKey(identity2) {
5370
5396
  if (!import_node_path21.default.isAbsolute(identity2.repoPath) || import_node_path21.default.resolve(identity2.repoPath) !== identity2.repoPath || identity2.repoPath.includes("\0") || identity2.workspace !== null && !isReliabilityId(identity2.workspace) || !["devpod", "devsy"].includes(identity2.provider)) {
5371
5397
  throw new Error("Invalid reliability workspace identity.");
5372
5398
  }
5373
- return (0, import_node_crypto8.createHash)("sha256").update(identity2.repoPath).digest("hex");
5399
+ return (0, import_node_crypto9.createHash)("sha256").update(identity2.repoPath).digest("hex");
5374
5400
  }
5375
5401
  function reliabilityOperationPath(identity2) {
5376
5402
  return import_node_path21.default.join(DEVROUTER_HOME, "reliability", `${identityKey(identity2)}.json`);
@@ -5487,6 +5513,7 @@ function validate2(record5, identity2) {
5487
5513
  "revision",
5488
5514
  "state",
5489
5515
  "worker",
5516
+ "stopWorkStarted",
5490
5517
  "effectSequence",
5491
5518
  "outcome",
5492
5519
  "result",
@@ -5668,13 +5695,39 @@ function validate2(record5, identity2) {
5668
5695
  throw new Error("Reliability worker identity is invalid.");
5669
5696
  }
5670
5697
  }
5698
+ if (record5.stopWorkStarted !== void 0 && record5.stopWorkStarted !== null) {
5699
+ if (record5.stopWorkStarted !== true) throw new Error("Invalid stop work marker.");
5700
+ }
5701
+ }
5702
+ var ReliabilityJournalError = class extends Error {
5703
+ constructor(cause, location, message) {
5704
+ super(message);
5705
+ this.cause = cause;
5706
+ this.location = location;
5707
+ this.name = "ReliabilityJournalError";
5708
+ }
5709
+ };
5710
+ var MAX_REPORTED_ENTRY_NAME = 160;
5711
+ var JournalFileGuardError = class extends Error {
5712
+ constructor(message) {
5713
+ super(message);
5714
+ this.name = "JournalFileGuardError";
5715
+ }
5716
+ };
5717
+ function journalEntryLocation(name) {
5718
+ const printable = name.replace(/[^A-Za-z0-9._-]/g, "?");
5719
+ return printable.length > MAX_REPORTED_ENTRY_NAME ? `${printable.slice(0, MAX_REPORTED_ENTRY_NAME - 3)}...` : printable;
5671
5720
  }
5672
5721
  function createLifecycleCapacityStore(directory = import_node_path21.default.join(DEVROUTER_HOME, "controller")) {
5673
5722
  return new CapacityStore(directory, void 0, () => {
5674
5723
  try {
5675
5724
  return listUnsettledCapacityBindings().floor;
5676
- } catch {
5677
- throw new CapacityHistoryError("capacity-history-unprovable");
5725
+ } catch (error) {
5726
+ throw error instanceof ReliabilityJournalError ? new CapacityHistoryError("capacity-history-unprovable", error.cause, error.location) : new CapacityHistoryError(
5727
+ "capacity-history-unprovable",
5728
+ "journal-enumeration-failed",
5729
+ null
5730
+ );
5678
5731
  }
5679
5732
  });
5680
5733
  }
@@ -5733,11 +5786,12 @@ function readBoundedPrivateJson(file, label) {
5733
5786
  try {
5734
5787
  const stat = import_node_fs17.default.fstatSync(descriptor);
5735
5788
  if (!stat.isFile() || stat.uid !== process.getuid?.() || stat.size > MAX_RECORD_BYTES || (stat.mode & 63) !== 0) {
5736
- throw new Error(`${label} is not a bounded private file.`);
5789
+ throw new JournalFileGuardError(`${label} is not a bounded private file.`);
5737
5790
  }
5738
5791
  const bytes2 = Buffer.alloc(MAX_RECORD_BYTES + 1);
5739
5792
  const count = import_node_fs17.default.readSync(descriptor, bytes2, 0, bytes2.length, 0);
5740
- if (count > MAX_RECORD_BYTES) throw new Error(`${label} exceeds its byte limit.`);
5793
+ if (count > MAX_RECORD_BYTES)
5794
+ throw new JournalFileGuardError(`${label} exceeds its byte limit.`);
5741
5795
  return JSON.parse(bytes2.subarray(0, count).toString("utf8"));
5742
5796
  } finally {
5743
5797
  import_node_fs17.default.closeSync(descriptor);
@@ -5745,7 +5799,11 @@ function readBoundedPrivateJson(file, label) {
5745
5799
  }
5746
5800
  function assertReliabilityEnumerationTime(startedAtMs) {
5747
5801
  if (performance.now() - startedAtMs > MAX_RELIABILITY_ENUMERATION_MS)
5748
- throw new Error("Reliability journal enumeration exceeded its time limit.");
5802
+ throw new ReliabilityJournalError(
5803
+ "journal-enumeration-timeout",
5804
+ null,
5805
+ "Reliability journal enumeration exceeded its time limit."
5806
+ );
5749
5807
  }
5750
5808
  function reliabilityDirectory() {
5751
5809
  return import_node_path21.default.join(DEVROUTER_HOME, "reliability");
@@ -5766,22 +5824,56 @@ function listReliabilityOperations() {
5766
5824
  stat = import_node_fs17.default.lstatSync(directory);
5767
5825
  } catch (error) {
5768
5826
  if (error.code === "ENOENT") return [];
5769
- throw error;
5827
+ throw new ReliabilityJournalError(
5828
+ "journal-directory-unreadable",
5829
+ null,
5830
+ "Reliability journal directory could not be read."
5831
+ );
5770
5832
  }
5771
5833
  if (!stat.isDirectory() || stat.isSymbolicLink())
5772
- throw new Error("Reliability journal directory is unsafe.");
5834
+ throw new ReliabilityJournalError(
5835
+ "journal-directory-unsafe",
5836
+ null,
5837
+ "Reliability journal directory is unsafe."
5838
+ );
5773
5839
  if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
5774
- throw new Error("Reliability journal directory is not private.");
5840
+ throw new ReliabilityJournalError(
5841
+ "journal-directory-unsafe",
5842
+ null,
5843
+ "Reliability journal directory is not private."
5844
+ );
5775
5845
  const entries = [];
5776
- const handle = import_node_fs17.default.opendirSync(directory);
5846
+ let handle;
5847
+ try {
5848
+ handle = import_node_fs17.default.opendirSync(directory);
5849
+ } catch {
5850
+ throw new ReliabilityJournalError(
5851
+ "journal-directory-unreadable",
5852
+ null,
5853
+ "Reliability journal directory could not be read."
5854
+ );
5855
+ }
5777
5856
  try {
5778
5857
  for (; ; ) {
5779
5858
  assertReliabilityEnumerationTime(startedAtMs);
5780
- const entry = handle.readSync();
5859
+ let entry;
5860
+ try {
5861
+ entry = handle.readSync();
5862
+ } catch {
5863
+ throw new ReliabilityJournalError(
5864
+ "journal-directory-unreadable",
5865
+ null,
5866
+ "Reliability journal directory could not be read."
5867
+ );
5868
+ }
5781
5869
  if (!entry) break;
5782
5870
  entries.push(entry);
5783
5871
  if (entries.length > MAX_RELIABILITY_DIRECTORY_ENTRIES)
5784
- throw new Error("Reliability journal directory exceeds its entry limit.");
5872
+ throw new ReliabilityJournalError(
5873
+ "journal-enumeration-limit",
5874
+ null,
5875
+ "Reliability journal directory exceeds its entry limit."
5876
+ );
5785
5877
  }
5786
5878
  } finally {
5787
5879
  handle.closeSync();
@@ -5790,27 +5882,82 @@ function listReliabilityOperations() {
5790
5882
  for (const entry of entries) {
5791
5883
  assertReliabilityEnumerationTime(startedAtMs);
5792
5884
  if (entry.isSymbolicLink())
5793
- throw new Error("Reliability journal directory contains a symlink.");
5885
+ throw new ReliabilityJournalError(
5886
+ "journal-entry-unsupported",
5887
+ journalEntryLocation(entry.name),
5888
+ "Reliability journal directory contains a symlink."
5889
+ );
5794
5890
  if (!entry.isFile())
5795
- throw new Error("Reliability journal directory contains an unsupported entry.");
5891
+ throw new ReliabilityJournalError(
5892
+ "journal-entry-unsupported",
5893
+ journalEntryLocation(entry.name),
5894
+ "Reliability journal directory contains an unsupported entry."
5895
+ );
5796
5896
  if (RELIABILITY_LOCK_NAME_RE.test(entry.name) || RELIABILITY_ATOMIC_TEMP_NAME_RE.test(entry.name))
5797
5897
  continue;
5798
5898
  const match = RELIABILITY_JOURNAL_NAME_RE.exec(entry.name);
5799
- if (!match) throw new Error("Reliability journal directory contains an unsupported entry.");
5899
+ if (!match)
5900
+ throw new ReliabilityJournalError(
5901
+ "journal-entry-unsupported",
5902
+ journalEntryLocation(entry.name),
5903
+ "Reliability journal directory contains an unsupported entry."
5904
+ );
5800
5905
  journals.push({ name: entry.name, key: match[1] });
5801
5906
  }
5802
5907
  if (journals.length > MAX_RELIABILITY_JOURNALS)
5803
- throw new Error("Reliability journal directory exceeds its journal limit.");
5908
+ throw new ReliabilityJournalError(
5909
+ "journal-enumeration-limit",
5910
+ null,
5911
+ "Reliability journal directory exceeds its journal limit."
5912
+ );
5804
5913
  journals.sort((left, right) => left.name.localeCompare(right.name));
5805
5914
  const records = [];
5806
5915
  for (const journal of journals) {
5807
5916
  assertReliabilityEnumerationTime(startedAtMs);
5808
5917
  const file = import_node_path21.default.join(directory, journal.name);
5809
- const identity2 = journalIdentity(readBoundedPrivateJson(file, "Reliability journal"));
5810
- if (identityKey(identity2) !== journal.key)
5811
- throw new Error("Reliability journal filename does not match its identity.");
5812
- const record5 = readReliabilityOperation(identity2);
5813
- if (!record5) throw new Error("Reliability journal disappeared during enumeration.");
5918
+ let raw;
5919
+ try {
5920
+ raw = readBoundedPrivateJson(file, "Reliability journal");
5921
+ } catch (error) {
5922
+ const fsCode = error?.code;
5923
+ const cause = error instanceof JournalFileGuardError ? "journal-entry-unsafe" : error instanceof SyntaxError || !fsCode ? "journal-invalid" : "journal-unreadable";
5924
+ throw new ReliabilityJournalError(
5925
+ cause,
5926
+ journalEntryLocation(journal.name),
5927
+ error instanceof JournalFileGuardError ? error.message : cause === "journal-invalid" ? "Reliability journal entry is invalid." : "Reliability journal entry could not be read."
5928
+ );
5929
+ }
5930
+ if (raw === void 0)
5931
+ throw new ReliabilityJournalError(
5932
+ "journal-unstable",
5933
+ journalEntryLocation(journal.name),
5934
+ "Reliability journal disappeared during enumeration."
5935
+ );
5936
+ let identity2;
5937
+ let record5;
5938
+ try {
5939
+ identity2 = journalIdentity(raw);
5940
+ if (identityKey(identity2) !== journal.key)
5941
+ throw new ReliabilityJournalError(
5942
+ "journal-identity-mismatch",
5943
+ journalEntryLocation(journal.name),
5944
+ "Reliability journal filename does not match its identity."
5945
+ );
5946
+ record5 = readReliabilityOperation(identity2);
5947
+ } catch (error) {
5948
+ if (error instanceof ReliabilityJournalError) throw error;
5949
+ throw new ReliabilityJournalError(
5950
+ "journal-invalid",
5951
+ journalEntryLocation(journal.name),
5952
+ "Reliability journal entry is invalid."
5953
+ );
5954
+ }
5955
+ if (!record5)
5956
+ throw new ReliabilityJournalError(
5957
+ "journal-unstable",
5958
+ journalEntryLocation(journal.name),
5959
+ "Reliability journal disappeared during enumeration."
5960
+ );
5814
5961
  records.push(record5);
5815
5962
  assertReliabilityEnumerationTime(startedAtMs);
5816
5963
  }
@@ -5886,7 +6033,7 @@ function clearStartupWitness(identity2, fence) {
5886
6033
  }
5887
6034
 
5888
6035
  // src/core/repo-config.ts
5889
- var import_node_crypto9 = require("crypto");
6036
+ var import_node_crypto10 = require("crypto");
5890
6037
  var import_node_fs18 = __toESM(require("fs"));
5891
6038
  var import_node_path22 = __toESM(require("path"));
5892
6039
  var import_yaml3 = __toESM(require("yaml"));
@@ -7163,7 +7310,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs18.default.rea
7163
7310
  const config = parseConfig(parsed ?? {}, configPath);
7164
7311
  const requiredVersion = config.devrouter?.version;
7165
7312
  if (requiredVersion && !hasWarnedVersionMismatch) {
7166
- const cliVersion = true ? "0.1.1" : "0.0.0-dev";
7313
+ const cliVersion = true ? "0.1.3" : "0.0.0-dev";
7167
7314
  if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
7168
7315
  hasWarnedVersionMismatch = true;
7169
7316
  process.stderr.write(
@@ -7342,7 +7489,7 @@ async function ensureNetwork(name) {
7342
7489
 
7343
7490
  // src/core/tls.ts
7344
7491
  var import_node_child_process13 = require("child_process");
7345
- var import_node_crypto10 = require("crypto");
7492
+ var import_node_crypto11 = require("crypto");
7346
7493
  var import_node_fs19 = __toESM(require("fs"));
7347
7494
  var import_node_path23 = __toESM(require("path"));
7348
7495
  var DEFAULT_TLS_CERT_HOSTS = ["localhost", "*.localhost"];
@@ -7412,7 +7559,7 @@ function parseDnsHostsFromSubjectAltName(subjectAltName) {
7412
7559
  return normalizeUniqueHosts(names);
7413
7560
  }
7414
7561
  function parseCertificateDnsHosts(pem) {
7415
- const certificate = new import_node_crypto10.X509Certificate(pem);
7562
+ const certificate = new import_node_crypto11.X509Certificate(pem);
7416
7563
  const subjectAltName = certificate.subjectAltName ?? "";
7417
7564
  if (subjectAltName.length === 0) {
7418
7565
  return [];
@@ -8241,6 +8388,41 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
8241
8388
  throw new Error("Initial managed stop left a workload running.");
8242
8389
  return true;
8243
8390
  }
8391
+ function restoreRecordedManagedDevcontainerConfig(repoPath) {
8392
+ const plan = recordedManagedDevcontainerRestorePlan(repoPath);
8393
+ if (!plan) return false;
8394
+ writeManagedDevcontainerConfig(plan);
8395
+ if (inspectManagedDevcontainerGeneratedConfig(plan).status !== "valid") {
8396
+ throw new Error(
8397
+ `Managed Dev Container path '${plan.generatedPath}' could not be restored from the recorded state.`
8398
+ );
8399
+ }
8400
+ return true;
8401
+ }
8402
+ function recordedManagedDevcontainerRestorePlan(repoPath) {
8403
+ try {
8404
+ if (!import_node_fs21.default.existsSync(import_node_path25.default.join(repoPath, ".devrouter.yml"))) return void 0;
8405
+ const linked = isLinkedWorktree(repoPath);
8406
+ const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
8407
+ const state = readManagedRuntimeState(repoPath, workspace);
8408
+ if (!state) return void 0;
8409
+ const runtime = loadRuntimeConfig(repoPath, workspace ?? "", state.profile);
8410
+ if (!runtime.config.managedRuntime || runtime.profile !== state.profile || runtime.workspace !== workspace)
8411
+ return void 0;
8412
+ const plan = inspectManagedDevcontainerConfig({
8413
+ repoPath,
8414
+ config: runtime.config,
8415
+ profile: runtime.resolvedProfile,
8416
+ linked
8417
+ });
8418
+ if (inspectManagedDevcontainerGeneratedConfig(plan).status !== "missing") return void 0;
8419
+ if (plan.sourceConfigSha256 !== state.sourceConfigSha256 || plan.effectiveConfigSha256 !== state.effectiveConfigSha256)
8420
+ return void 0;
8421
+ return plan;
8422
+ } catch {
8423
+ return void 0;
8424
+ }
8425
+ }
8244
8426
  function stopRetainedManagedDevsyWorkspace(options) {
8245
8427
  const { repoPath, devsyId } = options;
8246
8428
  const linked = isLinkedWorktree(repoPath);
@@ -8478,12 +8660,12 @@ function networkProviderEnvironment(binding, source) {
8478
8660
  }
8479
8661
 
8480
8662
  // src/core/network-claim-lookup.ts
8481
- var import_node_crypto12 = require("crypto");
8663
+ var import_node_crypto13 = require("crypto");
8482
8664
  var import_node_fs24 = __toESM(require("fs"));
8483
8665
  var import_node_path28 = __toESM(require("path"));
8484
8666
 
8485
8667
  // src/core/network-claims.ts
8486
- var import_node_crypto11 = require("crypto");
8668
+ var import_node_crypto12 = require("crypto");
8487
8669
  var import_node_fs23 = __toESM(require("fs"));
8488
8670
  var import_node_path27 = __toESM(require("path"));
8489
8671
 
@@ -9673,7 +9855,7 @@ function assertDirectory(directory) {
9673
9855
  }
9674
9856
  }
9675
9857
  function hashKey(value) {
9676
- return (0, import_node_crypto11.createHash)("sha256").update(value).digest("hex");
9858
+ return (0, import_node_crypto12.createHash)("sha256").update(value).digest("hex");
9677
9859
  }
9678
9860
  function cloneFence(fence) {
9679
9861
  return { ...fence };
@@ -9701,7 +9883,7 @@ function claimError(code, message) {
9701
9883
  function networkOwnerKey(repoPath) {
9702
9884
  if (!import_node_path28.default.isAbsolute(repoPath) || import_node_path28.default.resolve(repoPath) !== repoPath)
9703
9885
  throw new Error("Invalid network owner path.");
9704
- return (0, import_node_crypto12.createHash)("sha256").update(repoPath).digest("hex");
9886
+ return (0, import_node_crypto13.createHash)("sha256").update(repoPath).digest("hex");
9705
9887
  }
9706
9888
  function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9707
9889
  let names;
@@ -9741,7 +9923,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9741
9923
  } finally {
9742
9924
  import_node_fs24.default.closeSync(descriptor);
9743
9925
  }
9744
- if (typeof value.daemonId !== "string" || `${(0, import_node_crypto12.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
9926
+ if (typeof value.daemonId !== "string" || `${(0, import_node_crypto13.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
9745
9927
  throw new Error("Retained network daemon identity is invalid.");
9746
9928
  const claim2 = readNetworkClaim({
9747
9929
  daemonId: value.daemonId,
@@ -9758,7 +9940,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9758
9940
 
9759
9941
  // src/core/network-provider-inspect.ts
9760
9942
  var import_node_child_process15 = require("child_process");
9761
- var import_node_crypto13 = require("crypto");
9943
+ var import_node_crypto14 = require("crypto");
9762
9944
  function object2(value) {
9763
9945
  if (!value || typeof value !== "object" || Array.isArray(value))
9764
9946
  throw new Error("Invalid provider evidence.");
@@ -9778,7 +9960,7 @@ function qualifyNetworkProviderDefinition(value, provider) {
9778
9960
  if (definition.name !== "docker" || ![true, "true"].includes(agent.local) || agent.driver !== void 0 && agent.driver !== "docker" && agent.driver !== "" || docker.path !== "${DOCKER_PATH}" || docker.builder !== "${DOCKER_BUILDER}" || ![false, "false"].includes(docker.install) || (provider === "devsy" ? docker.elevation !== "${DOCKER_ELEVATION}" : docker.elevation !== void 0 && docker.elevation !== "") || env.DOCKER_HOST !== "${DOCKER_HOST}" || Object.keys(env).some((key) => key !== "DOCKER_HOST") || host.global !== true || dockerPath.default !== "docker" || actualCommand.length !== 1 || typeof actualCommand[0] !== "string" || actualCommand[0].trim() !== command || Object.keys(exec).some((key) => key !== "command") || agent.path !== void 0 && agent.path !== "" || agent.downloadURL !== void 0 && agent.downloadURL !== "") {
9779
9961
  throw new Error("Docker provider definition is not qualified for network allocation.");
9780
9962
  }
9781
- return (0, import_node_crypto13.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
9963
+ return (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
9782
9964
  }
9783
9965
  function read(provider, args) {
9784
9966
  const result = (0, import_node_child_process15.spawnSync)(provider, args, {
@@ -9996,6 +10178,7 @@ function inspectExactOwnership(devsyId, worktreePath) {
9996
10178
  }
9997
10179
  function mutateOwnedDevsyWorkspace(action, devsyId, worktreePath) {
9998
10180
  return withMutationLock(`Devsy ${action}`, worktreePath, () => {
10181
+ restoreRecordedManagedDevcontainerConfig(worktreePath);
9999
10182
  if (action === "stop") {
10000
10183
  const stopped = stopRetainedManagedDevsyWorkspace({
10001
10184
  repoPath: worktreePath,
@@ -10161,7 +10344,7 @@ var ExecutionOutcomeError = class extends Error {
10161
10344
  };
10162
10345
 
10163
10346
  // src/core/reliability-lifecycle.ts
10164
- var import_node_crypto21 = require("crypto");
10347
+ var import_node_crypto22 = require("crypto");
10165
10348
  var import_node_path40 = __toESM(require("path"));
10166
10349
  var import_node_util7 = require("util");
10167
10350
 
@@ -10170,7 +10353,7 @@ var import_node_fs26 = __toESM(require("fs"));
10170
10353
  var import_node_path30 = __toESM(require("path"));
10171
10354
 
10172
10355
  // src/core/controller-client.ts
10173
- var import_node_crypto14 = require("crypto");
10356
+ var import_node_crypto15 = require("crypto");
10174
10357
  var import_node_fs27 = __toESM(require("fs"));
10175
10358
  var import_node_net2 = __toESM(require("net"));
10176
10359
  var import_node_path32 = __toESM(require("path"));
@@ -10185,7 +10368,7 @@ var CONTROLLER_PROFILE_RE = new RegExp(
10185
10368
  );
10186
10369
 
10187
10370
  // src/core/controller-monitor.ts
10188
- var import_node_crypto15 = require("crypto");
10371
+ var import_node_crypto16 = require("crypto");
10189
10372
  var import_node_util6 = require("util");
10190
10373
 
10191
10374
  // src/core/reliability-output.ts
@@ -10516,7 +10699,7 @@ function handleOperationRequest(state, event) {
10516
10699
  if (state.phase === "stopping" || state.desired === "parked-for-capacity")
10517
10700
  return blocked(
10518
10701
  state,
10519
- `phase is '${state.phase}' with desired '${state.desired}'; wait for the running stop to finish.`
10702
+ `phase is '${state.phase}' with desired '${state.desired}'; wait for the running stop to finish, or when no stop worker is running rerun 'devrouter stop <path> --delete', removing the exact provider registration first when the stop cannot prove the recorded population.`
10520
10703
  );
10521
10704
  if (event.kind === "exec" && (!event.runtimeRunning || state.desired !== "running" && state.intentRevision !== 0))
10522
10705
  return blocked(
@@ -10974,7 +11157,7 @@ function stepReliability(state, event, nowMs) {
10974
11157
 
10975
11158
  // src/core/reliability-worker.ts
10976
11159
  var import_node_child_process17 = require("child_process");
10977
- var import_node_crypto16 = require("crypto");
11160
+ var import_node_crypto17 = require("crypto");
10978
11161
  var import_node_fs28 = __toESM(require("fs"));
10979
11162
  var import_node_path33 = __toESM(require("path"));
10980
11163
 
@@ -11043,7 +11226,7 @@ function workerGroupAbsent(pid) {
11043
11226
  }
11044
11227
 
11045
11228
  // src/core/workspace-ensure.ts
11046
- var import_node_child_process27 = require("child_process");
11229
+ var import_node_child_process28 = require("child_process");
11047
11230
  var import_node_fs34 = __toESM(require("fs"));
11048
11231
  var import_node_path39 = __toESM(require("path"));
11049
11232
 
@@ -11742,7 +11925,7 @@ async function runManagedHostPreparation(repoPath, config) {
11742
11925
 
11743
11926
  // src/core/managed-post-start.ts
11744
11927
  var import_node_child_process22 = require("child_process");
11745
- var import_node_crypto17 = require("crypto");
11928
+ var import_node_crypto18 = require("crypto");
11746
11929
  var import_node_fs31 = __toESM(require("fs"));
11747
11930
  var import_node_path36 = __toESM(require("path"));
11748
11931
  var MANAGED_MARKER = "devrouter:managed devcontainer";
@@ -11799,7 +11982,7 @@ function readRegularFile(filePath) {
11799
11982
  return readRegularFileBytes(filePath)?.toString("utf-8");
11800
11983
  }
11801
11984
  function adapterFingerprint(adapter) {
11802
- return (0, import_node_crypto17.createHash)("sha256").update(adapter).digest("hex");
11985
+ return (0, import_node_crypto18.createHash)("sha256").update(adapter).digest("hex");
11803
11986
  }
11804
11987
  function resolveProcessHelperPath() {
11805
11988
  const candidates = [
@@ -11951,26 +12134,125 @@ function runManagedProcessAction(options) {
11951
12134
  return "drifted";
11952
12135
  }
11953
12136
 
12137
+ // src/core/managed-mount-nesting.ts
12138
+ var import_node_child_process23 = require("child_process");
12139
+ var NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
12140
+ var UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
12141
+ function normalizeDestination(value) {
12142
+ const trimmed = value.trim().replace(/\/+$/, "");
12143
+ return trimmed === "" ? "/" : trimmed;
12144
+ }
12145
+ function isNestedWithin(destination, candidate) {
12146
+ return candidate === "/" ? destination !== "/" : destination.startsWith(`${candidate}/`);
12147
+ }
12148
+ function unescapeMountField(value) {
12149
+ return value.replace(
12150
+ /\\([0-7]{3})/g,
12151
+ (_match, octal) => String.fromCharCode(Number.parseInt(octal, 8))
12152
+ );
12153
+ }
12154
+ function parseMountinfoDestinations(text4) {
12155
+ const destinations = /* @__PURE__ */ new Set();
12156
+ for (const line of text4.split("\n")) {
12157
+ const fields2 = line.split(" ");
12158
+ if (fields2.length < 5 || !/^\d+$/.test(fields2[0] ?? "")) continue;
12159
+ destinations.add(normalizeDestination(unescapeMountField(fields2[4] ?? "")));
12160
+ }
12161
+ return [...destinations];
12162
+ }
12163
+ function isNestedIndex(destinations, index) {
12164
+ return destinations.some(
12165
+ (candidate, other) => other !== index && isNestedWithin(destinations[index] ?? "", candidate)
12166
+ );
12167
+ }
12168
+ function configuredDestinations(configured) {
12169
+ return configured.map((mount) => normalizeDestination(mount.Destination));
12170
+ }
12171
+ function classifyManagedMountNesting(configured, effectiveDestinations, containerId) {
12172
+ const destinations = configuredDestinations(configured);
12173
+ const nested = configured.filter((_mount, index) => isNestedIndex(destinations, index));
12174
+ const identity2 = containerId ? { container: containerId } : {};
12175
+ if (nested.length === 0) {
12176
+ return { status: "not-applicable", checked: [], unwound: [], reason: NESTED_MOUNT_REASON };
12177
+ }
12178
+ if (effectiveDestinations === null) {
12179
+ return {
12180
+ status: "unverified",
12181
+ checked: [],
12182
+ unwound: [],
12183
+ ...identity2,
12184
+ reason: UNREADABLE_MOUNT_REASON
12185
+ };
12186
+ }
12187
+ const effective = new Set(effectiveDestinations.map(normalizeDestination));
12188
+ const checked = [];
12189
+ const unwound = [];
12190
+ for (const mount of nested) {
12191
+ const destination = normalizeDestination(mount.Destination);
12192
+ if (effective.has(destination)) {
12193
+ checked.push(mount.Destination);
12194
+ continue;
12195
+ }
12196
+ const nestedWithin = destinations.filter((candidate) => isNestedWithin(destination, candidate)).sort((a, b) => a.length - b.length)[0];
12197
+ unwound.push({
12198
+ destination: mount.Destination,
12199
+ source: mount.Source,
12200
+ nestedWithin: nestedWithin ?? "/"
12201
+ });
12202
+ }
12203
+ return {
12204
+ status: unwound.length > 0 ? "unwound" : "effective",
12205
+ checked,
12206
+ unwound,
12207
+ ...identity2
12208
+ };
12209
+ }
12210
+ function readContainerMountinfo(containerId, options) {
12211
+ const result = (0, import_node_child_process23.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
12212
+ encoding: "utf-8",
12213
+ timeout: options.timeoutMs ?? 5e3,
12214
+ stdio: ["ignore", "pipe", "pipe"],
12215
+ ...networkDockerOptions()
12216
+ });
12217
+ if (result.status !== 0 || typeof result.stdout !== "string") return null;
12218
+ const destinations = parseMountinfoDestinations(result.stdout);
12219
+ return destinations.length > 0 ? destinations : null;
12220
+ }
12221
+ function observeManagedMountNesting(container, options = {}) {
12222
+ const destinations = configuredDestinations(container.mounts);
12223
+ const effective = destinations.some((_destination, index) => isNestedIndex(destinations, index)) ? readContainerMountinfo(container.id, options) : null;
12224
+ return classifyManagedMountNesting(container.mounts, effective, container.id);
12225
+ }
12226
+
11954
12227
  // src/core/managed-runtime-status.ts
12228
+ function recoveryPath(repoPath) {
12229
+ if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(repoPath)) return repoPath;
12230
+ return `'${repoPath.replaceAll("'", "'\\''")}'`;
12231
+ }
11955
12232
  function reliabilityRecovery(reason2, repoPath) {
12233
+ const checkout = recoveryPath(repoPath);
11956
12234
  switch (reason2) {
11957
12235
  case "stop-incomplete":
11958
12236
  case "operation-unknown":
11959
- return [`Run: devrouter stop ${repoPath}`, `Run: devrouter ensure ${repoPath} --repair`];
12237
+ return [`Run: devrouter stop ${checkout}`, `Run: devrouter ensure ${checkout} --repair`];
11960
12238
  case "start-refused":
11961
12239
  return [
11962
- `Run: devrouter doctor ${repoPath} to read the refused fixed host-port claim and its holder`,
11963
- `Stop the holding workspace or change this repository's own published binding, then run: devrouter ensure ${repoPath}`
12240
+ `Run: devrouter doctor --repo ${checkout} to read the refused fixed host-port claim and its holder`,
12241
+ `Stop the holding workspace or change this repository's own published binding, then run: devrouter ensure ${checkout}`
11964
12242
  ];
11965
12243
  case "unadmittable":
11966
12244
  return [
11967
- `Run: devrouter stop ${repoPath}`,
11968
- `Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${repoPath}`
12245
+ `Run: devrouter stop ${checkout}`,
12246
+ `Lower the requested capacity in .devrouter.yml, then run: devrouter ensure ${checkout}`
11969
12247
  ];
11970
12248
  case "capacity-parked":
11971
- return [`Run: devrouter ensure ${repoPath} (waits for capacity to free up)`];
12249
+ return [
12250
+ "Parked for host capacity: the enrolled foreground controller resumes this checkout after its pressure dwell and live-consumer checks pass.",
12251
+ `Inspect the parked intent with: devrouter status --repo ${checkout} --json`,
12252
+ `'devrouter ensure' refuses while the journal stays parked; release the intent instead with: devrouter stop ${checkout}`
12253
+ ];
11972
12254
  case "capacity-waiting":
11973
- return [`Run: devrouter ensure ${repoPath} (still queued until capacity frees up)`];
12255
+ return [`Run: devrouter ensure ${checkout} (still queued until capacity frees up)`];
11974
12256
  default:
11975
12257
  return [];
11976
12258
  }
@@ -12222,6 +12504,7 @@ function inspectManagedRuntime(options) {
12222
12504
  (mount) => mount.Type === "bind" && sameWorkspacePath(mount.Source, repoPath)
12223
12505
  )?.Destination;
12224
12506
  const primaryActive = Boolean(primary?.state.Running);
12507
+ const mountNesting = primary && primaryActive ? observeManagedMountNesting(primary) : void 0;
12225
12508
  if (generatedConfigMissing && (state || primaryActive || managedServicesActive)) {
12226
12509
  drift.push("managed generated Dev Container configuration is missing");
12227
12510
  }
@@ -12288,7 +12571,8 @@ function inspectManagedRuntime(options) {
12288
12571
  processStatuses,
12289
12572
  activeServices: sortedUnique(activeServices),
12290
12573
  activeProcesses: sortedUnique(activeProcesses),
12291
- drift
12574
+ drift,
12575
+ ...mountNesting ? { mountNesting } : {}
12292
12576
  };
12293
12577
  }
12294
12578
  function collectManagedRuntimeStatus(options) {
@@ -12436,6 +12720,7 @@ function collectManagedRuntimeStatus(options) {
12436
12720
  baseServiceStatuses: inspection.baseStatuses,
12437
12721
  processStatuses: inspection.processStatuses,
12438
12722
  drift: sortedUnique(drift),
12723
+ ...inspection.mountNesting ? { mountNesting: inspection.mountNesting } : {},
12439
12724
  ...inspection.plan?.sourceConfigSha256 || state?.sourceConfigSha256 ? { sourceConfigSha256: inspection.plan?.sourceConfigSha256 ?? state?.sourceConfigSha256 } : {},
12440
12725
  ...inspection.plan?.effectiveConfigSha256 || state?.effectiveConfigSha256 ? {
12441
12726
  effectiveConfigSha256: inspection.plan?.effectiveConfigSha256 ?? state?.effectiveConfigSha256
@@ -12445,19 +12730,19 @@ function collectManagedRuntimeStatus(options) {
12445
12730
  }
12446
12731
 
12447
12732
  // src/core/network-inventory.ts
12448
- var import_node_child_process23 = require("child_process");
12733
+ var import_node_child_process24 = require("child_process");
12449
12734
  var NetworkInventoryError = class extends Error {
12450
12735
  };
12451
12736
  var MAX_IDS = 4096;
12452
12737
  var MAX_OUTPUT_BYTES = 2 * 1024 * 1024;
12453
12738
  var FULL_ID = /^[a-f0-9]{64}$/;
12454
- var NETWORK_TEMPLATE = '{"id":{{json .Id}},"name":{{json .Name}},"driver":{{json .Driver}},"ipam":{{json .IPAM.Config}},"activeEndpoints":{{len .Containers}},"project":{{json (index .Labels "com.docker.compose.project")}},"network":{{json (index .Labels "com.docker.compose.network")}}';
12739
+ var NETWORK_TEMPLATE = '{"id":{{json .Id}},"name":{{json .Name}},"driver":{{json .Driver}},"ipam":{{json .IPAM.Config}},"activeEndpoints":{{len .Containers}},"project":{{json (index .Labels "com.docker.compose.project")}},"network":{{json (index .Labels "com.docker.compose.network")}}}';
12455
12740
  var CONTAINER_TEMPLATE = '{"id":{{json .Id}},"networks":{{json .NetworkSettings.Networks}}}';
12456
12741
  function readDocker(endpoint, args, timeoutMs) {
12457
12742
  const env = { ...process.env };
12458
12743
  delete env.DOCKER_CONTEXT;
12459
12744
  delete env.DOCKER_HOST;
12460
- const result = (0, import_node_child_process23.spawnSync)("docker", ["--host", endpoint, ...args], {
12745
+ const result = (0, import_node_child_process24.spawnSync)("docker", ["--host", endpoint, ...args], {
12461
12746
  env,
12462
12747
  encoding: "utf-8",
12463
12748
  timeout: timeoutMs,
@@ -12488,7 +12773,14 @@ function id4(value) {
12488
12773
  }
12489
12774
  function rows(output) {
12490
12775
  const trimmed = output.trim();
12491
- return trimmed ? trimmed.split(/\r?\n/).map((line) => JSON.parse(line)) : [];
12776
+ return trimmed ? trimmed.split(/\r?\n/).map((line) => parseRecord(line)) : [];
12777
+ }
12778
+ function parseRecord(line) {
12779
+ try {
12780
+ return JSON.parse(line);
12781
+ } catch {
12782
+ throw new NetworkInventoryError("Docker network inventory contains a malformed record.");
12783
+ }
12492
12784
  }
12493
12785
  function ids(output) {
12494
12786
  const values = output.trim() ? output.trim().split(/\r?\n/).map(id4) : [];
@@ -12533,7 +12825,7 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
12533
12825
  return output;
12534
12826
  };
12535
12827
  const info = record4(
12536
- JSON.parse(
12828
+ parseRecord(
12537
12829
  read2(["info", "--format", '{"id":{{json .ID}},"pools":{{json .DefaultAddressPools}}}'])
12538
12830
  )
12539
12831
  );
@@ -12614,7 +12906,7 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
12614
12906
  }
12615
12907
 
12616
12908
  // src/core/network-routes.ts
12617
- var import_node_child_process24 = require("child_process");
12909
+ var import_node_child_process25 = require("child_process");
12618
12910
  var import_node_net3 = require("net");
12619
12911
 
12620
12912
  // src/core/network-local-daemon.ts
@@ -12683,7 +12975,7 @@ function parseLinuxNetworkRoutes(output) {
12683
12975
  function collectNetworkRoutes(options) {
12684
12976
  if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
12685
12977
  return { status: "unknown", routes: [] };
12686
- const result = (0, import_node_child_process24.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
12978
+ const result = (0, import_node_child_process25.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
12687
12979
  encoding: "utf8",
12688
12980
  timeout: 5e3,
12689
12981
  maxBuffer: 1024 * 1024
@@ -12719,10 +13011,10 @@ function inspectLegacyNetworkCapacity(input) {
12719
13011
  }
12720
13012
 
12721
13013
  // src/core/network-managed.ts
12722
- var import_node_crypto20 = require("crypto");
13014
+ var import_node_crypto21 = require("crypto");
12723
13015
 
12724
13016
  // src/core/network-compose.ts
12725
- var import_node_crypto18 = require("crypto");
13017
+ var import_node_crypto19 = require("crypto");
12726
13018
  var SAFE_ENDPOINT_UPPER_BOUND_SEMANTICS = "full-lifecycle-demand";
12727
13019
  function isRecord5(value) {
12728
13020
  return value !== null && typeof value === "object" && !Array.isArray(value);
@@ -13528,12 +13820,12 @@ function stableValue(value) {
13528
13820
  }
13529
13821
  function fingerprintComposeNetworkModel(input) {
13530
13822
  const projection = normalizedFingerprintProjection(input);
13531
- return (0, import_node_crypto18.createHash)("sha256").update(stableValue(projection), "utf8").digest("hex");
13823
+ return (0, import_node_crypto19.createHash)("sha256").update(stableValue(projection), "utf8").digest("hex");
13532
13824
  }
13533
13825
 
13534
13826
  // src/core/network-compose-files.ts
13535
- var import_node_child_process25 = require("child_process");
13536
- var import_node_crypto19 = require("crypto");
13827
+ var import_node_child_process26 = require("child_process");
13828
+ var import_node_crypto20 = require("crypto");
13537
13829
  var import_node_fs33 = __toESM(require("fs"));
13538
13830
  var import_node_path38 = __toESM(require("path"));
13539
13831
  var import_yaml4 = __toESM(require("yaml"));
@@ -13569,7 +13861,7 @@ function inspectNetworkComposeFiles(input) {
13569
13861
  const env = managedComposeEnvironment(input.workspace);
13570
13862
  delete env.DOCKER_CONTEXT;
13571
13863
  delete env.DOCKER_HOST;
13572
- const result = (0, import_node_child_process25.spawnSync)(
13864
+ const result = (0, import_node_child_process26.spawnSync)(
13573
13865
  "docker",
13574
13866
  [
13575
13867
  "--host",
@@ -13604,7 +13896,7 @@ function prepareNetworkComposeFiles(plan, subnet) {
13604
13896
  const overlay = deriveComposeNetworkOverlay(subnet);
13605
13897
  if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
13606
13898
  const overlayPath = import_node_path38.default.join(plan.composeDirectory, OVERLAY);
13607
- const ignored = (0, import_node_child_process25.spawnSync)("git", [
13899
+ const ignored = (0, import_node_child_process26.spawnSync)("git", [
13608
13900
  "-C",
13609
13901
  plan.composeDirectory,
13610
13902
  "check-ignore",
@@ -13634,7 +13926,7 @@ ${JSON.stringify(extended.config, null, 2)}
13634
13926
  ...plan,
13635
13927
  contents,
13636
13928
  composeFiles: [...plan.composeFiles, overlayPath],
13637
- effectiveConfigSha256: (0, import_node_crypto19.createHash)("sha256").update(contents).digest("hex")
13929
+ effectiveConfigSha256: (0, import_node_crypto20.createHash)("sha256").update(contents).digest("hex")
13638
13930
  };
13639
13931
  return {
13640
13932
  plan: result,
@@ -13646,7 +13938,7 @@ ${JSON.stringify(extended.config, null, 2)}
13646
13938
  }
13647
13939
 
13648
13940
  // src/core/network-connected-route.ts
13649
- var import_node_child_process26 = require("child_process");
13941
+ var import_node_child_process27 = require("child_process");
13650
13942
  function bounds(cidr) {
13651
13943
  const canonical = parseIPv4Cidr(cidr);
13652
13944
  if (!canonical) throw new Error("Invalid connected route.");
@@ -13671,7 +13963,7 @@ function inspectClaimedBridge(claim2, networkId) {
13671
13963
  const env = { ...process.env };
13672
13964
  delete env.DOCKER_CONTEXT;
13673
13965
  delete env.DOCKER_HOST;
13674
- const result = (0, import_node_child_process26.spawnSync)(
13966
+ const result = (0, import_node_child_process27.spawnSync)(
13675
13967
  "docker",
13676
13968
  [
13677
13969
  "--host",
@@ -13698,7 +13990,7 @@ function inspectClaimedBridge(claim2, networkId) {
13698
13990
  const [first, last] = bounds(claim2.subnet);
13699
13991
  const [address] = bounds(gateway);
13700
13992
  if (address <= first || address >= last) throw new Error();
13701
- const interfaces = (0, import_node_child_process26.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
13993
+ const interfaces = (0, import_node_child_process27.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
13702
13994
  encoding: "utf8",
13703
13995
  timeout: 5e3,
13704
13996
  maxBuffer: 65536
@@ -13952,7 +14244,7 @@ function createManagedNetworkSession(input) {
13952
14244
  "Insufficient endpoint headroom; request an allowed larger network before first allocation."
13953
14245
  );
13954
14246
  const authority = readNetworkOperationAuthority(identity2);
13955
- const fingerprint = (0, import_node_crypto20.createHash)("sha256").update(input.plan().sourceConfigSha256).update(fingerprintComposeNetworkModel(model)).digest("hex");
14247
+ const fingerprint = (0, import_node_crypto21.createHash)("sha256").update(input.plan().sourceConfigSha256).update(fingerprintComposeNetworkModel(model)).digest("hex");
13956
14248
  if (!saved) {
13957
14249
  if (policy.status !== "valid")
13958
14250
  throw new Error("New network allocation requires valid machine policy.");
@@ -14454,7 +14746,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14454
14746
  target
14455
14747
  });
14456
14748
  if (target.kind === "linked") {
14457
- const workspaceEnv = (0, import_node_child_process27.spawnSync)(
14749
+ const workspaceEnv = (0, import_node_child_process28.spawnSync)(
14458
14750
  "docker",
14459
14751
  ["exec", appContainer.id, "printenv", "WORKSPACE"],
14460
14752
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14464,7 +14756,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14464
14756
  `Workspace app container must expose WORKSPACE='${target.workspace}' (got '${workspaceEnv.stdout.trim() || "(empty)"}').`
14465
14757
  );
14466
14758
  }
14467
- const devrouterWorkspaceEnv = (0, import_node_child_process27.spawnSync)(
14759
+ const devrouterWorkspaceEnv = (0, import_node_child_process28.spawnSync)(
14468
14760
  "docker",
14469
14761
  ["exec", appContainer.id, "printenv", "DEVROUTER_WORKSPACE"],
14470
14762
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14475,7 +14767,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14475
14767
  );
14476
14768
  }
14477
14769
  }
14478
- const gitCheck = (0, import_node_child_process27.spawnSync)(
14770
+ const gitCheck = (0, import_node_child_process28.spawnSync)(
14479
14771
  "docker",
14480
14772
  [
14481
14773
  "exec",
@@ -14755,7 +15047,7 @@ function isPrimaryCheckout(repoPath) {
14755
15047
  }
14756
15048
  function openUrls(urls) {
14757
15049
  for (const url of urls) {
14758
- const opened = (0, import_node_child_process27.spawnSync)("open", [url], { encoding: "utf-8" });
15050
+ const opened = (0, import_node_child_process28.spawnSync)("open", [url], { encoding: "utf-8" });
14759
15051
  if (opened.status !== 0) {
14760
15052
  process.stderr.write(`Warning: could not open '${url}'.
14761
15053
  `);
@@ -15038,7 +15330,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15038
15330
  transitionPhase = "service-start";
15039
15331
  reportLifecycleProgress("service-start");
15040
15332
  claimLifecycleEffect();
15041
- const result = (0, import_node_child_process27.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15333
+ const result = (0, import_node_child_process28.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15042
15334
  ...networkDockerOptions(),
15043
15335
  encoding: "utf-8",
15044
15336
  timeout: DEFAULT_READINESS_TIMEOUT_MS,
@@ -15982,6 +16274,11 @@ async function executeLifecycleWorker(request, operation) {
15982
16274
  ];
15983
16275
  for (const project of stopProjects) inspectManagedStopContainers(project);
15984
16276
  }
16277
+ updateReliabilityOperation(request.identity, (record5) => {
16278
+ if (!matchesFence(record5, request.fence))
16279
+ throw new Error("Lifecycle intent changed before stop work began.");
16280
+ record5.stopWorkStarted = true;
16281
+ });
15985
16282
  } else {
15986
16283
  updateReliabilityOperation(request.identity, (record5) => {
15987
16284
  stepRecord(record5, {
@@ -16093,6 +16390,7 @@ function proveLifecycleStopped() {
16093
16390
  const settlement = updateReliabilityOperation(request.identity, (record5) => {
16094
16391
  if (!matchesFence(record5, request.fence) || record5.worker)
16095
16392
  throw new Error("Stop proof was superseded or an earlier worker remains.");
16393
+ delete record5.stopWorkStarted;
16096
16394
  if (record5.version === 2) {
16097
16395
  if (record5.capacity) record5.capacity.validUntilMs = 0;
16098
16396
  return record5.state.environmentId;
@@ -16131,6 +16429,7 @@ function proveLifecycleStopped() {
16131
16429
  if (!matchesFence(record5, request.fence) || record5.worker || record5.state.environmentId !== settlement || record5.capacity && record5.capacity.validUntilMs !== 0)
16132
16430
  throw new Error("Capacity settlement was superseded before journal confirmation.");
16133
16431
  record5.capacity = null;
16432
+ delete record5.stopWorkStarted;
16134
16433
  if (record5.enrollment) {
16135
16434
  record5.phaseSettlement = null;
16136
16435
  record5.activeProfile = null;
@@ -16184,7 +16483,7 @@ async function devsyExecOutcome(repoPath, command, retainedProof) {
16184
16483
  const launch = () => {
16185
16484
  if (retainedProof) revalidateDevsyExecProof(repoPath, retainedProof);
16186
16485
  claimLifecycleEffect();
16187
- return (0, import_node_child_process28.spawn)("devsy", args, { stdio: "inherit" });
16486
+ return (0, import_node_child_process29.spawn)("devsy", args, { stdio: "inherit" });
16188
16487
  };
16189
16488
  child = retainedProof ? withMutationLock("Execute retained workspace", repoPath, launch) : launch();
16190
16489
  } catch (error) {
@@ -16232,7 +16531,7 @@ function ensureGuidance2(repoPath) {
16232
16531
  return `Run 'devrouter ensure ${repoPath}' first.`;
16233
16532
  }
16234
16533
  function assertRunningDevpod(devpodId, repoPath) {
16235
- const result = (0, import_node_child_process29.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16534
+ const result = (0, import_node_child_process30.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16236
16535
  encoding: "utf-8"
16237
16536
  });
16238
16537
  if (result.status !== 0) {
@@ -16279,7 +16578,7 @@ async function devpodExecOutcome(repoPath, command) {
16279
16578
  }
16280
16579
  assertRunningDevpod(devpod.id, repoPath);
16281
16580
  const workspaceDirectory = resolveWorkspaceDirectory(repoPath);
16282
- const statusMarker = `__DEVROUTER_EXIT_${(0, import_node_crypto22.randomUUID)()}__:`;
16581
+ const statusMarker = `__DEVROUTER_EXIT_${(0, import_node_crypto23.randomUUID)()}__:`;
16283
16582
  const statusMarkerBytes = Buffer.from(statusMarker, "ascii");
16284
16583
  const literalCommand = command.map(quotePosixArg).join(" ");
16285
16584
  const wrappedCommand = `${literalCommand}; __devrouter_status=$?; printf '${statusMarker}%s\\n' "$__devrouter_status" >&2; exit 0`;
@@ -16411,7 +16710,7 @@ async function devpodExecOutcome(repoPath, command) {
16411
16710
  let child;
16412
16711
  try {
16413
16712
  claimLifecycleEffect();
16414
- child = (0, import_node_child_process29.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16713
+ child = (0, import_node_child_process30.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16415
16714
  } catch (error) {
16416
16715
  settled = true;
16417
16716
  reject(
@@ -16468,7 +16767,7 @@ async function devpodExecOutcome(repoPath, command) {
16468
16767
  }
16469
16768
 
16470
16769
  // src/core/workspace-lifecycle.ts
16471
- var import_node_child_process30 = require("child_process");
16770
+ var import_node_child_process31 = require("child_process");
16472
16771
  var import_node_fs36 = __toESM(require("fs"));
16473
16772
  var import_node_path41 = __toESM(require("path"));
16474
16773