@devrouter/cli 0.1.3 → 0.3.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.3.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.3.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
  });
@@ -10176,6 +10237,25 @@ function inspectExactOwnership(devsyId, worktreePath) {
10176
10237
  if (ownership.status === "conflict") throw new Error(ownership.reason);
10177
10238
  return ownership;
10178
10239
  }
10240
+ function checkoutVanished(worktreePath) {
10241
+ try {
10242
+ import_node_fs26.default.lstatSync(worktreePath);
10243
+ return false;
10244
+ } catch (error) {
10245
+ return error.code === "ENOENT";
10246
+ }
10247
+ }
10248
+ function deleteVanishedCheckoutRegistration(devsyId, worktreePath, originalError) {
10249
+ if (!checkoutVanished(worktreePath)) throw originalError;
10250
+ const runtime = inspectDevsyRuntimeStatus(devsyId);
10251
+ if (runtime !== "stopped" && runtime !== "not-found") throw originalError;
10252
+ runDevsyAction("delete", devsyId, true, worktreePath);
10253
+ if (inspectExactOwnership(devsyId, worktreePath).status !== "absent") {
10254
+ throw new Error(
10255
+ `Devsy workspace '${devsyId}' still owns vanished checkout '${worktreePath}' after forced provider delete.`
10256
+ );
10257
+ }
10258
+ }
10179
10259
  function mutateOwnedDevsyWorkspace(action, devsyId, worktreePath) {
10180
10260
  return withMutationLock(`Devsy ${action}`, worktreePath, () => {
10181
10261
  restoreRecordedManagedDevcontainerConfig(worktreePath);
@@ -10189,7 +10269,13 @@ function mutateOwnedDevsyWorkspace(action, devsyId, worktreePath) {
10189
10269
  }
10190
10270
  const before = inspectExactOwnership(devsyId, worktreePath);
10191
10271
  if (before.status === "absent") return { status: "absent" };
10192
- runDevsyAction(action, devsyId, false, worktreePath);
10272
+ try {
10273
+ runDevsyAction(action, devsyId, false, worktreePath);
10274
+ } catch (error) {
10275
+ if (action !== "delete") throw error;
10276
+ deleteVanishedCheckoutRegistration(devsyId, worktreePath, error);
10277
+ return { status: "changed" };
10278
+ }
10193
10279
  let after = inspectExactOwnership(devsyId, worktreePath);
10194
10280
  if (action === "stop" && after.status !== "owned") {
10195
10281
  throw new Error(
@@ -10345,21 +10431,21 @@ var ExecutionOutcomeError = class extends Error {
10345
10431
 
10346
10432
  // src/core/reliability-lifecycle.ts
10347
10433
  var import_node_crypto22 = require("crypto");
10348
- var import_node_path40 = __toESM(require("path"));
10434
+ var import_node_path41 = __toESM(require("path"));
10349
10435
  var import_node_util7 = require("util");
10350
10436
 
10351
10437
  // src/core/capacity-policy.ts
10352
- var import_node_fs26 = __toESM(require("fs"));
10353
- var import_node_path30 = __toESM(require("path"));
10438
+ var import_node_fs27 = __toESM(require("fs"));
10439
+ var import_node_path31 = __toESM(require("path"));
10354
10440
 
10355
10441
  // src/core/controller-client.ts
10356
10442
  var import_node_crypto15 = require("crypto");
10357
- var import_node_fs27 = __toESM(require("fs"));
10443
+ var import_node_fs28 = __toESM(require("fs"));
10358
10444
  var import_node_net2 = __toESM(require("net"));
10359
- var import_node_path32 = __toESM(require("path"));
10445
+ var import_node_path33 = __toESM(require("path"));
10360
10446
 
10361
10447
  // src/core/controller-protocol.ts
10362
- var import_node_path31 = __toESM(require("path"));
10448
+ var import_node_path32 = __toESM(require("path"));
10363
10449
  var CONTROLLER_FRAME_BYTES = 64 * 1024;
10364
10450
  var CONTROLLER_MAX_OPERATION_REQUEST_BYTES = 32 * 1024;
10365
10451
  var CONTROLLER_PROFILE_TOKEN_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
@@ -11156,10 +11242,10 @@ function stepReliability(state, event, nowMs) {
11156
11242
  }
11157
11243
 
11158
11244
  // src/core/reliability-worker.ts
11159
- var import_node_child_process17 = require("child_process");
11245
+ var import_node_child_process19 = require("child_process");
11160
11246
  var import_node_crypto17 = require("crypto");
11161
- var import_node_fs28 = __toESM(require("fs"));
11162
- var import_node_path33 = __toESM(require("path"));
11247
+ var import_node_fs29 = __toESM(require("fs"));
11248
+ var import_node_path34 = __toESM(require("path"));
11163
11249
 
11164
11250
  // src/core/lifecycle-progress.ts
11165
11251
  var ROLES = {
@@ -11226,20 +11312,20 @@ function workerGroupAbsent(pid) {
11226
11312
  }
11227
11313
 
11228
11314
  // 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"));
11315
+ var import_node_child_process30 = require("child_process");
11316
+ var import_node_fs35 = __toESM(require("fs"));
11317
+ var import_node_path40 = __toESM(require("path"));
11232
11318
 
11233
11319
  // 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");
11320
+ var import_node_child_process20 = require("child_process");
11321
+ var import_node_fs30 = __toESM(require("fs"));
11322
+ var import_node_path35 = __toESM(require("path"));
11323
+ var DEVPOD_MUTATION_LOCK_FILE = import_node_path35.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
11238
11324
  var DEVPOD_MUTATION_WAIT_MS = 18e5;
11239
11325
  var DevpodStartPostconditionError = class extends Error {
11240
11326
  };
11241
11327
  function withMutationLock2(activity, target, operation) {
11242
- import_node_fs29.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
11328
+ import_node_fs30.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
11243
11329
  return withFileLockSync(
11244
11330
  DEVPOD_MUTATION_LOCK_FILE,
11245
11331
  {
@@ -11259,7 +11345,7 @@ function runDevpodAction(action, devpodId, force = false, repoPath) {
11259
11345
  const args = action === "delete" ? [action, devpodId, ...force ? ["--force"] : [], "--ignore-not-found"] : [action, devpodId];
11260
11346
  claimLifecycleEffect();
11261
11347
  const binding = repoPath ? networkProviderEffectOptions("devpod", devpodId, repoPath) : { args: [] };
11262
- const result = (0, import_node_child_process18.spawnSync)("devpod", [...args, ...binding.args], {
11348
+ const result = (0, import_node_child_process20.spawnSync)("devpod", [...args, ...binding.args], {
11263
11349
  encoding: "utf-8",
11264
11350
  ...binding.env ? { env: binding.env } : {}
11265
11351
  });
@@ -11401,7 +11487,7 @@ async function startDevpodWorkspace(options) {
11401
11487
  }
11402
11488
  claimLifecycleEffect();
11403
11489
  network?.beforeDispatch?.();
11404
- const result = (0, import_node_child_process18.spawnSync)("devpod", args, {
11490
+ const result = (0, import_node_child_process20.spawnSync)("devpod", args, {
11405
11491
  stdio: options.quiet ? ["inherit", 2, "inherit"] : "inherit",
11406
11492
  env
11407
11493
  });
@@ -11441,8 +11527,8 @@ async function startDevpodWorkspace(options) {
11441
11527
  }
11442
11528
 
11443
11529
  // src/core/host-port-claims.ts
11444
- var import_node_child_process19 = require("child_process");
11445
- var import_node_path35 = __toESM(require("path"));
11530
+ var import_node_child_process21 = require("child_process");
11531
+ var import_node_path36 = __toESM(require("path"));
11446
11532
  var COMPOSE_RENDER_TIMEOUT_MS = 3e4;
11447
11533
  var COMPOSE_RENDER_MAX_BUFFER = 8 * 1024 * 1024;
11448
11534
  var DOCKER_TIMEOUT_MS = 1e4;
@@ -11545,7 +11631,7 @@ function hostPortBindingsConflict(desired, holder) {
11545
11631
  }
11546
11632
  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
11633
  function runDocker(args) {
11548
- const result = (0, import_node_child_process19.spawnSync)("docker", args, {
11634
+ const result = (0, import_node_child_process21.spawnSync)("docker", args, {
11549
11635
  ...networkDockerOptions(),
11550
11636
  encoding: "utf-8",
11551
11637
  timeout: DOCKER_TIMEOUT_MS,
@@ -11615,7 +11701,7 @@ function listHolderSnapshots() {
11615
11701
  }
11616
11702
  function renderManagedComposeModel(plan, workspace) {
11617
11703
  const fileArgs = plan.composeFiles.flatMap((file) => ["-f", file]);
11618
- const result = (0, import_node_child_process19.spawnSync)(
11704
+ const result = (0, import_node_child_process21.spawnSync)(
11619
11705
  "docker",
11620
11706
  [
11621
11707
  "compose",
@@ -11650,8 +11736,8 @@ function renderManagedComposeModel(plan, workspace) {
11650
11736
  }
11651
11737
  }
11652
11738
  function attributeHolderWorktree(workingDir) {
11653
- if (import_node_path35.default.basename(workingDir) !== ".devcontainer") return void 0;
11654
- return comparableWorkspacePath(import_node_path35.default.dirname(workingDir));
11739
+ if (import_node_path36.default.basename(workingDir) !== ".devcontainer") return void 0;
11740
+ return comparableWorkspacePath(import_node_path36.default.dirname(workingDir));
11655
11741
  }
11656
11742
  function holderAttribution(holder, repoPath) {
11657
11743
  const attribution = {};
@@ -11686,7 +11772,7 @@ function detectHostPortClaimConflicts(options) {
11686
11772
  );
11687
11773
  if (desired.length === 0) return [];
11688
11774
  const holders = listHolderSnapshots();
11689
- const devcontainerDir = import_node_path35.default.join(options.repoPath, ".devcontainer");
11775
+ const devcontainerDir = import_node_path36.default.join(options.repoPath, ".devcontainer");
11690
11776
  const conflicts = [];
11691
11777
  for (const binding of desired) {
11692
11778
  for (const holder of holders) {
@@ -11710,7 +11796,7 @@ function detectHostPortClaimConflicts(options) {
11710
11796
  }
11711
11797
 
11712
11798
  // src/core/http-route-probe.ts
11713
- var import_node_child_process20 = require("child_process");
11799
+ var import_node_child_process22 = require("child_process");
11714
11800
  var DEFAULT_MAX_TIME_SECONDS = 5;
11715
11801
  var PARENT_TIMEOUT_PADDING_MS = 250;
11716
11802
  var CONTRACT_MAX_BUFFER = 1024;
@@ -11743,7 +11829,7 @@ function probeHttpRoute(host, options = {}) {
11743
11829
  args.push("--cacert", CERT_FILE);
11744
11830
  }
11745
11831
  args.push(url);
11746
- const result = (0, import_node_child_process20.spawnSync)("curl", args, { encoding: "utf-8" });
11832
+ const result = (0, import_node_child_process22.spawnSync)("curl", args, { encoding: "utf-8" });
11747
11833
  const stdout = result.stdout?.trim() ?? "";
11748
11834
  const status = /^\d{3}$/.test(stdout) ? Number(stdout) : void 0;
11749
11835
  const ok = result.status === 0 && status !== void 0 && status >= 100 && status < 500;
@@ -11762,7 +11848,7 @@ function probeHttpReadinessSync(host, readiness, maxTimeSeconds, repoPath) {
11762
11848
  }
11763
11849
  let result;
11764
11850
  try {
11765
- result = (0, import_node_child_process20.spawnSync)("curl", args, {
11851
+ result = (0, import_node_child_process22.spawnSync)("curl", args, {
11766
11852
  encoding: "utf-8",
11767
11853
  maxBuffer: CONTRACT_MAX_BUFFER,
11768
11854
  timeout: Math.ceil(parentTimeoutMs)
@@ -11846,8 +11932,8 @@ function transportFailure() {
11846
11932
  }
11847
11933
 
11848
11934
  // src/core/managed-host-preparation.ts
11849
- var import_node_child_process21 = require("child_process");
11850
- var import_node_fs30 = __toESM(require("fs"));
11935
+ var import_node_child_process23 = require("child_process");
11936
+ var import_node_fs31 = __toESM(require("fs"));
11851
11937
  var PREPARATION_TIMEOUT_MS = 6e4;
11852
11938
  var CONFIG_READ_ERROR = "Managed host preparation could not read .devrouter.yml.";
11853
11939
  var CONFIG_CHANGED_ERROR = "Managed host preparation changed .devrouter.yml; refusing to continue.";
@@ -11858,7 +11944,7 @@ function runPreparationCommand(argv, cwd) {
11858
11944
  return new Promise((resolve) => {
11859
11945
  let child;
11860
11946
  try {
11861
- child = (0, import_node_child_process21.spawn)(argv[0], argv.slice(1), {
11947
+ child = (0, import_node_child_process23.spawn)(argv[0], argv.slice(1), {
11862
11948
  cwd,
11863
11949
  detached: true,
11864
11950
  shell: false,
@@ -11890,7 +11976,7 @@ function runPreparationCommand(argv, cwd) {
11890
11976
  }
11891
11977
  function readConfigBytes(configPath) {
11892
11978
  try {
11893
- return import_node_fs30.default.readFileSync(configPath);
11979
+ return import_node_fs31.default.readFileSync(configPath);
11894
11980
  } catch {
11895
11981
  return void 0;
11896
11982
  }
@@ -11924,10 +12010,10 @@ async function runManagedHostPreparation(repoPath, config) {
11924
12010
  }
11925
12011
 
11926
12012
  // src/core/managed-post-start.ts
11927
- var import_node_child_process22 = require("child_process");
12013
+ var import_node_child_process24 = require("child_process");
11928
12014
  var import_node_crypto18 = require("crypto");
11929
- var import_node_fs31 = __toESM(require("fs"));
11930
- var import_node_path36 = __toESM(require("path"));
12015
+ var import_node_fs32 = __toESM(require("fs"));
12016
+ var import_node_path37 = __toESM(require("path"));
11931
12017
  var MANAGED_MARKER = "devrouter:managed devcontainer";
11932
12018
  var MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
11933
12019
  var RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
@@ -11940,7 +12026,7 @@ function renderDeliveryScript(targetPath) {
11940
12026
  if (!/^\/tmp\/devrouter\/bin\/[a-zA-Z0-9._-]+$/.test(targetPath)) {
11941
12027
  throw new Error(`Unsafe managed runtime delivery path: ${targetPath}`);
11942
12028
  }
11943
- const temporaryPrefix = import_node_path36.default.posix.basename(targetPath);
12029
+ const temporaryPrefix = import_node_path37.default.posix.basename(targetPath);
11944
12030
  return `set -eu
11945
12031
  umask 077
11946
12032
  runtime_root=/tmp/devrouter
@@ -11964,7 +12050,7 @@ function commandFailure3(result) {
11964
12050
  return [result.error?.message, result.stderr, result.stdout].filter(Boolean).map((value) => String(value).trim()).filter(Boolean).join("\n");
11965
12051
  }
11966
12052
  function deliverRuntimeFile(containerId, targetPath, contents, label) {
11967
- const result = (0, import_node_child_process22.spawnSync)(
12053
+ const result = (0, import_node_child_process24.spawnSync)(
11968
12054
  "docker",
11969
12055
  ["exec", "-i", containerId, "sh", "-c", renderDeliveryScript(targetPath)],
11970
12056
  { input: contents, encoding: "utf-8", ...networkDockerOptions() }
@@ -11975,8 +12061,8 @@ function deliverRuntimeFile(containerId, targetPath, contents, label) {
11975
12061
  }
11976
12062
  }
11977
12063
  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);
12064
+ if (!import_node_fs32.default.existsSync(filePath) || !import_node_fs32.default.lstatSync(filePath).isFile()) return void 0;
12065
+ return import_node_fs32.default.readFileSync(filePath);
11980
12066
  }
11981
12067
  function readRegularFile(filePath) {
11982
12068
  return readRegularFileBytes(filePath)?.toString("utf-8");
@@ -11986,21 +12072,21 @@ function adapterFingerprint(adapter) {
11986
12072
  }
11987
12073
  function resolveProcessHelperPath() {
11988
12074
  const candidates = [
11989
- import_node_path36.default.resolve(__dirname, "..", "bin", "devrouter-process"),
11990
- import_node_path36.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
12075
+ import_node_path37.default.resolve(__dirname, "..", "bin", "devrouter-process"),
12076
+ import_node_path37.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
11991
12077
  ];
11992
- const helperPath = candidates.find((candidate) => import_node_fs31.default.existsSync(candidate));
12078
+ const helperPath = candidates.find((candidate) => import_node_fs32.default.existsSync(candidate));
11993
12079
  if (!helperPath) {
11994
12080
  throw new Error("Could not locate the packaged devrouter-process helper.");
11995
12081
  }
11996
12082
  return helperPath;
11997
12083
  }
11998
12084
  function resolveManagedPostStartPlan(repoPath) {
11999
- const adapterPath = import_node_path36.default.join(repoPath, MANAGED_ADAPTER_PATH);
12085
+ const adapterPath = import_node_path37.default.join(repoPath, MANAGED_ADAPTER_PATH);
12000
12086
  const adapterBytes = readRegularFileBytes(adapterPath);
12001
12087
  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");
12088
+ const dockerfilePath = import_node_path37.default.join(repoPath, ".devcontainer", "Dockerfile");
12089
+ const devcontainerPath = import_node_path37.default.join(repoPath, ".devcontainer", "devcontainer.json");
12004
12090
  const dockerfile = readRegularFile(dockerfilePath) ?? "";
12005
12091
  const devcontainer = readRegularFile(devcontainerPath) ?? "";
12006
12092
  const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
@@ -12041,7 +12127,7 @@ function resolveManagedPostStartPlan(repoPath) {
12041
12127
  }
12042
12128
  function runManagedPostStart(options) {
12043
12129
  if (options.plan.kind !== "runtime") return;
12044
- const helper = import_node_fs31.default.readFileSync(resolveProcessHelperPath());
12130
+ const helper = import_node_fs32.default.readFileSync(resolveProcessHelperPath());
12045
12131
  deliverRuntimeFile(
12046
12132
  options.container.id,
12047
12133
  RUNTIME_HELPER_PATH,
@@ -12055,7 +12141,7 @@ function runManagedPostStart(options) {
12055
12141
  options.plan.adapterContents,
12056
12142
  "the managed post-start adapter"
12057
12143
  );
12058
- const started2 = (0, import_node_child_process22.spawnSync)(
12144
+ const started2 = (0, import_node_child_process24.spawnSync)(
12059
12145
  "docker",
12060
12146
  [
12061
12147
  "exec",
@@ -12096,7 +12182,7 @@ function assertSafeProcessName(name) {
12096
12182
  }
12097
12183
  function runManagedProcessAction(options) {
12098
12184
  assertSafeProcessName(options.name);
12099
- const result = (0, import_node_child_process22.spawnSync)(
12185
+ const result = (0, import_node_child_process24.spawnSync)(
12100
12186
  "docker",
12101
12187
  [
12102
12188
  "exec",
@@ -12135,7 +12221,7 @@ function runManagedProcessAction(options) {
12135
12221
  }
12136
12222
 
12137
12223
  // src/core/managed-mount-nesting.ts
12138
- var import_node_child_process23 = require("child_process");
12224
+ var import_node_child_process25 = require("child_process");
12139
12225
  var NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
12140
12226
  var UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
12141
12227
  function normalizeDestination(value) {
@@ -12208,7 +12294,7 @@ function classifyManagedMountNesting(configured, effectiveDestinations, containe
12208
12294
  };
12209
12295
  }
12210
12296
  function readContainerMountinfo(containerId, options) {
12211
- const result = (0, import_node_child_process23.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
12297
+ const result = (0, import_node_child_process25.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
12212
12298
  encoding: "utf-8",
12213
12299
  timeout: options.timeoutMs ?? 5e3,
12214
12300
  stdio: ["ignore", "pipe", "pipe"],
@@ -12730,7 +12816,7 @@ function collectManagedRuntimeStatus(options) {
12730
12816
  }
12731
12817
 
12732
12818
  // src/core/network-inventory.ts
12733
- var import_node_child_process24 = require("child_process");
12819
+ var import_node_child_process26 = require("child_process");
12734
12820
  var NetworkInventoryError = class extends Error {
12735
12821
  };
12736
12822
  var MAX_IDS = 4096;
@@ -12742,7 +12828,7 @@ function readDocker(endpoint, args, timeoutMs) {
12742
12828
  const env = { ...process.env };
12743
12829
  delete env.DOCKER_CONTEXT;
12744
12830
  delete env.DOCKER_HOST;
12745
- const result = (0, import_node_child_process24.spawnSync)("docker", ["--host", endpoint, ...args], {
12831
+ const result = (0, import_node_child_process26.spawnSync)("docker", ["--host", endpoint, ...args], {
12746
12832
  env,
12747
12833
  encoding: "utf-8",
12748
12834
  timeout: timeoutMs,
@@ -12906,37 +12992,37 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
12906
12992
  }
12907
12993
 
12908
12994
  // src/core/network-routes.ts
12909
- var import_node_child_process25 = require("child_process");
12995
+ var import_node_child_process27 = require("child_process");
12910
12996
  var import_node_net3 = require("net");
12911
12997
 
12912
12998
  // src/core/network-local-daemon.ts
12913
- var import_node_fs32 = __toESM(require("fs"));
12914
- var import_node_path37 = __toESM(require("path"));
12999
+ var import_node_fs33 = __toESM(require("fs"));
13000
+ var import_node_path38 = __toESM(require("path"));
12915
13001
  function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
12916
13002
  const deadline = Date.now() + 2e3;
12917
13003
  try {
12918
13004
  if (!endpoint.startsWith("unix:///")) return false;
12919
13005
  const socket = endpoint.slice("unix://".length);
12920
- const table = import_node_fs32.default.readFileSync(import_node_path37.default.join(procRoot, "net/unix"), "utf8");
13006
+ const table = import_node_fs33.default.readFileSync(import_node_path38.default.join(procRoot, "net/unix"), "utf8");
12921
13007
  if (Buffer.byteLength(table) > 1024 * 1024) return false;
12922
13008
  const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
12923
13009
  if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
12924
13010
  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));
13011
+ const ownNamespace = import_node_fs33.default.readlinkSync(import_node_path38.default.join(procRoot, "self/ns/net"));
13012
+ const pids = import_node_fs33.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
12927
13013
  if (pids.length > 4096) return false;
12928
13014
  for (const pid of pids) {
12929
13015
  if (Date.now() > deadline) return false;
12930
13016
  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"));
13017
+ const root = import_node_path38.default.join(procRoot, pid);
13018
+ if (import_node_path38.default.basename(import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "exe"))) !== "dockerd") continue;
13019
+ if (import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "ns/net")) !== ownNamespace) continue;
13020
+ const descriptors = import_node_fs33.default.readdirSync(import_node_path38.default.join(root, "fd"));
12935
13021
  if (descriptors.length > 4096) continue;
12936
13022
  if (descriptors.some((fd) => {
12937
13023
  if (Date.now() > deadline) return false;
12938
13024
  try {
12939
- return import_node_fs32.default.readlinkSync(import_node_path37.default.join(root, "fd", fd)) === inode;
13025
+ return import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "fd", fd)) === inode;
12940
13026
  } catch {
12941
13027
  return false;
12942
13028
  }
@@ -12975,7 +13061,7 @@ function parseLinuxNetworkRoutes(output) {
12975
13061
  function collectNetworkRoutes(options) {
12976
13062
  if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
12977
13063
  return { status: "unknown", routes: [] };
12978
- const result = (0, import_node_child_process25.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
13064
+ const result = (0, import_node_child_process27.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
12979
13065
  encoding: "utf8",
12980
13066
  timeout: 5e3,
12981
13067
  maxBuffer: 1024 * 1024
@@ -13824,10 +13910,10 @@ function fingerprintComposeNetworkModel(input) {
13824
13910
  }
13825
13911
 
13826
13912
  // src/core/network-compose-files.ts
13827
- var import_node_child_process26 = require("child_process");
13913
+ var import_node_child_process28 = require("child_process");
13828
13914
  var import_node_crypto20 = require("crypto");
13829
- var import_node_fs33 = __toESM(require("fs"));
13830
- var import_node_path38 = __toESM(require("path"));
13915
+ var import_node_fs34 = __toESM(require("fs"));
13916
+ var import_node_path39 = __toESM(require("path"));
13831
13917
  var import_yaml4 = __toESM(require("yaml"));
13832
13918
  var OVERLAY = "docker-compose.devrouter-network.yml";
13833
13919
  var MARKER = "# devrouter:managed workspace network";
@@ -13840,12 +13926,12 @@ function object3(value) {
13840
13926
  function inspectNetworkComposeFiles(input) {
13841
13927
  const authoredNetworks = {};
13842
13928
  for (const file of input.plan.composeFiles) {
13843
- const stat = import_node_fs33.default.lstatSync(file);
13929
+ const stat = import_node_fs34.default.lstatSync(file);
13844
13930
  if (!stat.isFile() || stat.size > MAX_BYTES2)
13845
13931
  throw new Error("Network Compose source is unavailable or too large.");
13846
13932
  let source;
13847
13933
  try {
13848
- source = object3(import_yaml4.default.parse(import_node_fs33.default.readFileSync(file, "utf8")));
13934
+ source = object3(import_yaml4.default.parse(import_node_fs34.default.readFileSync(file, "utf8")));
13849
13935
  } catch {
13850
13936
  throw new Error("Network Compose source could not be parsed safely.");
13851
13937
  }
@@ -13861,7 +13947,7 @@ function inspectNetworkComposeFiles(input) {
13861
13947
  const env = managedComposeEnvironment(input.workspace);
13862
13948
  delete env.DOCKER_CONTEXT;
13863
13949
  delete env.DOCKER_HOST;
13864
- const result = (0, import_node_child_process26.spawnSync)(
13950
+ const result = (0, import_node_child_process28.spawnSync)(
13865
13951
  "docker",
13866
13952
  [
13867
13953
  "--host",
@@ -13895,8 +13981,8 @@ function inspectNetworkComposeFiles(input) {
13895
13981
  function prepareNetworkComposeFiles(plan, subnet) {
13896
13982
  const overlay = deriveComposeNetworkOverlay(subnet);
13897
13983
  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", [
13984
+ const overlayPath = import_node_path39.default.join(plan.composeDirectory, OVERLAY);
13985
+ const ignored = (0, import_node_child_process28.spawnSync)("git", [
13900
13986
  "-C",
13901
13987
  plan.composeDirectory,
13902
13988
  "check-ignore",
@@ -13910,9 +13996,9 @@ function prepareNetworkComposeFiles(plan, subnet) {
13910
13996
  const bytes2 = `${MARKER}
13911
13997
  ${import_yaml4.default.stringify(overlay.overlay)}`;
13912
13998
  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)
13999
+ if (!import_node_fs34.default.existsSync(overlayPath)) return;
14000
+ const stat = import_node_fs34.default.lstatSync(overlayPath);
14001
+ if (!stat.isFile() || stat.size > MAX_BYTES2 || import_node_fs34.default.readFileSync(overlayPath, "utf8") !== bytes2)
13916
14002
  throw new Error("Retained network overlay changed; repair is required.");
13917
14003
  };
13918
14004
  assertOwnership();
@@ -13938,7 +14024,7 @@ ${JSON.stringify(extended.config, null, 2)}
13938
14024
  }
13939
14025
 
13940
14026
  // src/core/network-connected-route.ts
13941
- var import_node_child_process27 = require("child_process");
14027
+ var import_node_child_process29 = require("child_process");
13942
14028
  function bounds(cidr) {
13943
14029
  const canonical = parseIPv4Cidr(cidr);
13944
14030
  if (!canonical) throw new Error("Invalid connected route.");
@@ -13963,7 +14049,7 @@ function inspectClaimedBridge(claim2, networkId) {
13963
14049
  const env = { ...process.env };
13964
14050
  delete env.DOCKER_CONTEXT;
13965
14051
  delete env.DOCKER_HOST;
13966
- const result = (0, import_node_child_process27.spawnSync)(
14052
+ const result = (0, import_node_child_process29.spawnSync)(
13967
14053
  "docker",
13968
14054
  [
13969
14055
  "--host",
@@ -13990,7 +14076,7 @@ function inspectClaimedBridge(claim2, networkId) {
13990
14076
  const [first, last] = bounds(claim2.subnet);
13991
14077
  const [address] = bounds(gateway);
13992
14078
  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], {
14079
+ const interfaces = (0, import_node_child_process29.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
13994
14080
  encoding: "utf8",
13995
14081
  timeout: 5e3,
13996
14082
  maxBuffer: 65536
@@ -14428,11 +14514,11 @@ var DEFAULT_READINESS_TIMEOUT_MS = 12e4;
14428
14514
  var POLL_INTERVAL_MS = 1e3;
14429
14515
  function assertOverlay(container, repoPath) {
14430
14516
  const workingDir = container.labels["com.docker.compose.project.working_dir"];
14431
- if (!workingDir || !sameWorkspacePath(workingDir, import_node_path39.default.join(repoPath, ".devcontainer"))) {
14517
+ if (!workingDir || !sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))) {
14432
14518
  throw new Error(`Container '${container.id}' does not belong to the exact worktree.`);
14433
14519
  }
14434
14520
  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);
14521
+ const expectedOverlay = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
14436
14522
  if (!configFiles.some((configFile) => sameWorkspacePath(configFile, expectedOverlay))) {
14437
14523
  throw new Error(`Container '${container.id}' was not started with ${DEVCONTAINER_OVERLAY}.`);
14438
14524
  }
@@ -14446,7 +14532,7 @@ function assertWorktreeOwnership(container, repoPath) {
14446
14532
  function isInsideWorktree(candidate, repoPath) {
14447
14533
  const normalizedCandidate = comparableWorkspacePath(candidate);
14448
14534
  const normalizedRoot = comparableWorkspacePath(repoPath);
14449
- return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${import_node_path39.default.sep}`);
14535
+ return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${import_node_path40.default.sep}`);
14450
14536
  }
14451
14537
  function assertReady(container, label) {
14452
14538
  if (!container.state.Running) {
@@ -14638,7 +14724,7 @@ function hasExactManagedComposeProject(repoPath, state) {
14638
14724
  }).some((container) => {
14639
14725
  const workingDir = container.labels["com.docker.compose.project.working_dir"];
14640
14726
  return Boolean(
14641
- workingDir && sameWorkspacePath(workingDir, import_node_path39.default.join(repoPath, ".devcontainer"))
14727
+ workingDir && sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))
14642
14728
  );
14643
14729
  });
14644
14730
  } catch {
@@ -14746,7 +14832,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14746
14832
  target
14747
14833
  });
14748
14834
  if (target.kind === "linked") {
14749
- const workspaceEnv = (0, import_node_child_process28.spawnSync)(
14835
+ const workspaceEnv = (0, import_node_child_process30.spawnSync)(
14750
14836
  "docker",
14751
14837
  ["exec", appContainer.id, "printenv", "WORKSPACE"],
14752
14838
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14756,7 +14842,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14756
14842
  `Workspace app container must expose WORKSPACE='${target.workspace}' (got '${workspaceEnv.stdout.trim() || "(empty)"}').`
14757
14843
  );
14758
14844
  }
14759
- const devrouterWorkspaceEnv = (0, import_node_child_process28.spawnSync)(
14845
+ const devrouterWorkspaceEnv = (0, import_node_child_process30.spawnSync)(
14760
14846
  "docker",
14761
14847
  ["exec", appContainer.id, "printenv", "DEVROUTER_WORKSPACE"],
14762
14848
  { encoding: "utf-8", ...networkDockerOptions() }
@@ -14767,7 +14853,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
14767
14853
  );
14768
14854
  }
14769
14855
  }
14770
- const gitCheck = (0, import_node_child_process28.spawnSync)(
14856
+ const gitCheck = (0, import_node_child_process30.spawnSync)(
14771
14857
  "docker",
14772
14858
  [
14773
14859
  "exec",
@@ -15040,14 +15126,14 @@ function resolvePrimaryTarget(repoPath) {
15040
15126
  }
15041
15127
  function isPrimaryCheckout(repoPath) {
15042
15128
  try {
15043
- return import_node_fs34.default.statSync(import_node_path39.default.join(repoPath, ".git")).isDirectory();
15129
+ return import_node_fs35.default.statSync(import_node_path40.default.join(repoPath, ".git")).isDirectory();
15044
15130
  } catch {
15045
15131
  return false;
15046
15132
  }
15047
15133
  }
15048
15134
  function openUrls(urls) {
15049
15135
  for (const url of urls) {
15050
- const opened = (0, import_node_child_process28.spawnSync)("open", [url], { encoding: "utf-8" });
15136
+ const opened = (0, import_node_child_process30.spawnSync)("open", [url], { encoding: "utf-8" });
15051
15137
  if (opened.status !== 0) {
15052
15138
  process.stderr.write(`Warning: could not open '${url}'.
15053
15139
  `);
@@ -15104,8 +15190,8 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15104
15190
  const target = options.repair ? resolveRepairTarget(repoPath, linked) : linked ? resolveLinkedTarget(repoPath) : resolvePrimaryTarget(repoPath);
15105
15191
  let devpodId = target.devpodId;
15106
15192
  if (target.kind === "linked") {
15107
- const overlayPath = import_node_path39.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
15108
- if (!import_node_fs34.default.existsSync(overlayPath)) {
15193
+ const overlayPath = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
15194
+ if (!import_node_fs35.default.existsSync(overlayPath)) {
15109
15195
  throw new Error(`Missing required DevPod compose overlay: ${overlayPath}`);
15110
15196
  }
15111
15197
  }
@@ -15205,7 +15291,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15205
15291
  }
15206
15292
  const apps = proxyAppsFromConfig(runtime.config);
15207
15293
  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";
15294
+ const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ?? import_node_path40.default.basename(repoPath)) ?? "app";
15209
15295
  for (const [index, app] of apps.entries()) {
15210
15296
  if (!parsedUpstreams[index].host.startsWith(`${aliasPrefix}-`)) {
15211
15297
  const owner = target.kind === "linked" ? "workspace" : "checkout";
@@ -15330,7 +15416,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
15330
15416
  transitionPhase = "service-start";
15331
15417
  reportLifecycleProgress("service-start");
15332
15418
  claimLifecycleEffect();
15333
- const result = (0, import_node_child_process28.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15419
+ const result = (0, import_node_child_process30.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
15334
15420
  ...networkDockerOptions(),
15335
15421
  encoding: "utf-8",
15336
15422
  timeout: DEFAULT_READINESS_TIMEOUT_MS,
@@ -16047,9 +16133,9 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
16047
16133
  }
16048
16134
  const repairLocked = () => {
16049
16135
  const runtime = resolveWorkspaceRuntimeOrDefault(repoPath);
16050
- import_node_fs34.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
16136
+ import_node_fs35.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
16051
16137
  return withFileLock(
16052
- import_node_path39.default.join(DEVROUTER_HOME, `${runtime}-mutation.lock`),
16138
+ import_node_path40.default.join(DEVROUTER_HOME, `${runtime}-mutation.lock`),
16053
16139
  {
16054
16140
  activity: "Managed runtime repair",
16055
16141
  target: repoPath,
@@ -16263,7 +16349,7 @@ async function executeLifecycleWorker(request, operation) {
16263
16349
  const owned = containers.filter(
16264
16350
  (container) => sameWorkspacePath(
16265
16351
  container.labels["com.docker.compose.project.working_dir"] ?? "",
16266
- import_node_path40.default.join(request.repoPath, ".devcontainer")
16352
+ import_node_path41.default.join(request.repoPath, ".devcontainer")
16267
16353
  )
16268
16354
  );
16269
16355
  const projects = owned.map((container) => container.labels["com.docker.compose.project"]);
@@ -16374,7 +16460,7 @@ function proveLifecycleStopped() {
16374
16460
  const remaining = inspectWorkspaceContainers().filter(
16375
16461
  (container) => sameWorkspacePath(
16376
16462
  container.labels["com.docker.compose.project.working_dir"] ?? "",
16377
- import_node_path40.default.join(request.repoPath, ".devcontainer")
16463
+ import_node_path41.default.join(request.repoPath, ".devcontainer")
16378
16464
  )
16379
16465
  );
16380
16466
  if (remaining.some(
@@ -16404,7 +16490,7 @@ function proveLifecycleStopped() {
16404
16490
  return void 0;
16405
16491
  });
16406
16492
  if (settlement) {
16407
- const capacity = createLifecycleCapacityStore(import_node_path40.default.join(DEVROUTER_HOME, "controller"));
16493
+ const capacity = createLifecycleCapacityStore(import_node_path41.default.join(DEVROUTER_HOME, "controller"));
16408
16494
  for (let attempt = 0; ; attempt++) {
16409
16495
  try {
16410
16496
  const state = capacity.inspect();
@@ -16483,7 +16569,7 @@ async function devsyExecOutcome(repoPath, command, retainedProof) {
16483
16569
  const launch = () => {
16484
16570
  if (retainedProof) revalidateDevsyExecProof(repoPath, retainedProof);
16485
16571
  claimLifecycleEffect();
16486
- return (0, import_node_child_process29.spawn)("devsy", args, { stdio: "inherit" });
16572
+ return (0, import_node_child_process31.spawn)("devsy", args, { stdio: "inherit" });
16487
16573
  };
16488
16574
  child = retainedProof ? withMutationLock("Execute retained workspace", repoPath, launch) : launch();
16489
16575
  } catch (error) {
@@ -16531,7 +16617,7 @@ function ensureGuidance2(repoPath) {
16531
16617
  return `Run 'devrouter ensure ${repoPath}' first.`;
16532
16618
  }
16533
16619
  function assertRunningDevpod(devpodId, repoPath) {
16534
- const result = (0, import_node_child_process30.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16620
+ const result = (0, import_node_child_process32.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
16535
16621
  encoding: "utf-8"
16536
16622
  });
16537
16623
  if (result.status !== 0) {
@@ -16710,7 +16796,7 @@ async function devpodExecOutcome(repoPath, command) {
16710
16796
  let child;
16711
16797
  try {
16712
16798
  claimLifecycleEffect();
16713
- child = (0, import_node_child_process30.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16799
+ child = (0, import_node_child_process32.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
16714
16800
  } catch (error) {
16715
16801
  settled = true;
16716
16802
  reject(
@@ -16767,12 +16853,12 @@ async function devpodExecOutcome(repoPath, command) {
16767
16853
  }
16768
16854
 
16769
16855
  // 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"));
16856
+ var import_node_child_process33 = require("child_process");
16857
+ var import_node_fs37 = __toESM(require("fs"));
16858
+ var import_node_path42 = __toESM(require("path"));
16773
16859
 
16774
16860
  // src/core/route-state.ts
16775
- var import_node_fs35 = __toESM(require("fs"));
16861
+ var import_node_fs36 = __toESM(require("fs"));
16776
16862
  function listRoutesForWorktreePath(worktreePath, routes = listHostRouteState()) {
16777
16863
  return routes.filter((route) => sameWorkspacePath(route.repoPath, worktreePath));
16778
16864
  }