@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.
- package/README.md +12 -0
- package/dist/devrouter-lifecycle-worker.js +278 -192
- package/dist/devrouter.js +3380 -893
- package/package.json +2 -1
- package/upgrade-prompts/0.2.0.md +81 -0
- package/upgrade-prompts/0.3.0.md +59 -0
|
@@ -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
|
|
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
|
|
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
|
|
2050
|
-
var
|
|
2051
|
-
var
|
|
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
|
|
2327
|
+
var import_node_fs22 = __toESM(require("fs"));
|
|
2328
2328
|
var import_node_os5 = __toESM(require("os"));
|
|
2329
|
-
var
|
|
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.
|
|
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
|
|
6038
|
-
var
|
|
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
|
|
7356
|
+
return import_node_path23.default.resolve(repoPath ?? process.cwd());
|
|
7296
7357
|
}
|
|
7297
7358
|
function getRepoConfigPath(repoPath) {
|
|
7298
|
-
return
|
|
7359
|
+
return import_node_path23.default.join(resolveRepoPath(repoPath), CONFIG_FILE_NAME);
|
|
7299
7360
|
}
|
|
7300
|
-
function loadRepoConfig(repoPath, read2 = (file) =>
|
|
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 (!
|
|
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.
|
|
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 ??
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
7552
|
+
var import_node_child_process15 = require("child_process");
|
|
7492
7553
|
var import_node_crypto11 = require("crypto");
|
|
7493
|
-
var
|
|
7494
|
-
var
|
|
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 =
|
|
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,
|
|
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,
|
|
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 =
|
|
7529
|
-
if (!
|
|
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 (!
|
|
7691
|
+
if (!import_node_fs20.default.existsSync(CERT_FILE)) {
|
|
7631
7692
|
return [];
|
|
7632
7693
|
}
|
|
7633
7694
|
try {
|
|
7634
|
-
const pem =
|
|
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
|
|
7827
|
-
var
|
|
7828
|
-
var
|
|
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 =
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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 (!
|
|
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 (!
|
|
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 =
|
|
8283
|
-
const featureDirectory =
|
|
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 (!
|
|
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
|
-
|
|
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 =
|
|
8525
|
-
const featureDirectory =
|
|
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
|
|
8665
|
-
var
|
|
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
|
|
8670
|
-
var
|
|
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
|
|
9012
|
-
var
|
|
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 =
|
|
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 =
|
|
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 =
|
|
9281
|
+
fileDescriptor = import_node_fs23.default.openSync(
|
|
9221
9282
|
filePath,
|
|
9222
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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 =
|
|
9743
|
+
descriptor = import_node_fs24.default.openSync(
|
|
9683
9744
|
store.filePath,
|
|
9684
|
-
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
9834
|
-
lockPath:
|
|
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" || !
|
|
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 =
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
9901
|
-
const stat =
|
|
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 =
|
|
9966
|
+
const descriptor = import_node_fs25.default.openSync(
|
|
9906
9967
|
full,
|
|
9907
|
-
|
|
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 (!
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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,
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
10353
|
-
var
|
|
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
|
|
10443
|
+
var import_node_fs28 = __toESM(require("fs"));
|
|
10358
10444
|
var import_node_net2 = __toESM(require("net"));
|
|
10359
|
-
var
|
|
10445
|
+
var import_node_path33 = __toESM(require("path"));
|
|
10360
10446
|
|
|
10361
10447
|
// src/core/controller-protocol.ts
|
|
10362
|
-
var
|
|
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
|
|
11245
|
+
var import_node_child_process19 = require("child_process");
|
|
11160
11246
|
var import_node_crypto17 = require("crypto");
|
|
11161
|
-
var
|
|
11162
|
-
var
|
|
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
|
|
11230
|
-
var
|
|
11231
|
-
var
|
|
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
|
|
11235
|
-
var
|
|
11236
|
-
var
|
|
11237
|
-
var DEVPOD_MUTATION_LOCK_FILE =
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
|
11445
|
-
var
|
|
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,
|
|
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,
|
|
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 (
|
|
11654
|
-
return comparableWorkspacePath(
|
|
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 =
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
11850
|
-
var
|
|
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,
|
|
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
|
|
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
|
|
12013
|
+
var import_node_child_process24 = require("child_process");
|
|
11928
12014
|
var import_node_crypto18 = require("crypto");
|
|
11929
|
-
var
|
|
11930
|
-
var
|
|
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 =
|
|
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,
|
|
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 (!
|
|
11979
|
-
return
|
|
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
|
-
|
|
11990
|
-
|
|
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) =>
|
|
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 =
|
|
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 =
|
|
12003
|
-
const devcontainerPath =
|
|
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 =
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
12914
|
-
var
|
|
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 =
|
|
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 =
|
|
12926
|
-
const pids =
|
|
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 =
|
|
12932
|
-
if (
|
|
12933
|
-
if (
|
|
12934
|
-
const descriptors =
|
|
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
|
|
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,
|
|
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
|
|
13913
|
+
var import_node_child_process28 = require("child_process");
|
|
13828
13914
|
var import_node_crypto20 = require("crypto");
|
|
13829
|
-
var
|
|
13830
|
-
var
|
|
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 =
|
|
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(
|
|
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,
|
|
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 =
|
|
13899
|
-
const ignored = (0,
|
|
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 (!
|
|
13914
|
-
const stat =
|
|
13915
|
-
if (!stat.isFile() || stat.size > MAX_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
|
|
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,
|
|
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,
|
|
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,
|
|
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 =
|
|
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}${
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
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,
|
|
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 =
|
|
15108
|
-
if (!
|
|
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 ??
|
|
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,
|
|
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
|
-
|
|
16136
|
+
import_node_fs35.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
16051
16137
|
return withFileLock(
|
|
16052
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
16771
|
-
var
|
|
16772
|
-
var
|
|
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
|
|
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
|
}
|