@devrouter/cli 0.1.3 → 0.2.0

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,7 +23,7 @@ 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_process30 = require("child_process");
26
+ var import_node_child_process32 = require("child_process");
27
27
  var import_node_crypto23 = require("crypto");
28
28
 
29
29
  // src/core/devpod-environment.ts
@@ -1958,7 +1958,7 @@ function selectDevpodWorkspace(workspaces, repoPath) {
1958
1958
  }
1959
1959
 
1960
1960
  // src/core/devsy-exec.ts
1961
- var import_node_child_process29 = require("child_process");
1961
+ var import_node_child_process31 = require("child_process");
1962
1962
 
1963
1963
  // src/core/devsy-exec-proof.ts
1964
1964
  var import_node_fs7 = __toESM(require("fs"));
@@ -2046,9 +2046,9 @@ function revalidateDevsyExecProof(repoPath, proof) {
2046
2046
  }
2047
2047
 
2048
2048
  // src/core/devsy-mutation.ts
2049
- var import_node_child_process16 = require("child_process");
2050
- var import_node_fs25 = __toESM(require("fs"));
2051
- var import_node_path29 = __toESM(require("path"));
2049
+ var import_node_child_process18 = require("child_process");
2050
+ var import_node_fs26 = __toESM(require("fs"));
2051
+ var import_node_path30 = __toESM(require("path"));
2052
2052
 
2053
2053
  // src/core/devsy-agent.ts
2054
2054
  var import_node_child_process9 = require("child_process");
@@ -2324,9 +2324,9 @@ function requireReadyDevsyAgent(options = {}) {
2324
2324
  }
2325
2325
 
2326
2326
  // src/core/managed-devsy-stop.ts
2327
- var import_node_fs21 = __toESM(require("fs"));
2327
+ var import_node_fs22 = __toESM(require("fs"));
2328
2328
  var import_node_os5 = __toESM(require("os"));
2329
- var import_node_path25 = __toESM(require("path"));
2329
+ var import_node_path26 = __toESM(require("path"));
2330
2330
  var import_node_util5 = require("util");
2331
2331
 
2332
2332
  // src/core/devcontainer-profile.ts
@@ -5373,7 +5373,7 @@ function retain(session, previous) {
5373
5373
 
5374
5374
  // src/core/reliability-operation-store.ts
5375
5375
  function installedCliVersion() {
5376
- return true ? "0.1.3" : "0.0.0-dev";
5376
+ return true ? "0.2.0" : "0.0.0-dev";
5377
5377
  }
5378
5378
  function compareCliVersions(left, right) {
5379
5379
  const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
@@ -6034,8 +6034,8 @@ function clearStartupWitness(identity2, fence) {
6034
6034
 
6035
6035
  // src/core/repo-config.ts
6036
6036
  var import_node_crypto10 = require("crypto");
6037
- var import_node_fs18 = __toESM(require("fs"));
6038
- var import_node_path22 = __toESM(require("path"));
6037
+ var import_node_fs19 = __toESM(require("fs"));
6038
+ var import_node_path23 = __toESM(require("path"));
6039
6039
  var import_yaml3 = __toESM(require("yaml"));
6040
6040
 
6041
6041
  // src/core/capabilities.ts
@@ -6060,6 +6060,44 @@ function formatSupportedTcpProtocols() {
6060
6060
  return SUPPORTED_TCP_PROTOCOLS.join(", ");
6061
6061
  }
6062
6062
 
6063
+ // src/core/worktree-safety.ts
6064
+ var import_node_child_process13 = require("child_process");
6065
+ var import_node_fs18 = __toESM(require("fs"));
6066
+ var import_node_path22 = __toESM(require("path"));
6067
+
6068
+ // src/core/forge-changes.ts
6069
+ var import_node_child_process12 = require("child_process");
6070
+
6071
+ // src/core/worktree-safety.ts
6072
+ var WORKTREE_LOCAL_SAFETY_CODES = [
6073
+ "git-error",
6074
+ "detached",
6075
+ "index-lock",
6076
+ "operation-in-progress",
6077
+ "submodule",
6078
+ "dirty",
6079
+ "untracked",
6080
+ "ignored-state"
6081
+ ];
6082
+ var WORKTREE_SAFETY_CODES = [
6083
+ ...WORKTREE_LOCAL_SAFETY_CODES,
6084
+ "primary",
6085
+ "locked",
6086
+ "runtime-present",
6087
+ "forge-not-checked",
6088
+ "forge-unavailable",
6089
+ "no-change",
6090
+ "change-open",
6091
+ "change-closed",
6092
+ "head-beyond-merge",
6093
+ "active"
6094
+ ];
6095
+ var DISPOSABLE_OVERRIDE_FILE = import_node_path22.default.join("info", "worktree-reclaim-disposable");
6096
+ function isValidWorktreePattern(pattern) {
6097
+ if (!pattern || pattern.startsWith("/") || pattern.includes("\\")) return false;
6098
+ return pattern.split("/").every((segment) => segment && segment !== "." && segment !== "..");
6099
+ }
6100
+
6063
6101
  // src/core/repo-config.ts
6064
6102
  function compareSemver2(a, b) {
6065
6103
  const parse2 = (v) => {
@@ -6894,6 +6932,7 @@ function parseConfig(raw, configPath) {
6894
6932
  "managedRuntime",
6895
6933
  "profiles",
6896
6934
  "capacity",
6935
+ "worktrees",
6897
6936
  "apps"
6898
6937
  ],
6899
6938
  configPath
@@ -6968,6 +7007,7 @@ function parseConfig(raw, configPath) {
6968
7007
  const managedRuntime = parseManagedRuntime(root.managedRuntime, configPath);
6969
7008
  const profiles = parseProfiles(root.profiles, configPath, apps, managedRuntime);
6970
7009
  const capacity = parseCapacityEstimates(root.capacity, configPath, profiles);
7010
+ const worktrees = parseWorktreesConfig(root.worktrees, configPath);
6971
7011
  return {
6972
7012
  version: 1,
6973
7013
  ...devrouter ? { devrouter } : {},
@@ -6976,9 +7016,30 @@ function parseConfig(raw, configPath) {
6976
7016
  ...managedRuntime ? { managedRuntime } : {},
6977
7017
  ...profiles ? { profiles } : {},
6978
7018
  ...capacity ? { capacity } : {},
7019
+ ...worktrees ? { worktrees } : {},
6979
7020
  apps
6980
7021
  };
6981
7022
  }
7023
+ function parseWorktreesConfig(value, configPath) {
7024
+ if (value === void 0) return void 0;
7025
+ const raw = ensureObject(value, `${configPath}.worktrees`);
7026
+ ensureAllowedKeys(raw, ["disposable", "trim"], `${configPath}.worktrees`);
7027
+ const result = {};
7028
+ for (const key of ["disposable", "trim"]) {
7029
+ if (raw[key] === void 0) continue;
7030
+ const label = `${configPath}.worktrees.${key}`;
7031
+ if (!Array.isArray(raw[key])) throw new Error(`${label} must be an array of patterns.`);
7032
+ result[key] = raw[key].map((pattern, index) => {
7033
+ if (typeof pattern !== "string" || !isValidWorktreePattern(pattern)) {
7034
+ throw new Error(
7035
+ `${label}[${index}] must be a worktree-relative pattern without '..' or a leading '/'.`
7036
+ );
7037
+ }
7038
+ return pattern;
7039
+ });
7040
+ }
7041
+ return result;
7042
+ }
6982
7043
  var PROFILE_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
6983
7044
  var MAX_PROFILES = 32;
6984
7045
  function parseProfiles(value, configPath, apps, managedRuntime) {
@@ -7292,15 +7353,15 @@ function applyProfile(config, profile) {
7292
7353
  return next;
7293
7354
  }
7294
7355
  function resolveRepoPath(repoPath) {
7295
- return import_node_path22.default.resolve(repoPath ?? process.cwd());
7356
+ return import_node_path23.default.resolve(repoPath ?? process.cwd());
7296
7357
  }
7297
7358
  function getRepoConfigPath(repoPath) {
7298
- return import_node_path22.default.join(resolveRepoPath(repoPath), CONFIG_FILE_NAME);
7359
+ return import_node_path23.default.join(resolveRepoPath(repoPath), CONFIG_FILE_NAME);
7299
7360
  }
7300
- function loadRepoConfig(repoPath, read2 = (file) => import_node_fs18.default.readFileSync(file, "utf-8")) {
7361
+ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs19.default.readFileSync(file, "utf-8")) {
7301
7362
  const resolvedRepoPath = resolveRepoPath(repoPath);
7302
7363
  const configPath = getRepoConfigPath(resolvedRepoPath);
7303
- if (!import_node_fs18.default.existsSync(configPath)) {
7364
+ if (!import_node_fs19.default.existsSync(configPath)) {
7304
7365
  throw new Error(
7305
7366
  `Missing ${CONFIG_FILE_NAME} in ${resolvedRepoPath}. Run 'dev repo init --repo ${resolvedRepoPath}' first.`
7306
7367
  );
@@ -7310,7 +7371,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs18.default.rea
7310
7371
  const config = parseConfig(parsed ?? {}, configPath);
7311
7372
  const requiredVersion = config.devrouter?.version;
7312
7373
  if (requiredVersion && !hasWarnedVersionMismatch) {
7313
- const cliVersion = true ? "0.1.3" : "0.0.0-dev";
7374
+ const cliVersion = true ? "0.2.0" : "0.0.0-dev";
7314
7375
  if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
7315
7376
  hasWarnedVersionMismatch = true;
7316
7377
  process.stderr.write(
@@ -7330,7 +7391,7 @@ function namespaceHost(host, workspace) {
7330
7391
  return `${base}.${workspace}${suffix}`;
7331
7392
  }
7332
7393
  function applyWorkspace(config, workspace, repoPath) {
7333
- const defaultToken = wsFromBranch(config.project?.name ?? import_node_path22.default.basename(import_node_path22.default.resolve(repoPath))) ?? "app";
7394
+ const defaultToken = wsFromBranch(config.project?.name ?? import_node_path23.default.basename(import_node_path23.default.resolve(repoPath))) ?? "app";
7334
7395
  const substitutionToken = workspace ?? defaultToken;
7335
7396
  const next = structuredClone(config);
7336
7397
  for (const app of next.apps) {
@@ -7403,7 +7464,7 @@ function resolveAppDependencies(config, app) {
7403
7464
  }
7404
7465
 
7405
7466
  // src/core/docker.ts
7406
- var import_node_child_process12 = require("child_process");
7467
+ var import_node_child_process14 = require("child_process");
7407
7468
  var dockerodeConstructorPromise = null;
7408
7469
  async function getDockerodeConstructor() {
7409
7470
  if (!dockerodeConstructorPromise) {
@@ -7415,7 +7476,7 @@ async function getDockerodeConstructor() {
7415
7476
  return dockerodeConstructorPromise;
7416
7477
  }
7417
7478
  function runDockerContextCommand(args) {
7418
- const result = (0, import_node_child_process12.spawnSync)("docker", ["context", ...args], {
7479
+ const result = (0, import_node_child_process14.spawnSync)("docker", ["context", ...args], {
7419
7480
  encoding: "utf-8"
7420
7481
  });
7421
7482
  if (result.status !== 0) {
@@ -7428,7 +7489,7 @@ function getCurrentDockerContext() {
7428
7489
  return runDockerContextCommand(["show"]);
7429
7490
  }
7430
7491
  function getDockerHostFromContext(context) {
7431
- const result = (0, import_node_child_process12.spawnSync)(
7492
+ const result = (0, import_node_child_process14.spawnSync)(
7432
7493
  "docker",
7433
7494
  ["context", "inspect", context, "--format", "{{ .Endpoints.docker.Host }}"],
7434
7495
  { encoding: "utf-8" }
@@ -7488,16 +7549,16 @@ async function ensureNetwork(name) {
7488
7549
  }
7489
7550
 
7490
7551
  // src/core/tls.ts
7491
- var import_node_child_process13 = require("child_process");
7552
+ var import_node_child_process15 = require("child_process");
7492
7553
  var import_node_crypto11 = require("crypto");
7493
- var import_node_fs19 = __toESM(require("fs"));
7494
- var import_node_path23 = __toESM(require("path"));
7554
+ var import_node_fs20 = __toESM(require("fs"));
7555
+ var import_node_path24 = __toESM(require("path"));
7495
7556
  var DEFAULT_TLS_CERT_HOSTS = ["localhost", "*.localhost"];
7496
- var TLS_CERTIFICATE_LOCK_FILE = import_node_path23.default.join(DEVROUTER_HOME, "tls-certificate.lock");
7557
+ var TLS_CERTIFICATE_LOCK_FILE = import_node_path24.default.join(DEVROUTER_HOME, "tls-certificate.lock");
7497
7558
  var TLS_CERTIFICATE_LOCK_WAIT_MS = 6e4;
7498
7559
  var TLS_CERTIFICATE_WRITE_ATTEMPTS = 2;
7499
7560
  function runOrThrow(command, args) {
7500
- const result = (0, import_node_child_process13.spawnSync)(command, args, {
7561
+ const result = (0, import_node_child_process15.spawnSync)(command, args, {
7501
7562
  encoding: "utf-8"
7502
7563
  });
7503
7564
  if (result.status !== 0) {
@@ -7507,7 +7568,7 @@ function runOrThrow(command, args) {
7507
7568
  return result.stdout.trim();
7508
7569
  }
7509
7570
  function commandExists(command) {
7510
- const result = (0, import_node_child_process13.spawnSync)("sh", ["-c", `command -v ${command}`], { encoding: "utf-8" });
7571
+ const result = (0, import_node_child_process15.spawnSync)("sh", ["-c", `command -v ${command}`], { encoding: "utf-8" });
7511
7572
  return result.status === 0;
7512
7573
  }
7513
7574
  function ensureMkcert() {
@@ -7525,8 +7586,8 @@ function tlsSetupCommand(repoPath) {
7525
7586
  }
7526
7587
  function getMkcertRootCAPath(options = {}) {
7527
7588
  ensureMkcert();
7528
- const rootCAPath = import_node_path23.default.join(runOrThrow("mkcert", ["-CAROOT"]), "rootCA.pem");
7529
- if (!import_node_fs19.default.existsSync(rootCAPath)) {
7589
+ const rootCAPath = import_node_path24.default.join(runOrThrow("mkcert", ["-CAROOT"]), "rootCA.pem");
7590
+ if (!import_node_fs20.default.existsSync(rootCAPath)) {
7530
7591
  throw new Error(
7531
7592
  `mkcert root CA was not found at '${rootCAPath}'. Run: ${tlsSetupCommand(options.repoPath)}`
7532
7593
  );
@@ -7627,11 +7688,11 @@ function compactTLSCertificateHosts(hosts) {
7627
7688
  );
7628
7689
  }
7629
7690
  function readCurrentCertificateHosts(options = {}) {
7630
- if (!import_node_fs19.default.existsSync(CERT_FILE)) {
7691
+ if (!import_node_fs20.default.existsSync(CERT_FILE)) {
7631
7692
  return [];
7632
7693
  }
7633
7694
  try {
7634
- const pem = import_node_fs19.default.readFileSync(CERT_FILE, "utf-8");
7695
+ const pem = import_node_fs20.default.readFileSync(CERT_FILE, "utf-8");
7635
7696
  return parseCertificateDnsHosts(pem);
7636
7697
  } catch (error) {
7637
7698
  if (options.replaceMalformed) {
@@ -7823,11 +7884,11 @@ async function replacePublishedProxyRoutes(repoPath, config, workspace, options
7823
7884
  }
7824
7885
 
7825
7886
  // src/core/traefik-route-health.ts
7826
- var import_node_child_process14 = require("child_process");
7827
- var import_node_fs20 = __toESM(require("fs"));
7828
- var import_node_path24 = __toESM(require("path"));
7887
+ var import_node_child_process16 = require("child_process");
7888
+ var import_node_fs21 = __toESM(require("fs"));
7889
+ var import_node_path25 = __toESM(require("path"));
7829
7890
  var ROUTER_API_BASE = "http://127.0.0.1:8080/api";
7830
- var ROUTER_RELOAD_LOCK_FILE = import_node_path24.default.join(DEVROUTER_HOME, "router-reload.lock");
7891
+ var ROUTER_RELOAD_LOCK_FILE = import_node_path25.default.join(DEVROUTER_HOME, "router-reload.lock");
7831
7892
  var ROUTER_API_REQUEST_TIMEOUT_SECONDS = "2";
7832
7893
  var DEFAULT_INITIAL_TIMEOUT_MS = 3e3;
7833
7894
  var DEFAULT_RECOVERY_TIMEOUT_MS = 1e4;
@@ -7837,7 +7898,7 @@ function sleep(ms) {
7837
7898
  return new Promise((resolve) => setTimeout(resolve, ms));
7838
7899
  }
7839
7900
  function inspectRouterApi(protocol) {
7840
- const result = (0, import_node_child_process14.spawnSync)(
7901
+ const result = (0, import_node_child_process16.spawnSync)(
7841
7902
  "curl",
7842
7903
  [
7843
7904
  "--silent",
@@ -7885,7 +7946,7 @@ function isRecord3(value) {
7885
7946
  return value !== null && typeof value === "object" && !Array.isArray(value);
7886
7947
  }
7887
7948
  function inspectNamedRouterApi(protocol, resource, name) {
7888
- const result = (0, import_node_child_process14.spawnSync)(
7949
+ const result = (0, import_node_child_process16.spawnSync)(
7889
7950
  "curl",
7890
7951
  [
7891
7952
  "--silent",
@@ -8096,7 +8157,7 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
8096
8157
  throw new Error(
8097
8158
  "Traefik routes did not reload; shared router restart is disabled for this operation."
8098
8159
  );
8099
- import_node_fs20.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
8160
+ import_node_fs21.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
8100
8161
  return withFileLock(
8101
8162
  ROUTER_RELOAD_LOCK_FILE,
8102
8163
  {
@@ -8162,7 +8223,7 @@ function proveInitialManagedDevsyAbsence(repoPath, expectedId) {
8162
8223
  if (!isLinkedWorktree(repoPath)) return void 0;
8163
8224
  const workspace = resolveWorktreeWorkspace(repoPath);
8164
8225
  if (!workspace || readManagedRuntimeState(repoPath, workspace)) return void 0;
8165
- if (!import_node_fs21.default.existsSync(import_node_path25.default.join(repoPath, ".devrouter.yml"))) return void 0;
8226
+ if (!import_node_fs22.default.existsSync(import_node_path26.default.join(repoPath, ".devrouter.yml"))) return void 0;
8166
8227
  const runtime = loadRuntimeConfig(repoPath, workspace);
8167
8228
  if (!runtime.config.managedRuntime) return void 0;
8168
8229
  const routes = proxyAppsFromConfig(runtime.config).flatMap(
@@ -8222,7 +8283,7 @@ function proveInitialManagedDevsyAbsence(repoPath, expectedId) {
8222
8283
  };
8223
8284
  }
8224
8285
  function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
8225
- if (!import_node_fs21.default.existsSync(import_node_path25.default.join(repoPath, ".devrouter.yml"))) return false;
8286
+ if (!import_node_fs22.default.existsSync(import_node_path26.default.join(repoPath, ".devrouter.yml"))) return false;
8226
8287
  if (!loadRepoConfig(repoPath).managedRuntime) return false;
8227
8288
  const linked = isLinkedWorktree(repoPath);
8228
8289
  const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
@@ -8279,8 +8340,8 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
8279
8340
  profile: runtime.resolvedProfile,
8280
8341
  linked
8281
8342
  });
8282
- const providerRoot = import_node_path25.default.resolve(process.env.DEVSY_HOME || import_node_path25.default.join(import_node_os5.default.homedir(), ".devsy"));
8283
- const featureDirectory = import_node_path25.default.join(
8343
+ const providerRoot = import_node_path26.default.resolve(process.env.DEVSY_HOME || import_node_path26.default.join(import_node_os5.default.homedir(), ".devsy"));
8344
+ const featureDirectory = import_node_path26.default.join(
8284
8345
  providerRoot,
8285
8346
  "contexts",
8286
8347
  owner.context,
@@ -8401,7 +8462,7 @@ function restoreRecordedManagedDevcontainerConfig(repoPath) {
8401
8462
  }
8402
8463
  function recordedManagedDevcontainerRestorePlan(repoPath) {
8403
8464
  try {
8404
- if (!import_node_fs21.default.existsSync(import_node_path25.default.join(repoPath, ".devrouter.yml"))) return void 0;
8465
+ if (!import_node_fs22.default.existsSync(import_node_path26.default.join(repoPath, ".devrouter.yml"))) return void 0;
8405
8466
  const linked = isLinkedWorktree(repoPath);
8406
8467
  const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
8407
8468
  const state = readManagedRuntimeState(repoPath, workspace);
@@ -8492,7 +8553,7 @@ function stopRetainedManagedDevsyWorkspace(options) {
8492
8553
  const owned = inspectWorkspaceContainers().filter(
8493
8554
  (container) => sameWorkspacePath(
8494
8555
  container.labels["com.docker.compose.project.working_dir"] ?? "",
8495
- import_node_path25.default.join(repoPath, ".devcontainer")
8556
+ import_node_path26.default.join(repoPath, ".devcontainer")
8496
8557
  )
8497
8558
  );
8498
8559
  if (owned.length !== 0) {
@@ -8521,8 +8582,8 @@ function stopRetainedManagedDevsyWorkspace(options) {
8521
8582
  if (!context || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(context) || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(devsyId)) {
8522
8583
  throw new Error("Managed stop requires a valid exact Devsy context and workspace ID.");
8523
8584
  }
8524
- const devsyRoot = import_node_path25.default.resolve(process.env.DEVSY_HOME || import_node_path25.default.join(import_node_os5.default.homedir(), ".devsy"));
8525
- const featureDirectory = import_node_path25.default.join(
8585
+ const devsyRoot = import_node_path26.default.resolve(process.env.DEVSY_HOME || import_node_path26.default.join(import_node_os5.default.homedir(), ".devsy"));
8586
+ const featureDirectory = import_node_path26.default.join(
8526
8587
  devsyRoot,
8527
8588
  "contexts",
8528
8589
  context,
@@ -8661,13 +8722,13 @@ function networkProviderEnvironment(binding, source) {
8661
8722
 
8662
8723
  // src/core/network-claim-lookup.ts
8663
8724
  var import_node_crypto13 = require("crypto");
8664
- var import_node_fs24 = __toESM(require("fs"));
8665
- var import_node_path28 = __toESM(require("path"));
8725
+ var import_node_fs25 = __toESM(require("fs"));
8726
+ var import_node_path29 = __toESM(require("path"));
8666
8727
 
8667
8728
  // src/core/network-claims.ts
8668
8729
  var import_node_crypto12 = require("crypto");
8669
- var import_node_fs23 = __toESM(require("fs"));
8670
- var import_node_path27 = __toESM(require("path"));
8730
+ var import_node_fs24 = __toESM(require("fs"));
8731
+ var import_node_path28 = __toESM(require("path"));
8671
8732
 
8672
8733
  // src/core/network-capacity.ts
8673
8734
  var import_node_net = require("net");
@@ -9008,10 +9069,10 @@ function overlaps(left, right) {
9008
9069
  }
9009
9070
 
9010
9071
  // src/core/network-policy.ts
9011
- var import_node_fs22 = __toESM(require("fs"));
9012
- var import_node_path26 = __toESM(require("path"));
9072
+ var import_node_fs23 = __toESM(require("fs"));
9073
+ var import_node_path27 = __toESM(require("path"));
9013
9074
  var NETWORK_POLICY_VERSION = 1;
9014
- var NETWORK_POLICY_FILE = import_node_path26.default.join(DEVROUTER_HOME, "network-policy.json");
9075
+ var NETWORK_POLICY_FILE = import_node_path27.default.join(DEVROUTER_HOME, "network-policy.json");
9015
9076
  var DEFAULT_NETWORK_POLICY_ENDPOINT_RESERVE = 8;
9016
9077
  var NETWORK_POLICY_PREFIX_LENGTHS = [24, 25, 26];
9017
9078
  var MAX_NETWORK_POLICY_FILE_BYTES = 64 * 1024;
@@ -9204,7 +9265,7 @@ function hasControlCharacter(value) {
9204
9265
  function readPolicyFile(filePath) {
9205
9266
  let initialStats;
9206
9267
  try {
9207
- initialStats = import_node_fs22.default.lstatSync(filePath);
9268
+ initialStats = import_node_fs23.default.lstatSync(filePath);
9208
9269
  } catch (error) {
9209
9270
  if (isErrno(error, "ENOENT")) return { status: "absent" };
9210
9271
  return { status: "invalid", error: "network policy could not be read" };
@@ -9217,16 +9278,16 @@ function readPolicyFile(filePath) {
9217
9278
  }
9218
9279
  let fileDescriptor;
9219
9280
  try {
9220
- fileDescriptor = import_node_fs22.default.openSync(
9281
+ fileDescriptor = import_node_fs23.default.openSync(
9221
9282
  filePath,
9222
- import_node_fs22.default.constants.O_RDONLY | import_node_fs22.default.constants.O_NONBLOCK | (import_node_fs22.default.constants.O_NOFOLLOW ?? 0)
9283
+ import_node_fs23.default.constants.O_RDONLY | import_node_fs23.default.constants.O_NONBLOCK | (import_node_fs23.default.constants.O_NOFOLLOW ?? 0)
9223
9284
  );
9224
9285
  } catch (error) {
9225
9286
  if (isErrno(error, "ENOENT")) return { status: "absent" };
9226
9287
  return { status: "invalid", error: "network policy could not be read" };
9227
9288
  }
9228
9289
  try {
9229
- const openedStats = import_node_fs22.default.fstatSync(fileDescriptor);
9290
+ const openedStats = import_node_fs23.default.fstatSync(fileDescriptor);
9230
9291
  if (!openedStats.isFile()) {
9231
9292
  return { status: "invalid", error: "network policy must be a regular file" };
9232
9293
  }
@@ -9239,12 +9300,12 @@ function readPolicyFile(filePath) {
9239
9300
  const buffer = Buffer.alloc(openedStats.size);
9240
9301
  let offset = 0;
9241
9302
  while (offset < buffer.length) {
9242
- const bytesRead = import_node_fs22.default.readSync(fileDescriptor, buffer, offset, buffer.length - offset, null);
9303
+ const bytesRead = import_node_fs23.default.readSync(fileDescriptor, buffer, offset, buffer.length - offset, null);
9243
9304
  if (bytesRead === 0)
9244
9305
  return { status: "invalid", error: "network policy changed during read" };
9245
9306
  offset += bytesRead;
9246
9307
  }
9247
- const finalStats = import_node_fs22.default.fstatSync(fileDescriptor);
9308
+ const finalStats = import_node_fs23.default.fstatSync(fileDescriptor);
9248
9309
  if (!finalStats.isFile() || finalStats.size !== openedStats.size) {
9249
9310
  return { status: "invalid", error: "network policy changed during read" };
9250
9311
  }
@@ -9253,7 +9314,7 @@ function readPolicyFile(filePath) {
9253
9314
  return { status: "invalid", error: "network policy could not be read" };
9254
9315
  } finally {
9255
9316
  try {
9256
- import_node_fs22.default.closeSync(fileDescriptor);
9317
+ import_node_fs23.default.closeSync(fileDescriptor);
9257
9318
  } catch {
9258
9319
  }
9259
9320
  }
@@ -9273,7 +9334,7 @@ function isErrno(error, code) {
9273
9334
 
9274
9335
  // src/core/network-claims.ts
9275
9336
  var NETWORK_CLAIMS_VERSION = 1;
9276
- var NETWORK_CLAIMS_ROOT = import_node_path27.default.join(DEVROUTER_HOME, "networks");
9337
+ var NETWORK_CLAIMS_ROOT = import_node_path28.default.join(DEVROUTER_HOME, "networks");
9277
9338
  var NETWORK_CLAIMS_MAX_RECORDS = 256;
9278
9339
  var NETWORK_CLAIMS_MAX_FILE_BYTES = 512 * 1024;
9279
9340
  var NETWORK_CLAIMS_DEFAULT_PREFIX = 26;
@@ -9679,27 +9740,27 @@ function assertExactKeys(value, keys2) {
9679
9740
  function readDocument(store) {
9680
9741
  let descriptor;
9681
9742
  try {
9682
- descriptor = import_node_fs23.default.openSync(
9743
+ descriptor = import_node_fs24.default.openSync(
9683
9744
  store.filePath,
9684
- import_node_fs23.default.constants.O_RDONLY | import_node_fs23.default.constants.O_NONBLOCK | (import_node_fs23.default.constants.O_NOFOLLOW ?? 0)
9745
+ import_node_fs24.default.constants.O_RDONLY | import_node_fs24.default.constants.O_NONBLOCK | (import_node_fs24.default.constants.O_NOFOLLOW ?? 0)
9685
9746
  );
9686
9747
  } catch (error) {
9687
9748
  if (isErrno2(error, "ENOENT")) return void 0;
9688
9749
  throw claimError("invalid-state", "network claim state could not be read");
9689
9750
  }
9690
9751
  try {
9691
- const stat = import_node_fs23.default.fstatSync(descriptor);
9752
+ const stat = import_node_fs24.default.fstatSync(descriptor);
9692
9753
  if (!stat.isFile() || stat.size > NETWORK_CLAIMS_MAX_FILE_BYTES || (stat.mode & 63) !== 0) {
9693
9754
  throw claimError("invalid-state", "network claim state is not a bounded private file");
9694
9755
  }
9695
9756
  const buffer = Buffer.alloc(NETWORK_CLAIMS_MAX_FILE_BYTES + 1);
9696
9757
  let count = 0;
9697
9758
  while (count < buffer.length) {
9698
- const bytesRead = import_node_fs23.default.readSync(descriptor, buffer, count, buffer.length - count, null);
9759
+ const bytesRead = import_node_fs24.default.readSync(descriptor, buffer, count, buffer.length - count, null);
9699
9760
  if (bytesRead === 0) break;
9700
9761
  count += bytesRead;
9701
9762
  }
9702
- const finalStat = import_node_fs23.default.fstatSync(descriptor);
9763
+ const finalStat = import_node_fs24.default.fstatSync(descriptor);
9703
9764
  if (count > NETWORK_CLAIMS_MAX_FILE_BYTES || finalStat.size !== stat.size) {
9704
9765
  throw claimError("invalid-state", "network claim state changed during read");
9705
9766
  }
@@ -9711,7 +9772,7 @@ function readDocument(store) {
9711
9772
  }
9712
9773
  return validateDocument(parsed, store.daemonId);
9713
9774
  } finally {
9714
- import_node_fs23.default.closeSync(descriptor);
9775
+ import_node_fs24.default.closeSync(descriptor);
9715
9776
  }
9716
9777
  }
9717
9778
  function validateDocument(value, daemonId) {
@@ -9815,7 +9876,7 @@ function withStoreLock(daemonId, options, operation) {
9815
9876
  if (!Number.isSafeInteger(waitMs) || waitMs < 0 || waitMs > MAX_LOCK_WAIT_MS) {
9816
9877
  throw claimError("invalid-input", "network claim lock wait is invalid");
9817
9878
  }
9818
- import_node_fs23.default.mkdirSync(store.root, { recursive: true, mode: 448 });
9879
+ import_node_fs24.default.mkdirSync(store.root, { recursive: true, mode: 448 });
9819
9880
  assertDirectory(store.root);
9820
9881
  return withFileLockSync(
9821
9882
  store.lockPath,
@@ -9830,23 +9891,23 @@ function createStore(daemonId, options) {
9830
9891
  return {
9831
9892
  root,
9832
9893
  daemonId,
9833
- filePath: import_node_path27.default.join(root, `${key}.json`),
9834
- lockPath: import_node_path27.default.join(root, `${key}.lock`),
9894
+ filePath: import_node_path28.default.join(root, `${key}.json`),
9895
+ lockPath: import_node_path28.default.join(root, `${key}.lock`),
9835
9896
  writeAtomic: options.writeAtomic ?? writeFileAtomically
9836
9897
  };
9837
9898
  }
9838
9899
  function validateRoot(root) {
9839
- if (typeof root !== "string" || !import_node_path27.default.isAbsolute(root) || root.includes("\0")) {
9900
+ if (typeof root !== "string" || !import_node_path28.default.isAbsolute(root) || root.includes("\0")) {
9840
9901
  throw claimError("invalid-input", "network claim root is invalid");
9841
9902
  }
9842
- const resolved = import_node_path27.default.resolve(root);
9903
+ const resolved = import_node_path28.default.resolve(root);
9843
9904
  if (resolved !== root) throw claimError("invalid-input", "network claim root is invalid");
9844
9905
  return resolved;
9845
9906
  }
9846
9907
  function assertDirectory(directory) {
9847
9908
  let stat;
9848
9909
  try {
9849
- stat = import_node_fs23.default.lstatSync(directory);
9910
+ stat = import_node_fs24.default.lstatSync(directory);
9850
9911
  } catch {
9851
9912
  throw claimError("invalid-state", "network claim root could not be read");
9852
9913
  }
@@ -9881,14 +9942,14 @@ function claimError(code, message) {
9881
9942
 
9882
9943
  // src/core/network-claim-lookup.ts
9883
9944
  function networkOwnerKey(repoPath) {
9884
- if (!import_node_path28.default.isAbsolute(repoPath) || import_node_path28.default.resolve(repoPath) !== repoPath)
9945
+ if (!import_node_path29.default.isAbsolute(repoPath) || import_node_path29.default.resolve(repoPath) !== repoPath)
9885
9946
  throw new Error("Invalid network owner path.");
9886
9947
  return (0, import_node_crypto13.createHash)("sha256").update(repoPath).digest("hex");
9887
9948
  }
9888
9949
  function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9889
9950
  let names;
9890
9951
  try {
9891
- names = import_node_fs24.default.readdirSync(root);
9952
+ names = import_node_fs25.default.readdirSync(root);
9892
9953
  } catch (error) {
9893
9954
  if (error.code === "ENOENT") return void 0;
9894
9955
  throw new Error("Network claims cannot be inspected; repair is required.");
@@ -9897,21 +9958,21 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9897
9958
  if (files.length > 128) throw new Error("Network daemon inventory exceeds its bound.");
9898
9959
  let found;
9899
9960
  for (const file of files) {
9900
- const full = import_node_path28.default.join(root, file);
9901
- const stat = import_node_fs24.default.lstatSync(full);
9961
+ const full = import_node_path29.default.join(root, file);
9962
+ const stat = import_node_fs25.default.lstatSync(full);
9902
9963
  if (!stat.isFile() || stat.size > NETWORK_CLAIMS_MAX_FILE_BYTES)
9903
9964
  throw new Error("Invalid retained network claim file.");
9904
9965
  let value;
9905
- const descriptor = import_node_fs24.default.openSync(
9966
+ const descriptor = import_node_fs25.default.openSync(
9906
9967
  full,
9907
- import_node_fs24.default.constants.O_RDONLY | import_node_fs24.default.constants.O_NONBLOCK | import_node_fs24.default.constants.O_NOFOLLOW
9968
+ import_node_fs25.default.constants.O_RDONLY | import_node_fs25.default.constants.O_NONBLOCK | import_node_fs25.default.constants.O_NOFOLLOW
9908
9969
  );
9909
9970
  try {
9910
- if (!import_node_fs24.default.fstatSync(descriptor).isFile()) throw new Error();
9971
+ if (!import_node_fs25.default.fstatSync(descriptor).isFile()) throw new Error();
9911
9972
  const bytes2 = Buffer.alloc(NETWORK_CLAIMS_MAX_FILE_BYTES + 1);
9912
9973
  let size = 0;
9913
9974
  while (size < bytes2.length) {
9914
- const count = import_node_fs24.default.readSync(descriptor, bytes2, size, bytes2.length - size, null);
9975
+ const count = import_node_fs25.default.readSync(descriptor, bytes2, size, bytes2.length - size, null);
9915
9976
  if (!count) break;
9916
9977
  size += count;
9917
9978
  }
@@ -9921,7 +9982,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9921
9982
  } catch {
9922
9983
  throw new Error("Retained network claim could not be read safely.");
9923
9984
  } finally {
9924
- import_node_fs24.default.closeSync(descriptor);
9985
+ import_node_fs25.default.closeSync(descriptor);
9925
9986
  }
9926
9987
  if (typeof value.daemonId !== "string" || `${(0, import_node_crypto13.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
9927
9988
  throw new Error("Retained network daemon identity is invalid.");
@@ -9939,7 +10000,7 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
9939
10000
  }
9940
10001
 
9941
10002
  // src/core/network-provider-inspect.ts
9942
- var import_node_child_process15 = require("child_process");
10003
+ var import_node_child_process17 = require("child_process");
9943
10004
  var import_node_crypto14 = require("crypto");
9944
10005
  function object2(value) {
9945
10006
  if (!value || typeof value !== "object" || Array.isArray(value))
@@ -9963,7 +10024,7 @@ function qualifyNetworkProviderDefinition(value, provider) {
9963
10024
  return (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
9964
10025
  }
9965
10026
  function read(provider, args) {
9966
- const result = (0, import_node_child_process15.spawnSync)(provider, args, {
10027
+ const result = (0, import_node_child_process17.spawnSync)(provider, args, {
9967
10028
  encoding: "utf8",
9968
10029
  timeout: 5e3,
9969
10030
  maxBuffer: 2 * 1024 * 1024
@@ -10077,7 +10138,7 @@ function networkProviderEffectOptions(provider, providerId, repoPath) {
10077
10138
  }
10078
10139
 
10079
10140
  // src/core/devsy-mutation.ts
10080
- var DEVSY_MUTATION_LOCK_FILE = import_node_path29.default.join(DEVROUTER_HOME, "devsy-mutation.lock");
10141
+ var DEVSY_MUTATION_LOCK_FILE = import_node_path30.default.join(DEVROUTER_HOME, "devsy-mutation.lock");
10081
10142
  var DEVSY_MUTATION_WAIT_MS = 18e5;
10082
10143
  var DevsyStartPostconditionError = class extends Error {
10083
10144
  };
@@ -10092,7 +10153,7 @@ function failedStartMayHaveAttached(devsyId, repoPath) {
10092
10153
  }
10093
10154
  }
10094
10155
  function withMutationLock(activity, target, operation) {
10095
- import_node_fs25.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
10156
+ import_node_fs26.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
10096
10157
  return withFileLockSync(
10097
10158
  DEVSY_MUTATION_LOCK_FILE,
10098
10159
  {
@@ -10106,7 +10167,7 @@ function withMutationLock(activity, target, operation) {
10106
10167
  );
10107
10168
  }
10108
10169
  function withMutationLockAsync(activity, target, operation) {
10109
- import_node_fs25.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
10170
+ import_node_fs26.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
10110
10171
  return withFileLock(
10111
10172
  DEVSY_MUTATION_LOCK_FILE,
10112
10173
  {
@@ -10127,7 +10188,7 @@ var DEVSY_STDERR_TAIL_BYTES = 8192;
10127
10188
  function runDevsyUp(args, env, quiet) {
10128
10189
  return new Promise((resolve) => {
10129
10190
  claimLifecycleEffect();
10130
- const child = (0, import_node_child_process16.spawn)("devsy", args, {
10191
+ const child = (0, import_node_child_process18.spawn)("devsy", args, {
10131
10192
  stdio: ["inherit", quiet ? 2 : "inherit", "pipe"],
10132
10193
  env
10133
10194
  });
@@ -10161,7 +10222,7 @@ function runDevsyAction(action, devsyId, force = false, repoPath) {
10161
10222
  const args = action === "delete" ? ["delete", devsyId, ...force ? ["--force"] : [], "--ignore-not-found"] : ["stop", devsyId];
10162
10223
  claimLifecycleEffect();
10163
10224
  const binding = repoPath ? networkProviderEffectOptions("devsy", devsyId, repoPath) : { args: [] };
10164
- const result = (0, import_node_child_process16.spawnSync)("devsy", ["workspace", ...args, ...binding.args], {
10225
+ const result = (0, import_node_child_process18.spawnSync)("devsy", ["workspace", ...args, ...binding.args], {
10165
10226
  encoding: "utf-8",
10166
10227
  ...binding.env ? { env: binding.env } : {}
10167
10228
  });
@@ -10345,21 +10406,21 @@ var ExecutionOutcomeError = class extends Error {
10345
10406
 
10346
10407
  // src/core/reliability-lifecycle.ts
10347
10408
  var import_node_crypto22 = require("crypto");
10348
- var import_node_path40 = __toESM(require("path"));
10409
+ var import_node_path41 = __toESM(require("path"));
10349
10410
  var import_node_util7 = require("util");
10350
10411
 
10351
10412
  // src/core/capacity-policy.ts
10352
- var import_node_fs26 = __toESM(require("fs"));
10353
- var import_node_path30 = __toESM(require("path"));
10413
+ var import_node_fs27 = __toESM(require("fs"));
10414
+ var import_node_path31 = __toESM(require("path"));
10354
10415
 
10355
10416
  // src/core/controller-client.ts
10356
10417
  var import_node_crypto15 = require("crypto");
10357
- var import_node_fs27 = __toESM(require("fs"));
10418
+ var import_node_fs28 = __toESM(require("fs"));
10358
10419
  var import_node_net2 = __toESM(require("net"));
10359
- var import_node_path32 = __toESM(require("path"));
10420
+ var import_node_path33 = __toESM(require("path"));
10360
10421
 
10361
10422
  // src/core/controller-protocol.ts
10362
- var import_node_path31 = __toESM(require("path"));
10423
+ var import_node_path32 = __toESM(require("path"));
10363
10424
  var CONTROLLER_FRAME_BYTES = 64 * 1024;
10364
10425
  var CONTROLLER_MAX_OPERATION_REQUEST_BYTES = 32 * 1024;
10365
10426
  var CONTROLLER_PROFILE_TOKEN_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -11156,10 +11217,10 @@ function stepReliability(state, event, nowMs) {
11156
11217
  }
11157
11218
 
11158
11219
  // src/core/reliability-worker.ts
11159
- var import_node_child_process17 = require("child_process");
11220
+ var import_node_child_process19 = require("child_process");
11160
11221
  var import_node_crypto17 = require("crypto");
11161
- var import_node_fs28 = __toESM(require("fs"));
11162
- var import_node_path33 = __toESM(require("path"));
11222
+ var import_node_fs29 = __toESM(require("fs"));
11223
+ var import_node_path34 = __toESM(require("path"));
11163
11224
 
11164
11225
  // src/core/lifecycle-progress.ts
11165
11226
  var ROLES = {
@@ -11226,20 +11287,20 @@ function workerGroupAbsent(pid) {
11226
11287
  }
11227
11288
 
11228
11289
  // src/core/workspace-ensure.ts
11229
- var import_node_child_process28 = require("child_process");
11230
- var import_node_fs34 = __toESM(require("fs"));
11231
- var import_node_path39 = __toESM(require("path"));
11290
+ var import_node_child_process30 = require("child_process");
11291
+ var import_node_fs35 = __toESM(require("fs"));
11292
+ var import_node_path40 = __toESM(require("path"));
11232
11293
 
11233
11294
  // src/core/devpod-mutation.ts
11234
- var import_node_child_process18 = require("child_process");
11235
- var import_node_fs29 = __toESM(require("fs"));
11236
- var import_node_path34 = __toESM(require("path"));
11237
- var DEVPOD_MUTATION_LOCK_FILE = import_node_path34.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
11295
+ var import_node_child_process20 = require("child_process");
11296
+ var import_node_fs30 = __toESM(require("fs"));
11297
+ var import_node_path35 = __toESM(require("path"));
11298
+ var DEVPOD_MUTATION_LOCK_FILE = import_node_path35.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
11238
11299
  var DEVPOD_MUTATION_WAIT_MS = 18e5;
11239
11300
  var DevpodStartPostconditionError = class extends Error {
11240
11301
  };
11241
11302
  function withMutationLock2(activity, target, operation) {
11242
- import_node_fs29.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
11303
+ import_node_fs30.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
11243
11304
  return withFileLockSync(
11244
11305
  DEVPOD_MUTATION_LOCK_FILE,
11245
11306
  {
@@ -11259,7 +11320,7 @@ function runDevpodAction(action, devpodId, force = false, repoPath) {
11259
11320
  const args = action === "delete" ? [action, devpodId, ...force ? ["--force"] : [], "--ignore-not-found"] : [action, devpodId];
11260
11321
  claimLifecycleEffect();
11261
11322
  const binding = repoPath ? networkProviderEffectOptions("devpod", devpodId, repoPath) : { args: [] };
11262
- const result = (0, import_node_child_process18.spawnSync)("devpod", [...args, ...binding.args], {
11323
+ const result = (0, import_node_child_process20.spawnSync)("devpod", [...args, ...binding.args], {
11263
11324
  encoding: "utf-8",
11264
11325
  ...binding.env ? { env: binding.env } : {}
11265
11326
  });
@@ -11401,7 +11462,7 @@ async function startDevpodWorkspace(options) {
11401
11462
  }
11402
11463
  claimLifecycleEffect();
11403
11464
  network?.beforeDispatch?.();
11404
- const result = (0, import_node_child_process18.spawnSync)("devpod", args, {
11465
+ const result = (0, import_node_child_process20.spawnSync)("devpod", args, {
11405
11466
  stdio: options.quiet ? ["inherit", 2, "inherit"] : "inherit",
11406
11467
  env
11407
11468
  });
@@ -11441,8 +11502,8 @@ async function startDevpodWorkspace(options) {
11441
11502
  }
11442
11503
 
11443
11504
  // src/core/host-port-claims.ts
11444
- var import_node_child_process19 = require("child_process");
11445
- var import_node_path35 = __toESM(require("path"));
11505
+ var import_node_child_process21 = require("child_process");
11506
+ var import_node_path36 = __toESM(require("path"));
11446
11507
  var COMPOSE_RENDER_TIMEOUT_MS = 3e4;
11447
11508
  var COMPOSE_RENDER_MAX_BUFFER = 8 * 1024 * 1024;
11448
11509
  var DOCKER_TIMEOUT_MS = 1e4;
@@ -11545,7 +11606,7 @@ function hostPortBindingsConflict(desired, holder) {
11545
11606
  }
11546
11607
  var HOST_PORT_INSPECT_TEMPLATE = '{"id":{{json .Id}},"name":{{json .Name}},"labels":{"com.docker.compose.project":{{json (index .Config.Labels "com.docker.compose.project")}},"com.docker.compose.project.working_dir":{{json (index .Config.Labels "com.docker.compose.project.working_dir")}}},"ports":{{json .NetworkSettings.Ports}}}';
11547
11608
  function runDocker(args) {
11548
- const result = (0, import_node_child_process19.spawnSync)("docker", args, {
11609
+ const result = (0, import_node_child_process21.spawnSync)("docker", args, {
11549
11610
  ...networkDockerOptions(),
11550
11611
  encoding: "utf-8",
11551
11612
  timeout: DOCKER_TIMEOUT_MS,
@@ -11615,7 +11676,7 @@ function listHolderSnapshots() {
11615
11676
  }
11616
11677
  function renderManagedComposeModel(plan, workspace) {
11617
11678
  const fileArgs = plan.composeFiles.flatMap((file) => ["-f", file]);
11618
- const result = (0, import_node_child_process19.spawnSync)(
11679
+ const result = (0, import_node_child_process21.spawnSync)(
11619
11680
  "docker",
11620
11681
  [
11621
11682
  "compose",
@@ -11650,8 +11711,8 @@ function renderManagedComposeModel(plan, workspace) {
11650
11711
  }
11651
11712
  }
11652
11713
  function attributeHolderWorktree(workingDir) {
11653
- if (import_node_path35.default.basename(workingDir) !== ".devcontainer") return void 0;
11654
- return comparableWorkspacePath(import_node_path35.default.dirname(workingDir));
11714
+ if (import_node_path36.default.basename(workingDir) !== ".devcontainer") return void 0;
11715
+ return comparableWorkspacePath(import_node_path36.default.dirname(workingDir));
11655
11716
  }
11656
11717
  function holderAttribution(holder, repoPath) {
11657
11718
  const attribution = {};
@@ -11686,7 +11747,7 @@ function detectHostPortClaimConflicts(options) {
11686
11747
  );
11687
11748
  if (desired.length === 0) return [];
11688
11749
  const holders = listHolderSnapshots();
11689
- const devcontainerDir = import_node_path35.default.join(options.repoPath, ".devcontainer");
11750
+ const devcontainerDir = import_node_path36.default.join(options.repoPath, ".devcontainer");
11690
11751
  const conflicts = [];
11691
11752
  for (const binding of desired) {
11692
11753
  for (const holder of holders) {
@@ -11710,7 +11771,7 @@ function detectHostPortClaimConflicts(options) {
11710
11771
  }
11711
11772
 
11712
11773
  // src/core/http-route-probe.ts
11713
- var import_node_child_process20 = require("child_process");
11774
+ var import_node_child_process22 = require("child_process");
11714
11775
  var DEFAULT_MAX_TIME_SECONDS = 5;
11715
11776
  var PARENT_TIMEOUT_PADDING_MS = 250;
11716
11777
  var CONTRACT_MAX_BUFFER = 1024;
@@ -11743,7 +11804,7 @@ function probeHttpRoute(host, options = {}) {
11743
11804
  args.push("--cacert", CERT_FILE);
11744
11805
  }
11745
11806
  args.push(url);
11746
- const result = (0, import_node_child_process20.spawnSync)("curl", args, { encoding: "utf-8" });
11807
+ const result = (0, import_node_child_process22.spawnSync)("curl", args, { encoding: "utf-8" });
11747
11808
  const stdout = result.stdout?.trim() ?? "";
11748
11809
  const status = /^\d{3}$/.test(stdout) ? Number(stdout) : void 0;
11749
11810
  const ok = result.status === 0 && status !== void 0 && status >= 100 && status < 500;
@@ -11762,7 +11823,7 @@ function probeHttpReadinessSync(host, readiness, maxTimeSeconds, repoPath) {
11762
11823
  }
11763
11824
  let result;
11764
11825
  try {
11765
- result = (0, import_node_child_process20.spawnSync)("curl", args, {
11826
+ result = (0, import_node_child_process22.spawnSync)("curl", args, {
11766
11827
  encoding: "utf-8",
11767
11828
  maxBuffer: CONTRACT_MAX_BUFFER,
11768
11829
  timeout: Math.ceil(parentTimeoutMs)
@@ -11846,8 +11907,8 @@ function transportFailure() {
11846
11907
  }
11847
11908
 
11848
11909
  // src/core/managed-host-preparation.ts
11849
- var import_node_child_process21 = require("child_process");
11850
- var import_node_fs30 = __toESM(require("fs"));
11910
+ var import_node_child_process23 = require("child_process");
11911
+ var import_node_fs31 = __toESM(require("fs"));
11851
11912
  var PREPARATION_TIMEOUT_MS = 6e4;
11852
11913
  var CONFIG_READ_ERROR = "Managed host preparation could not read .devrouter.yml.";
11853
11914
  var CONFIG_CHANGED_ERROR = "Managed host preparation changed .devrouter.yml; refusing to continue.";
@@ -11858,7 +11919,7 @@ function runPreparationCommand(argv, cwd) {
11858
11919
  return new Promise((resolve) => {
11859
11920
  let child;
11860
11921
  try {
11861
- child = (0, import_node_child_process21.spawn)(argv[0], argv.slice(1), {
11922
+ child = (0, import_node_child_process23.spawn)(argv[0], argv.slice(1), {
11862
11923
  cwd,
11863
11924
  detached: true,
11864
11925
  shell: false,
@@ -11890,7 +11951,7 @@ function runPreparationCommand(argv, cwd) {
11890
11951
  }
11891
11952
  function readConfigBytes(configPath) {
11892
11953
  try {
11893
- return import_node_fs30.default.readFileSync(configPath);
11954
+ return import_node_fs31.default.readFileSync(configPath);
11894
11955
  } catch {
11895
11956
  return void 0;
11896
11957
  }
@@ -11924,10 +11985,10 @@ async function runManagedHostPreparation(repoPath, config) {
11924
11985
  }
11925
11986
 
11926
11987
  // src/core/managed-post-start.ts
11927
- var import_node_child_process22 = require("child_process");
11988
+ var import_node_child_process24 = require("child_process");
11928
11989
  var import_node_crypto18 = require("crypto");
11929
- var import_node_fs31 = __toESM(require("fs"));
11930
- var import_node_path36 = __toESM(require("path"));
11990
+ var import_node_fs32 = __toESM(require("fs"));
11991
+ var import_node_path37 = __toESM(require("path"));
11931
11992
  var MANAGED_MARKER = "devrouter:managed devcontainer";
11932
11993
  var MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
11933
11994
  var RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
@@ -11940,7 +12001,7 @@ function renderDeliveryScript(targetPath) {
11940
12001
  if (!/^\/tmp\/devrouter\/bin\/[a-zA-Z0-9._-]+$/.test(targetPath)) {
11941
12002
  throw new Error(`Unsafe managed runtime delivery path: ${targetPath}`);
11942
12003
  }
11943
- const temporaryPrefix = import_node_path36.default.posix.basename(targetPath);
12004
+ const temporaryPrefix = import_node_path37.default.posix.basename(targetPath);
11944
12005
  return `set -eu
11945
12006
  umask 077
11946
12007
  runtime_root=/tmp/devrouter
@@ -11964,7 +12025,7 @@ function commandFailure3(result) {
11964
12025
  return [result.error?.message, result.stderr, result.stdout].filter(Boolean).map((value) => String(value).trim()).filter(Boolean).join("\n");
11965
12026
  }
11966
12027
  function deliverRuntimeFile(containerId, targetPath, contents, label) {
11967
- const result = (0, import_node_child_process22.spawnSync)(
12028
+ const result = (0, import_node_child_process24.spawnSync)(
11968
12029
  "docker",
11969
12030
  ["exec", "-i", containerId, "sh", "-c", renderDeliveryScript(targetPath)],
11970
12031
  { input: contents, encoding: "utf-8", ...networkDockerOptions() }
@@ -11975,8 +12036,8 @@ function deliverRuntimeFile(containerId, targetPath, contents, label) {
11975
12036
  }
11976
12037
  }
11977
12038
  function readRegularFileBytes(filePath) {
11978
- if (!import_node_fs31.default.existsSync(filePath) || !import_node_fs31.default.lstatSync(filePath).isFile()) return void 0;
11979
- return import_node_fs31.default.readFileSync(filePath);
12039
+ if (!import_node_fs32.default.existsSync(filePath) || !import_node_fs32.default.lstatSync(filePath).isFile()) return void 0;
12040
+ return import_node_fs32.default.readFileSync(filePath);
11980
12041
  }
11981
12042
  function readRegularFile(filePath) {
11982
12043
  return readRegularFileBytes(filePath)?.toString("utf-8");
@@ -11986,21 +12047,21 @@ function adapterFingerprint(adapter) {
11986
12047
  }
11987
12048
  function resolveProcessHelperPath() {
11988
12049
  const candidates = [
11989
- import_node_path36.default.resolve(__dirname, "..", "bin", "devrouter-process"),
11990
- import_node_path36.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
12050
+ import_node_path37.default.resolve(__dirname, "..", "bin", "devrouter-process"),
12051
+ import_node_path37.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
11991
12052
  ];
11992
- const helperPath = candidates.find((candidate) => import_node_fs31.default.existsSync(candidate));
12053
+ const helperPath = candidates.find((candidate) => import_node_fs32.default.existsSync(candidate));
11993
12054
  if (!helperPath) {
11994
12055
  throw new Error("Could not locate the packaged devrouter-process helper.");
11995
12056
  }
11996
12057
  return helperPath;
11997
12058
  }
11998
12059
  function resolveManagedPostStartPlan(repoPath) {
11999
- const adapterPath = import_node_path36.default.join(repoPath, MANAGED_ADAPTER_PATH);
12060
+ const adapterPath = import_node_path37.default.join(repoPath, MANAGED_ADAPTER_PATH);
12000
12061
  const adapterBytes = readRegularFileBytes(adapterPath);
12001
12062
  const adapterText = adapterBytes?.toString("utf-8");
12002
- const dockerfilePath = import_node_path36.default.join(repoPath, ".devcontainer", "Dockerfile");
12003
- const devcontainerPath = import_node_path36.default.join(repoPath, ".devcontainer", "devcontainer.json");
12063
+ const dockerfilePath = import_node_path37.default.join(repoPath, ".devcontainer", "Dockerfile");
12064
+ const devcontainerPath = import_node_path37.default.join(repoPath, ".devcontainer", "devcontainer.json");
12004
12065
  const dockerfile = readRegularFile(dockerfilePath) ?? "";
12005
12066
  const devcontainer = readRegularFile(devcontainerPath) ?? "";
12006
12067
  const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
@@ -12041,7 +12102,7 @@ function resolveManagedPostStartPlan(repoPath) {
12041
12102
  }
12042
12103
  function runManagedPostStart(options) {
12043
12104
  if (options.plan.kind !== "runtime") return;
12044
- const helper = import_node_fs31.default.readFileSync(resolveProcessHelperPath());
12105
+ const helper = import_node_fs32.default.readFileSync(resolveProcessHelperPath());
12045
12106
  deliverRuntimeFile(
12046
12107
  options.container.id,
12047
12108
  RUNTIME_HELPER_PATH,
@@ -12055,7 +12116,7 @@ function runManagedPostStart(options) {
12055
12116
  options.plan.adapterContents,
12056
12117
  "the managed post-start adapter"
12057
12118
  );
12058
- const started2 = (0, import_node_child_process22.spawnSync)(
12119
+ const started2 = (0, import_node_child_process24.spawnSync)(
12059
12120
  "docker",
12060
12121
  [
12061
12122
  "exec",
@@ -12096,7 +12157,7 @@ function assertSafeProcessName(name) {
12096
12157
  }
12097
12158
  function runManagedProcessAction(options) {
12098
12159
  assertSafeProcessName(options.name);
12099
- const result = (0, import_node_child_process22.spawnSync)(
12160
+ const result = (0, import_node_child_process24.spawnSync)(
12100
12161
  "docker",
12101
12162
  [
12102
12163
  "exec",
@@ -12135,7 +12196,7 @@ function runManagedProcessAction(options) {
12135
12196
  }
12136
12197
 
12137
12198
  // src/core/managed-mount-nesting.ts
12138
- var import_node_child_process23 = require("child_process");
12199
+ var import_node_child_process25 = require("child_process");
12139
12200
  var NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
12140
12201
  var UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
12141
12202
  function normalizeDestination(value) {
@@ -12208,7 +12269,7 @@ function classifyManagedMountNesting(configured, effectiveDestinations, containe
12208
12269
  };
12209
12270
  }
12210
12271
  function readContainerMountinfo(containerId, options) {
12211
- const result = (0, import_node_child_process23.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
12272
+ const result = (0, import_node_child_process25.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
12212
12273
  encoding: "utf-8",
12213
12274
  timeout: options.timeoutMs ?? 5e3,
12214
12275
  stdio: ["ignore", "pipe", "pipe"],
@@ -12730,7 +12791,7 @@ function collectManagedRuntimeStatus(options) {
12730
12791
  }
12731
12792
 
12732
12793
  // src/core/network-inventory.ts
12733
- var import_node_child_process24 = require("child_process");
12794
+ var import_node_child_process26 = require("child_process");
12734
12795
  var NetworkInventoryError = class extends Error {
12735
12796
  };
12736
12797
  var MAX_IDS = 4096;
@@ -12742,7 +12803,7 @@ function readDocker(endpoint, args, timeoutMs) {
12742
12803
  const env = { ...process.env };
12743
12804
  delete env.DOCKER_CONTEXT;
12744
12805
  delete env.DOCKER_HOST;
12745
- const result = (0, import_node_child_process24.spawnSync)("docker", ["--host", endpoint, ...args], {
12806
+ const result = (0, import_node_child_process26.spawnSync)("docker", ["--host", endpoint, ...args], {
12746
12807
  env,
12747
12808
  encoding: "utf-8",
12748
12809
  timeout: timeoutMs,
@@ -12906,37 +12967,37 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
12906
12967
  }
12907
12968
 
12908
12969
  // src/core/network-routes.ts
12909
- var import_node_child_process25 = require("child_process");
12970
+ var import_node_child_process27 = require("child_process");
12910
12971
  var import_node_net3 = require("net");
12911
12972
 
12912
12973
  // src/core/network-local-daemon.ts
12913
- var import_node_fs32 = __toESM(require("fs"));
12914
- var import_node_path37 = __toESM(require("path"));
12974
+ var import_node_fs33 = __toESM(require("fs"));
12975
+ var import_node_path38 = __toESM(require("path"));
12915
12976
  function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
12916
12977
  const deadline = Date.now() + 2e3;
12917
12978
  try {
12918
12979
  if (!endpoint.startsWith("unix:///")) return false;
12919
12980
  const socket = endpoint.slice("unix://".length);
12920
- const table = import_node_fs32.default.readFileSync(import_node_path37.default.join(procRoot, "net/unix"), "utf8");
12981
+ const table = import_node_fs33.default.readFileSync(import_node_path38.default.join(procRoot, "net/unix"), "utf8");
12921
12982
  if (Buffer.byteLength(table) > 1024 * 1024) return false;
12922
12983
  const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
12923
12984
  if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
12924
12985
  const inode = `socket:[${rows2[0][6]}]`;
12925
- const ownNamespace = import_node_fs32.default.readlinkSync(import_node_path37.default.join(procRoot, "self/ns/net"));
12926
- const pids = import_node_fs32.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
12986
+ const ownNamespace = import_node_fs33.default.readlinkSync(import_node_path38.default.join(procRoot, "self/ns/net"));
12987
+ const pids = import_node_fs33.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
12927
12988
  if (pids.length > 4096) return false;
12928
12989
  for (const pid of pids) {
12929
12990
  if (Date.now() > deadline) return false;
12930
12991
  try {
12931
- const root = import_node_path37.default.join(procRoot, pid);
12932
- if (import_node_path37.default.basename(import_node_fs32.default.readlinkSync(import_node_path37.default.join(root, "exe"))) !== "dockerd") continue;
12933
- if (import_node_fs32.default.readlinkSync(import_node_path37.default.join(root, "ns/net")) !== ownNamespace) continue;
12934
- const descriptors = import_node_fs32.default.readdirSync(import_node_path37.default.join(root, "fd"));
12992
+ const root = import_node_path38.default.join(procRoot, pid);
12993
+ if (import_node_path38.default.basename(import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "exe"))) !== "dockerd") continue;
12994
+ if (import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "ns/net")) !== ownNamespace) continue;
12995
+ const descriptors = import_node_fs33.default.readdirSync(import_node_path38.default.join(root, "fd"));
12935
12996
  if (descriptors.length > 4096) continue;
12936
12997
  if (descriptors.some((fd) => {
12937
12998
  if (Date.now() > deadline) return false;
12938
12999
  try {
12939
- return import_node_fs32.default.readlinkSync(import_node_path37.default.join(root, "fd", fd)) === inode;
13000
+ return import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "fd", fd)) === inode;
12940
13001
  } catch {
12941
13002
  return false;
12942
13003
  }
@@ -12975,7 +13036,7 @@ function parseLinuxNetworkRoutes(output) {
12975
13036
  function collectNetworkRoutes(options) {
12976
13037
  if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
12977
13038
  return { status: "unknown", routes: [] };
12978
- const result = (0, import_node_child_process25.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
13039
+ const result = (0, import_node_child_process27.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
12979
13040
  encoding: "utf8",
12980
13041
  timeout: 5e3,
12981
13042
  maxBuffer: 1024 * 1024
@@ -13824,10 +13885,10 @@ function fingerprintComposeNetworkModel(input) {
13824
13885
  }
13825
13886
 
13826
13887
  // src/core/network-compose-files.ts
13827
- var import_node_child_process26 = require("child_process");
13888
+ var import_node_child_process28 = require("child_process");
13828
13889
  var import_node_crypto20 = require("crypto");
13829
- var import_node_fs33 = __toESM(require("fs"));
13830
- var import_node_path38 = __toESM(require("path"));
13890
+ var import_node_fs34 = __toESM(require("fs"));
13891
+ var import_node_path39 = __toESM(require("path"));
13831
13892
  var import_yaml4 = __toESM(require("yaml"));
13832
13893
  var OVERLAY = "docker-compose.devrouter-network.yml";
13833
13894
  var MARKER = "# devrouter:managed workspace network";
@@ -13840,12 +13901,12 @@ function object3(value) {
13840
13901
  function inspectNetworkComposeFiles(input) {
13841
13902
  const authoredNetworks = {};
13842
13903
  for (const file of input.plan.composeFiles) {
13843
- const stat = import_node_fs33.default.lstatSync(file);
13904
+ const stat = import_node_fs34.default.lstatSync(file);
13844
13905
  if (!stat.isFile() || stat.size > MAX_BYTES2)
13845
13906
  throw new Error("Network Compose source is unavailable or too large.");
13846
13907
  let source;
13847
13908
  try {
13848
- source = object3(import_yaml4.default.parse(import_node_fs33.default.readFileSync(file, "utf8")));
13909
+ source = object3(import_yaml4.default.parse(import_node_fs34.default.readFileSync(file, "utf8")));
13849
13910
  } catch {
13850
13911
  throw new Error("Network Compose source could not be parsed safely.");
13851
13912
  }
@@ -13861,7 +13922,7 @@ function inspectNetworkComposeFiles(input) {
13861
13922
  const env = managedComposeEnvironment(input.workspace);
13862
13923
  delete env.DOCKER_CONTEXT;
13863
13924
  delete env.DOCKER_HOST;
13864
- const result = (0, import_node_child_process26.spawnSync)(
13925
+ const result = (0, import_node_child_process28.spawnSync)(
13865
13926
  "docker",
13866
13927
  [
13867
13928
  "--host",
@@ -13895,8 +13956,8 @@ function inspectNetworkComposeFiles(input) {
13895
13956
  function prepareNetworkComposeFiles(plan, subnet) {
13896
13957
  const overlay = deriveComposeNetworkOverlay(subnet);
13897
13958
  if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
13898
- const overlayPath = import_node_path38.default.join(plan.composeDirectory, OVERLAY);
13899
- const ignored = (0, import_node_child_process26.spawnSync)("git", [
13959
+ const overlayPath = import_node_path39.default.join(plan.composeDirectory, OVERLAY);
13960
+ const ignored = (0, import_node_child_process28.spawnSync)("git", [
13900
13961
  "-C",
13901
13962
  plan.composeDirectory,
13902
13963
  "check-ignore",
@@ -13910,9 +13971,9 @@ function prepareNetworkComposeFiles(plan, subnet) {
13910
13971
  const bytes2 = `${MARKER}
13911
13972
  ${import_yaml4.default.stringify(overlay.overlay)}`;
13912
13973
  const assertOwnership = () => {
13913
- if (!import_node_fs33.default.existsSync(overlayPath)) return;
13914
- const stat = import_node_fs33.default.lstatSync(overlayPath);
13915
- if (!stat.isFile() || stat.size > MAX_BYTES2 || import_node_fs33.default.readFileSync(overlayPath, "utf8") !== bytes2)
13974
+ if (!import_node_fs34.default.existsSync(overlayPath)) return;
13975
+ const stat = import_node_fs34.default.lstatSync(overlayPath);
13976
+ if (!stat.isFile() || stat.size > MAX_BYTES2 || import_node_fs34.default.readFileSync(overlayPath, "utf8") !== bytes2)
13916
13977
  throw new Error("Retained network overlay changed; repair is required.");
13917
13978
  };
13918
13979
  assertOwnership();
@@ -13938,7 +13999,7 @@ ${JSON.stringify(extended.config, null, 2)}
13938
13999
  }
13939
14000
 
13940
14001
  // src/core/network-connected-route.ts
13941
- var import_node_child_process27 = require("child_process");
14002
+ var import_node_child_process29 = require("child_process");
13942
14003
  function bounds(cidr) {
13943
14004
  const canonical = parseIPv4Cidr(cidr);
13944
14005
  if (!canonical) throw new Error("Invalid connected route.");
@@ -13963,7 +14024,7 @@ function inspectClaimedBridge(claim2, networkId) {
13963
14024
  const env = { ...process.env };
13964
14025
  delete env.DOCKER_CONTEXT;
13965
14026
  delete env.DOCKER_HOST;
13966
- const result = (0, import_node_child_process27.spawnSync)(
14027
+ const result = (0, import_node_child_process29.spawnSync)(
13967
14028
  "docker",
13968
14029
  [
13969
14030
  "--host",
@@ -13990,7 +14051,7 @@ function inspectClaimedBridge(claim2, networkId) {
13990
14051
  const [first, last] = bounds(claim2.subnet);
13991
14052
  const [address] = bounds(gateway);
13992
14053
  if (address <= first || address >= last) throw new Error();
13993
- const interfaces = (0, import_node_child_process27.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
14054
+ const interfaces = (0, import_node_child_process29.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
13994
14055
  encoding: "utf8",
13995
14056
  timeout: 5e3,
13996
14057
  maxBuffer: 65536
@@ -14428,11 +14489,11 @@ var DEFAULT_READINESS_TIMEOUT_MS = 12e4;
14428
14489
  var POLL_INTERVAL_MS = 1e3;
14429
14490
  function assertOverlay(container, repoPath) {
14430
14491
  const workingDir = container.labels["com.docker.compose.project.working_dir"];
14431
- if (!workingDir || !sameWorkspacePath(workingDir, import_node_path39.default.join(repoPath, ".devcontainer"))) {
14492
+ if (!workingDir || !sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))) {
14432
14493
  throw new Error(`Container '${container.id}' does not belong to the exact worktree.`);
14433
14494
  }
14434
14495
  const configFiles = (container.labels["com.docker.compose.project.config_files"] ?? "").split(",").filter(Boolean);
14435
- const expectedOverlay = import_node_path39.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
14496
+ const expectedOverlay = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
14436
14497
  if (!configFiles.some((configFile) => sameWorkspacePath(configFile, expectedOverlay))) {
14437
14498
  throw new Error(`Container '${container.id}' was not started with ${DEVCONTAINER_OVERLAY}.`);
14438
14499
  }
@@ -14446,7 +14507,7 @@ function assertWorktreeOwnership(container, repoPath) {
14446
14507
  function isInsideWorktree(candidate, repoPath) {
14447
14508
  const normalizedCandidate = comparableWorkspacePath(candidate);
14448
14509
  const normalizedRoot = comparableWorkspacePath(repoPath);
14449
- return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${import_node_path39.default.sep}`);
14510
+ return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${import_node_path40.default.sep}`);
14450
14511
  }
14451
14512
  function assertReady(container, label) {
14452
14513
  if (!container.state.Running) {
@@ -14638,7 +14699,7 @@ function hasExactManagedComposeProject(repoPath, state) {
14638
14699
  }).some((container) => {
14639
14700
  const workingDir = container.labels["com.docker.compose.project.working_dir"];
14640
14701
  return Boolean(
14641
- workingDir && sameWorkspacePath(workingDir, import_node_path39.default.join(repoPath, ".devcontainer"))
14702
+ workingDir && sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))
14642
14703
  );
14643
14704
  });
14644
14705
  } catch {
@@ -14746,7 +14807,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14746
14807
  target
14747
14808
  });
14748
14809
  if (target.kind === "linked") {
14749
- const workspaceEnv = (0, import_node_child_process28.spawnSync)(
14810
+ const workspaceEnv = (0, import_node_child_process30.spawnSync)(
14750
14811
  "docker",
14751
14812
  ["exec", appContainer.id, "printenv", "WORKSPACE"],
14752
14813
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14756,7 +14817,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14756
14817
  `Workspace app container must expose WORKSPACE='${target.workspace}' (got '${workspaceEnv.stdout.trim() || "(empty)"}').`
14757
14818
  );
14758
14819
  }
14759
- const devrouterWorkspaceEnv = (0, import_node_child_process28.spawnSync)(
14820
+ const devrouterWorkspaceEnv = (0, import_node_child_process30.spawnSync)(
14760
14821
  "docker",
14761
14822
  ["exec", appContainer.id, "printenv", "DEVROUTER_WORKSPACE"],
14762
14823
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14767,7 +14828,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14767
14828
  );
14768
14829
  }
14769
14830
  }
14770
- const gitCheck = (0, import_node_child_process28.spawnSync)(
14831
+ const gitCheck = (0, import_node_child_process30.spawnSync)(
14771
14832
  "docker",
14772
14833
  [
14773
14834
  "exec",
@@ -15040,14 +15101,14 @@ function resolvePrimaryTarget(repoPath) {
15040
15101
  }
15041
15102
  function isPrimaryCheckout(repoPath) {
15042
15103
  try {
15043
- return import_node_fs34.default.statSync(import_node_path39.default.join(repoPath, ".git")).isDirectory();
15104
+ return import_node_fs35.default.statSync(import_node_path40.default.join(repoPath, ".git")).isDirectory();
15044
15105
  } catch {
15045
15106
  return false;
15046
15107
  }
15047
15108
  }
15048
15109
  function openUrls(urls) {
15049
15110
  for (const url of urls) {
15050
- const opened = (0, import_node_child_process28.spawnSync)("open", [url], { encoding: "utf-8" });
15111
+ const opened = (0, import_node_child_process30.spawnSync)("open", [url], { encoding: "utf-8" });
15051
15112
  if (opened.status !== 0) {
15052
15113
  process.stderr.write(`Warning: could not open '${url}'.
15053
15114
  `);
@@ -15104,8 +15165,8 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15104
15165
  const target = options.repair ? resolveRepairTarget(repoPath, linked) : linked ? resolveLinkedTarget(repoPath) : resolvePrimaryTarget(repoPath);
15105
15166
  let devpodId = target.devpodId;
15106
15167
  if (target.kind === "linked") {
15107
- const overlayPath = import_node_path39.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
15108
- if (!import_node_fs34.default.existsSync(overlayPath)) {
15168
+ const overlayPath = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
15169
+ if (!import_node_fs35.default.existsSync(overlayPath)) {
15109
15170
  throw new Error(`Missing required DevPod compose overlay: ${overlayPath}`);
15110
15171
  }
15111
15172
  }
@@ -15205,7 +15266,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15205
15266
  }
15206
15267
  const apps = proxyAppsFromConfig(runtime.config);
15207
15268
  const parsedUpstreams = apps.map((app) => parseUpstream(app.upstream));
15208
- const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ?? import_node_path39.default.basename(repoPath)) ?? "app";
15269
+ const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ?? import_node_path40.default.basename(repoPath)) ?? "app";
15209
15270
  for (const [index, app] of apps.entries()) {
15210
15271
  if (!parsedUpstreams[index].host.startsWith(`${aliasPrefix}-`)) {
15211
15272
  const owner = target.kind === "linked" ? "workspace" : "checkout";
@@ -15330,7 +15391,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15330
15391
  transitionPhase = "service-start";
15331
15392
  reportLifecycleProgress("service-start");
15332
15393
  claimLifecycleEffect();
15333
- const result = (0, import_node_child_process28.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15394
+ const result = (0, import_node_child_process30.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15334
15395
  ...networkDockerOptions(),
15335
15396
  encoding: "utf-8",
15336
15397
  timeout: DEFAULT_READINESS_TIMEOUT_MS,
@@ -16047,9 +16108,9 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
16047
16108
  }
16048
16109
  const repairLocked = () => {
16049
16110
  const runtime = resolveWorkspaceRuntimeOrDefault(repoPath);
16050
- import_node_fs34.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
16111
+ import_node_fs35.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
16051
16112
  return withFileLock(
16052
- import_node_path39.default.join(DEVROUTER_HOME, `${runtime}-mutation.lock`),
16113
+ import_node_path40.default.join(DEVROUTER_HOME, `${runtime}-mutation.lock`),
16053
16114
  {
16054
16115
  activity: "Managed runtime repair",
16055
16116
  target: repoPath,
@@ -16263,7 +16324,7 @@ async function executeLifecycleWorker(request, operation) {
16263
16324
  const owned = containers.filter(
16264
16325
  (container) => sameWorkspacePath(
16265
16326
  container.labels["com.docker.compose.project.working_dir"] ?? "",
16266
- import_node_path40.default.join(request.repoPath, ".devcontainer")
16327
+ import_node_path41.default.join(request.repoPath, ".devcontainer")
16267
16328
  )
16268
16329
  );
16269
16330
  const projects = owned.map((container) => container.labels["com.docker.compose.project"]);
@@ -16374,7 +16435,7 @@ function proveLifecycleStopped() {
16374
16435
  const remaining = inspectWorkspaceContainers().filter(
16375
16436
  (container) => sameWorkspacePath(
16376
16437
  container.labels["com.docker.compose.project.working_dir"] ?? "",
16377
- import_node_path40.default.join(request.repoPath, ".devcontainer")
16438
+ import_node_path41.default.join(request.repoPath, ".devcontainer")
16378
16439
  )
16379
16440
  );
16380
16441
  if (remaining.some(
@@ -16404,7 +16465,7 @@ function proveLifecycleStopped() {
16404
16465
  return void 0;
16405
16466
  });
16406
16467
  if (settlement) {
16407
- const capacity = createLifecycleCapacityStore(import_node_path40.default.join(DEVROUTER_HOME, "controller"));
16468
+ const capacity = createLifecycleCapacityStore(import_node_path41.default.join(DEVROUTER_HOME, "controller"));
16408
16469
  for (let attempt = 0; ; attempt++) {
16409
16470
  try {
16410
16471
  const state = capacity.inspect();
@@ -16483,7 +16544,7 @@ async function devsyExecOutcome(repoPath, command, retainedProof) {
16483
16544
  const launch = () => {
16484
16545
  if (retainedProof) revalidateDevsyExecProof(repoPath, retainedProof);
16485
16546
  claimLifecycleEffect();
16486
- return (0, import_node_child_process29.spawn)("devsy", args, { stdio: "inherit" });
16547
+ return (0, import_node_child_process31.spawn)("devsy", args, { stdio: "inherit" });
16487
16548
  };
16488
16549
  child = retainedProof ? withMutationLock("Execute retained workspace", repoPath, launch) : launch();
16489
16550
  } catch (error) {
@@ -16531,7 +16592,7 @@ function ensureGuidance2(repoPath) {
16531
16592
  return `Run 'devrouter ensure ${repoPath}' first.`;
16532
16593
  }
16533
16594
  function assertRunningDevpod(devpodId, repoPath) {
16534
- const result = (0, import_node_child_process30.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16595
+ const result = (0, import_node_child_process32.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16535
16596
  encoding: "utf-8"
16536
16597
  });
16537
16598
  if (result.status !== 0) {
@@ -16710,7 +16771,7 @@ async function devpodExecOutcome(repoPath, command) {
16710
16771
  let child;
16711
16772
  try {
16712
16773
  claimLifecycleEffect();
16713
- child = (0, import_node_child_process30.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16774
+ child = (0, import_node_child_process32.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16714
16775
  } catch (error) {
16715
16776
  settled = true;
16716
16777
  reject(
@@ -16767,12 +16828,12 @@ async function devpodExecOutcome(repoPath, command) {
16767
16828
  }
16768
16829
 
16769
16830
  // src/core/workspace-lifecycle.ts
16770
- var import_node_child_process31 = require("child_process");
16771
- var import_node_fs36 = __toESM(require("fs"));
16772
- var import_node_path41 = __toESM(require("path"));
16831
+ var import_node_child_process33 = require("child_process");
16832
+ var import_node_fs37 = __toESM(require("fs"));
16833
+ var import_node_path42 = __toESM(require("path"));
16773
16834
 
16774
16835
  // src/core/route-state.ts
16775
- var import_node_fs35 = __toESM(require("fs"));
16836
+ var import_node_fs36 = __toESM(require("fs"));
16776
16837
  function listRoutesForWorktreePath(worktreePath, routes = listHostRouteState()) {
16777
16838
  return routes.filter((route) => sameWorkspacePath(route.repoPath, worktreePath));
16778
16839
  }