@devrouter/cli 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/devrouter-lifecycle-worker.js +252 -191
- package/dist/devrouter.js +2527 -772
- package/package.json +2 -1
- package/upgrade-prompts/0.2.0.md +81 -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.2.0" : "0.0.0-dev";
|
|
5377
5377
|
}
|
|
5378
5378
|
function compareCliVersions(left, right) {
|
|
5379
5379
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -6034,8 +6034,8 @@ function clearStartupWitness(identity2, fence) {
|
|
|
6034
6034
|
|
|
6035
6035
|
// src/core/repo-config.ts
|
|
6036
6036
|
var import_node_crypto10 = require("crypto");
|
|
6037
|
-
var
|
|
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.2.0" : "0.0.0-dev";
|
|
7314
7375
|
if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
|
|
7315
7376
|
hasWarnedVersionMismatch = true;
|
|
7316
7377
|
process.stderr.write(
|
|
@@ -7330,7 +7391,7 @@ function namespaceHost(host, workspace) {
|
|
|
7330
7391
|
return `${base}.${workspace}${suffix}`;
|
|
7331
7392
|
}
|
|
7332
7393
|
function applyWorkspace(config, workspace, repoPath) {
|
|
7333
|
-
const defaultToken = wsFromBranch(config.project?.name ??
|
|
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
|
});
|
|
@@ -10345,21 +10406,21 @@ var ExecutionOutcomeError = class extends Error {
|
|
|
10345
10406
|
|
|
10346
10407
|
// src/core/reliability-lifecycle.ts
|
|
10347
10408
|
var import_node_crypto22 = require("crypto");
|
|
10348
|
-
var
|
|
10409
|
+
var import_node_path41 = __toESM(require("path"));
|
|
10349
10410
|
var import_node_util7 = require("util");
|
|
10350
10411
|
|
|
10351
10412
|
// src/core/capacity-policy.ts
|
|
10352
|
-
var
|
|
10353
|
-
var
|
|
10413
|
+
var import_node_fs27 = __toESM(require("fs"));
|
|
10414
|
+
var import_node_path31 = __toESM(require("path"));
|
|
10354
10415
|
|
|
10355
10416
|
// src/core/controller-client.ts
|
|
10356
10417
|
var import_node_crypto15 = require("crypto");
|
|
10357
|
-
var
|
|
10418
|
+
var import_node_fs28 = __toESM(require("fs"));
|
|
10358
10419
|
var import_node_net2 = __toESM(require("net"));
|
|
10359
|
-
var
|
|
10420
|
+
var import_node_path33 = __toESM(require("path"));
|
|
10360
10421
|
|
|
10361
10422
|
// src/core/controller-protocol.ts
|
|
10362
|
-
var
|
|
10423
|
+
var import_node_path32 = __toESM(require("path"));
|
|
10363
10424
|
var CONTROLLER_FRAME_BYTES = 64 * 1024;
|
|
10364
10425
|
var CONTROLLER_MAX_OPERATION_REQUEST_BYTES = 32 * 1024;
|
|
10365
10426
|
var CONTROLLER_PROFILE_TOKEN_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -11156,10 +11217,10 @@ function stepReliability(state, event, nowMs) {
|
|
|
11156
11217
|
}
|
|
11157
11218
|
|
|
11158
11219
|
// src/core/reliability-worker.ts
|
|
11159
|
-
var
|
|
11220
|
+
var import_node_child_process19 = require("child_process");
|
|
11160
11221
|
var import_node_crypto17 = require("crypto");
|
|
11161
|
-
var
|
|
11162
|
-
var
|
|
11222
|
+
var import_node_fs29 = __toESM(require("fs"));
|
|
11223
|
+
var import_node_path34 = __toESM(require("path"));
|
|
11163
11224
|
|
|
11164
11225
|
// src/core/lifecycle-progress.ts
|
|
11165
11226
|
var ROLES = {
|
|
@@ -11226,20 +11287,20 @@ function workerGroupAbsent(pid) {
|
|
|
11226
11287
|
}
|
|
11227
11288
|
|
|
11228
11289
|
// src/core/workspace-ensure.ts
|
|
11229
|
-
var
|
|
11230
|
-
var
|
|
11231
|
-
var
|
|
11290
|
+
var import_node_child_process30 = require("child_process");
|
|
11291
|
+
var import_node_fs35 = __toESM(require("fs"));
|
|
11292
|
+
var import_node_path40 = __toESM(require("path"));
|
|
11232
11293
|
|
|
11233
11294
|
// src/core/devpod-mutation.ts
|
|
11234
|
-
var
|
|
11235
|
-
var
|
|
11236
|
-
var
|
|
11237
|
-
var DEVPOD_MUTATION_LOCK_FILE =
|
|
11295
|
+
var import_node_child_process20 = require("child_process");
|
|
11296
|
+
var import_node_fs30 = __toESM(require("fs"));
|
|
11297
|
+
var import_node_path35 = __toESM(require("path"));
|
|
11298
|
+
var DEVPOD_MUTATION_LOCK_FILE = import_node_path35.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
|
|
11238
11299
|
var DEVPOD_MUTATION_WAIT_MS = 18e5;
|
|
11239
11300
|
var DevpodStartPostconditionError = class extends Error {
|
|
11240
11301
|
};
|
|
11241
11302
|
function withMutationLock2(activity, target, operation) {
|
|
11242
|
-
|
|
11303
|
+
import_node_fs30.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
11243
11304
|
return withFileLockSync(
|
|
11244
11305
|
DEVPOD_MUTATION_LOCK_FILE,
|
|
11245
11306
|
{
|
|
@@ -11259,7 +11320,7 @@ function runDevpodAction(action, devpodId, force = false, repoPath) {
|
|
|
11259
11320
|
const args = action === "delete" ? [action, devpodId, ...force ? ["--force"] : [], "--ignore-not-found"] : [action, devpodId];
|
|
11260
11321
|
claimLifecycleEffect();
|
|
11261
11322
|
const binding = repoPath ? networkProviderEffectOptions("devpod", devpodId, repoPath) : { args: [] };
|
|
11262
|
-
const result = (0,
|
|
11323
|
+
const result = (0, import_node_child_process20.spawnSync)("devpod", [...args, ...binding.args], {
|
|
11263
11324
|
encoding: "utf-8",
|
|
11264
11325
|
...binding.env ? { env: binding.env } : {}
|
|
11265
11326
|
});
|
|
@@ -11401,7 +11462,7 @@ async function startDevpodWorkspace(options) {
|
|
|
11401
11462
|
}
|
|
11402
11463
|
claimLifecycleEffect();
|
|
11403
11464
|
network?.beforeDispatch?.();
|
|
11404
|
-
const result = (0,
|
|
11465
|
+
const result = (0, import_node_child_process20.spawnSync)("devpod", args, {
|
|
11405
11466
|
stdio: options.quiet ? ["inherit", 2, "inherit"] : "inherit",
|
|
11406
11467
|
env
|
|
11407
11468
|
});
|
|
@@ -11441,8 +11502,8 @@ async function startDevpodWorkspace(options) {
|
|
|
11441
11502
|
}
|
|
11442
11503
|
|
|
11443
11504
|
// src/core/host-port-claims.ts
|
|
11444
|
-
var
|
|
11445
|
-
var
|
|
11505
|
+
var import_node_child_process21 = require("child_process");
|
|
11506
|
+
var import_node_path36 = __toESM(require("path"));
|
|
11446
11507
|
var COMPOSE_RENDER_TIMEOUT_MS = 3e4;
|
|
11447
11508
|
var COMPOSE_RENDER_MAX_BUFFER = 8 * 1024 * 1024;
|
|
11448
11509
|
var DOCKER_TIMEOUT_MS = 1e4;
|
|
@@ -11545,7 +11606,7 @@ function hostPortBindingsConflict(desired, holder) {
|
|
|
11545
11606
|
}
|
|
11546
11607
|
var HOST_PORT_INSPECT_TEMPLATE = '{"id":{{json .Id}},"name":{{json .Name}},"labels":{"com.docker.compose.project":{{json (index .Config.Labels "com.docker.compose.project")}},"com.docker.compose.project.working_dir":{{json (index .Config.Labels "com.docker.compose.project.working_dir")}}},"ports":{{json .NetworkSettings.Ports}}}';
|
|
11547
11608
|
function runDocker(args) {
|
|
11548
|
-
const result = (0,
|
|
11609
|
+
const result = (0, import_node_child_process21.spawnSync)("docker", args, {
|
|
11549
11610
|
...networkDockerOptions(),
|
|
11550
11611
|
encoding: "utf-8",
|
|
11551
11612
|
timeout: DOCKER_TIMEOUT_MS,
|
|
@@ -11615,7 +11676,7 @@ function listHolderSnapshots() {
|
|
|
11615
11676
|
}
|
|
11616
11677
|
function renderManagedComposeModel(plan, workspace) {
|
|
11617
11678
|
const fileArgs = plan.composeFiles.flatMap((file) => ["-f", file]);
|
|
11618
|
-
const result = (0,
|
|
11679
|
+
const result = (0, import_node_child_process21.spawnSync)(
|
|
11619
11680
|
"docker",
|
|
11620
11681
|
[
|
|
11621
11682
|
"compose",
|
|
@@ -11650,8 +11711,8 @@ function renderManagedComposeModel(plan, workspace) {
|
|
|
11650
11711
|
}
|
|
11651
11712
|
}
|
|
11652
11713
|
function attributeHolderWorktree(workingDir) {
|
|
11653
|
-
if (
|
|
11654
|
-
return comparableWorkspacePath(
|
|
11714
|
+
if (import_node_path36.default.basename(workingDir) !== ".devcontainer") return void 0;
|
|
11715
|
+
return comparableWorkspacePath(import_node_path36.default.dirname(workingDir));
|
|
11655
11716
|
}
|
|
11656
11717
|
function holderAttribution(holder, repoPath) {
|
|
11657
11718
|
const attribution = {};
|
|
@@ -11686,7 +11747,7 @@ function detectHostPortClaimConflicts(options) {
|
|
|
11686
11747
|
);
|
|
11687
11748
|
if (desired.length === 0) return [];
|
|
11688
11749
|
const holders = listHolderSnapshots();
|
|
11689
|
-
const devcontainerDir =
|
|
11750
|
+
const devcontainerDir = import_node_path36.default.join(options.repoPath, ".devcontainer");
|
|
11690
11751
|
const conflicts = [];
|
|
11691
11752
|
for (const binding of desired) {
|
|
11692
11753
|
for (const holder of holders) {
|
|
@@ -11710,7 +11771,7 @@ function detectHostPortClaimConflicts(options) {
|
|
|
11710
11771
|
}
|
|
11711
11772
|
|
|
11712
11773
|
// src/core/http-route-probe.ts
|
|
11713
|
-
var
|
|
11774
|
+
var import_node_child_process22 = require("child_process");
|
|
11714
11775
|
var DEFAULT_MAX_TIME_SECONDS = 5;
|
|
11715
11776
|
var PARENT_TIMEOUT_PADDING_MS = 250;
|
|
11716
11777
|
var CONTRACT_MAX_BUFFER = 1024;
|
|
@@ -11743,7 +11804,7 @@ function probeHttpRoute(host, options = {}) {
|
|
|
11743
11804
|
args.push("--cacert", CERT_FILE);
|
|
11744
11805
|
}
|
|
11745
11806
|
args.push(url);
|
|
11746
|
-
const result = (0,
|
|
11807
|
+
const result = (0, import_node_child_process22.spawnSync)("curl", args, { encoding: "utf-8" });
|
|
11747
11808
|
const stdout = result.stdout?.trim() ?? "";
|
|
11748
11809
|
const status = /^\d{3}$/.test(stdout) ? Number(stdout) : void 0;
|
|
11749
11810
|
const ok = result.status === 0 && status !== void 0 && status >= 100 && status < 500;
|
|
@@ -11762,7 +11823,7 @@ function probeHttpReadinessSync(host, readiness, maxTimeSeconds, repoPath) {
|
|
|
11762
11823
|
}
|
|
11763
11824
|
let result;
|
|
11764
11825
|
try {
|
|
11765
|
-
result = (0,
|
|
11826
|
+
result = (0, import_node_child_process22.spawnSync)("curl", args, {
|
|
11766
11827
|
encoding: "utf-8",
|
|
11767
11828
|
maxBuffer: CONTRACT_MAX_BUFFER,
|
|
11768
11829
|
timeout: Math.ceil(parentTimeoutMs)
|
|
@@ -11846,8 +11907,8 @@ function transportFailure() {
|
|
|
11846
11907
|
}
|
|
11847
11908
|
|
|
11848
11909
|
// src/core/managed-host-preparation.ts
|
|
11849
|
-
var
|
|
11850
|
-
var
|
|
11910
|
+
var import_node_child_process23 = require("child_process");
|
|
11911
|
+
var import_node_fs31 = __toESM(require("fs"));
|
|
11851
11912
|
var PREPARATION_TIMEOUT_MS = 6e4;
|
|
11852
11913
|
var CONFIG_READ_ERROR = "Managed host preparation could not read .devrouter.yml.";
|
|
11853
11914
|
var CONFIG_CHANGED_ERROR = "Managed host preparation changed .devrouter.yml; refusing to continue.";
|
|
@@ -11858,7 +11919,7 @@ function runPreparationCommand(argv, cwd) {
|
|
|
11858
11919
|
return new Promise((resolve) => {
|
|
11859
11920
|
let child;
|
|
11860
11921
|
try {
|
|
11861
|
-
child = (0,
|
|
11922
|
+
child = (0, import_node_child_process23.spawn)(argv[0], argv.slice(1), {
|
|
11862
11923
|
cwd,
|
|
11863
11924
|
detached: true,
|
|
11864
11925
|
shell: false,
|
|
@@ -11890,7 +11951,7 @@ function runPreparationCommand(argv, cwd) {
|
|
|
11890
11951
|
}
|
|
11891
11952
|
function readConfigBytes(configPath) {
|
|
11892
11953
|
try {
|
|
11893
|
-
return
|
|
11954
|
+
return import_node_fs31.default.readFileSync(configPath);
|
|
11894
11955
|
} catch {
|
|
11895
11956
|
return void 0;
|
|
11896
11957
|
}
|
|
@@ -11924,10 +11985,10 @@ async function runManagedHostPreparation(repoPath, config) {
|
|
|
11924
11985
|
}
|
|
11925
11986
|
|
|
11926
11987
|
// src/core/managed-post-start.ts
|
|
11927
|
-
var
|
|
11988
|
+
var import_node_child_process24 = require("child_process");
|
|
11928
11989
|
var import_node_crypto18 = require("crypto");
|
|
11929
|
-
var
|
|
11930
|
-
var
|
|
11990
|
+
var import_node_fs32 = __toESM(require("fs"));
|
|
11991
|
+
var import_node_path37 = __toESM(require("path"));
|
|
11931
11992
|
var MANAGED_MARKER = "devrouter:managed devcontainer";
|
|
11932
11993
|
var MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
|
|
11933
11994
|
var RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
|
|
@@ -11940,7 +12001,7 @@ function renderDeliveryScript(targetPath) {
|
|
|
11940
12001
|
if (!/^\/tmp\/devrouter\/bin\/[a-zA-Z0-9._-]+$/.test(targetPath)) {
|
|
11941
12002
|
throw new Error(`Unsafe managed runtime delivery path: ${targetPath}`);
|
|
11942
12003
|
}
|
|
11943
|
-
const temporaryPrefix =
|
|
12004
|
+
const temporaryPrefix = import_node_path37.default.posix.basename(targetPath);
|
|
11944
12005
|
return `set -eu
|
|
11945
12006
|
umask 077
|
|
11946
12007
|
runtime_root=/tmp/devrouter
|
|
@@ -11964,7 +12025,7 @@ function commandFailure3(result) {
|
|
|
11964
12025
|
return [result.error?.message, result.stderr, result.stdout].filter(Boolean).map((value) => String(value).trim()).filter(Boolean).join("\n");
|
|
11965
12026
|
}
|
|
11966
12027
|
function deliverRuntimeFile(containerId, targetPath, contents, label) {
|
|
11967
|
-
const result = (0,
|
|
12028
|
+
const result = (0, import_node_child_process24.spawnSync)(
|
|
11968
12029
|
"docker",
|
|
11969
12030
|
["exec", "-i", containerId, "sh", "-c", renderDeliveryScript(targetPath)],
|
|
11970
12031
|
{ input: contents, encoding: "utf-8", ...networkDockerOptions() }
|
|
@@ -11975,8 +12036,8 @@ function deliverRuntimeFile(containerId, targetPath, contents, label) {
|
|
|
11975
12036
|
}
|
|
11976
12037
|
}
|
|
11977
12038
|
function readRegularFileBytes(filePath) {
|
|
11978
|
-
if (!
|
|
11979
|
-
return
|
|
12039
|
+
if (!import_node_fs32.default.existsSync(filePath) || !import_node_fs32.default.lstatSync(filePath).isFile()) return void 0;
|
|
12040
|
+
return import_node_fs32.default.readFileSync(filePath);
|
|
11980
12041
|
}
|
|
11981
12042
|
function readRegularFile(filePath) {
|
|
11982
12043
|
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
@@ -11986,21 +12047,21 @@ function adapterFingerprint(adapter) {
|
|
|
11986
12047
|
}
|
|
11987
12048
|
function resolveProcessHelperPath() {
|
|
11988
12049
|
const candidates = [
|
|
11989
|
-
|
|
11990
|
-
|
|
12050
|
+
import_node_path37.default.resolve(__dirname, "..", "bin", "devrouter-process"),
|
|
12051
|
+
import_node_path37.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
|
|
11991
12052
|
];
|
|
11992
|
-
const helperPath = candidates.find((candidate) =>
|
|
12053
|
+
const helperPath = candidates.find((candidate) => import_node_fs32.default.existsSync(candidate));
|
|
11993
12054
|
if (!helperPath) {
|
|
11994
12055
|
throw new Error("Could not locate the packaged devrouter-process helper.");
|
|
11995
12056
|
}
|
|
11996
12057
|
return helperPath;
|
|
11997
12058
|
}
|
|
11998
12059
|
function resolveManagedPostStartPlan(repoPath) {
|
|
11999
|
-
const adapterPath =
|
|
12060
|
+
const adapterPath = import_node_path37.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
12000
12061
|
const adapterBytes = readRegularFileBytes(adapterPath);
|
|
12001
12062
|
const adapterText = adapterBytes?.toString("utf-8");
|
|
12002
|
-
const dockerfilePath =
|
|
12003
|
-
const devcontainerPath =
|
|
12063
|
+
const dockerfilePath = import_node_path37.default.join(repoPath, ".devcontainer", "Dockerfile");
|
|
12064
|
+
const devcontainerPath = import_node_path37.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
12004
12065
|
const dockerfile = readRegularFile(dockerfilePath) ?? "";
|
|
12005
12066
|
const devcontainer = readRegularFile(devcontainerPath) ?? "";
|
|
12006
12067
|
const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
|
|
@@ -12041,7 +12102,7 @@ function resolveManagedPostStartPlan(repoPath) {
|
|
|
12041
12102
|
}
|
|
12042
12103
|
function runManagedPostStart(options) {
|
|
12043
12104
|
if (options.plan.kind !== "runtime") return;
|
|
12044
|
-
const helper =
|
|
12105
|
+
const helper = import_node_fs32.default.readFileSync(resolveProcessHelperPath());
|
|
12045
12106
|
deliverRuntimeFile(
|
|
12046
12107
|
options.container.id,
|
|
12047
12108
|
RUNTIME_HELPER_PATH,
|
|
@@ -12055,7 +12116,7 @@ function runManagedPostStart(options) {
|
|
|
12055
12116
|
options.plan.adapterContents,
|
|
12056
12117
|
"the managed post-start adapter"
|
|
12057
12118
|
);
|
|
12058
|
-
const started2 = (0,
|
|
12119
|
+
const started2 = (0, import_node_child_process24.spawnSync)(
|
|
12059
12120
|
"docker",
|
|
12060
12121
|
[
|
|
12061
12122
|
"exec",
|
|
@@ -12096,7 +12157,7 @@ function assertSafeProcessName(name) {
|
|
|
12096
12157
|
}
|
|
12097
12158
|
function runManagedProcessAction(options) {
|
|
12098
12159
|
assertSafeProcessName(options.name);
|
|
12099
|
-
const result = (0,
|
|
12160
|
+
const result = (0, import_node_child_process24.spawnSync)(
|
|
12100
12161
|
"docker",
|
|
12101
12162
|
[
|
|
12102
12163
|
"exec",
|
|
@@ -12135,7 +12196,7 @@ function runManagedProcessAction(options) {
|
|
|
12135
12196
|
}
|
|
12136
12197
|
|
|
12137
12198
|
// src/core/managed-mount-nesting.ts
|
|
12138
|
-
var
|
|
12199
|
+
var import_node_child_process25 = require("child_process");
|
|
12139
12200
|
var NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
|
|
12140
12201
|
var UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
|
|
12141
12202
|
function normalizeDestination(value) {
|
|
@@ -12208,7 +12269,7 @@ function classifyManagedMountNesting(configured, effectiveDestinations, containe
|
|
|
12208
12269
|
};
|
|
12209
12270
|
}
|
|
12210
12271
|
function readContainerMountinfo(containerId, options) {
|
|
12211
|
-
const result = (0,
|
|
12272
|
+
const result = (0, import_node_child_process25.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
|
|
12212
12273
|
encoding: "utf-8",
|
|
12213
12274
|
timeout: options.timeoutMs ?? 5e3,
|
|
12214
12275
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -12730,7 +12791,7 @@ function collectManagedRuntimeStatus(options) {
|
|
|
12730
12791
|
}
|
|
12731
12792
|
|
|
12732
12793
|
// src/core/network-inventory.ts
|
|
12733
|
-
var
|
|
12794
|
+
var import_node_child_process26 = require("child_process");
|
|
12734
12795
|
var NetworkInventoryError = class extends Error {
|
|
12735
12796
|
};
|
|
12736
12797
|
var MAX_IDS = 4096;
|
|
@@ -12742,7 +12803,7 @@ function readDocker(endpoint, args, timeoutMs) {
|
|
|
12742
12803
|
const env = { ...process.env };
|
|
12743
12804
|
delete env.DOCKER_CONTEXT;
|
|
12744
12805
|
delete env.DOCKER_HOST;
|
|
12745
|
-
const result = (0,
|
|
12806
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", ["--host", endpoint, ...args], {
|
|
12746
12807
|
env,
|
|
12747
12808
|
encoding: "utf-8",
|
|
12748
12809
|
timeout: timeoutMs,
|
|
@@ -12906,37 +12967,37 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
|
|
|
12906
12967
|
}
|
|
12907
12968
|
|
|
12908
12969
|
// src/core/network-routes.ts
|
|
12909
|
-
var
|
|
12970
|
+
var import_node_child_process27 = require("child_process");
|
|
12910
12971
|
var import_node_net3 = require("net");
|
|
12911
12972
|
|
|
12912
12973
|
// src/core/network-local-daemon.ts
|
|
12913
|
-
var
|
|
12914
|
-
var
|
|
12974
|
+
var import_node_fs33 = __toESM(require("fs"));
|
|
12975
|
+
var import_node_path38 = __toESM(require("path"));
|
|
12915
12976
|
function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
12916
12977
|
const deadline = Date.now() + 2e3;
|
|
12917
12978
|
try {
|
|
12918
12979
|
if (!endpoint.startsWith("unix:///")) return false;
|
|
12919
12980
|
const socket = endpoint.slice("unix://".length);
|
|
12920
|
-
const table =
|
|
12981
|
+
const table = import_node_fs33.default.readFileSync(import_node_path38.default.join(procRoot, "net/unix"), "utf8");
|
|
12921
12982
|
if (Buffer.byteLength(table) > 1024 * 1024) return false;
|
|
12922
12983
|
const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
|
|
12923
12984
|
if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
|
|
12924
12985
|
const inode = `socket:[${rows2[0][6]}]`;
|
|
12925
|
-
const ownNamespace =
|
|
12926
|
-
const pids =
|
|
12986
|
+
const ownNamespace = import_node_fs33.default.readlinkSync(import_node_path38.default.join(procRoot, "self/ns/net"));
|
|
12987
|
+
const pids = import_node_fs33.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
|
|
12927
12988
|
if (pids.length > 4096) return false;
|
|
12928
12989
|
for (const pid of pids) {
|
|
12929
12990
|
if (Date.now() > deadline) return false;
|
|
12930
12991
|
try {
|
|
12931
|
-
const root =
|
|
12932
|
-
if (
|
|
12933
|
-
if (
|
|
12934
|
-
const descriptors =
|
|
12992
|
+
const root = import_node_path38.default.join(procRoot, pid);
|
|
12993
|
+
if (import_node_path38.default.basename(import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "exe"))) !== "dockerd") continue;
|
|
12994
|
+
if (import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "ns/net")) !== ownNamespace) continue;
|
|
12995
|
+
const descriptors = import_node_fs33.default.readdirSync(import_node_path38.default.join(root, "fd"));
|
|
12935
12996
|
if (descriptors.length > 4096) continue;
|
|
12936
12997
|
if (descriptors.some((fd) => {
|
|
12937
12998
|
if (Date.now() > deadline) return false;
|
|
12938
12999
|
try {
|
|
12939
|
-
return
|
|
13000
|
+
return import_node_fs33.default.readlinkSync(import_node_path38.default.join(root, "fd", fd)) === inode;
|
|
12940
13001
|
} catch {
|
|
12941
13002
|
return false;
|
|
12942
13003
|
}
|
|
@@ -12975,7 +13036,7 @@ function parseLinuxNetworkRoutes(output) {
|
|
|
12975
13036
|
function collectNetworkRoutes(options) {
|
|
12976
13037
|
if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
|
|
12977
13038
|
return { status: "unknown", routes: [] };
|
|
12978
|
-
const result = (0,
|
|
13039
|
+
const result = (0, import_node_child_process27.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
|
|
12979
13040
|
encoding: "utf8",
|
|
12980
13041
|
timeout: 5e3,
|
|
12981
13042
|
maxBuffer: 1024 * 1024
|
|
@@ -13824,10 +13885,10 @@ function fingerprintComposeNetworkModel(input) {
|
|
|
13824
13885
|
}
|
|
13825
13886
|
|
|
13826
13887
|
// src/core/network-compose-files.ts
|
|
13827
|
-
var
|
|
13888
|
+
var import_node_child_process28 = require("child_process");
|
|
13828
13889
|
var import_node_crypto20 = require("crypto");
|
|
13829
|
-
var
|
|
13830
|
-
var
|
|
13890
|
+
var import_node_fs34 = __toESM(require("fs"));
|
|
13891
|
+
var import_node_path39 = __toESM(require("path"));
|
|
13831
13892
|
var import_yaml4 = __toESM(require("yaml"));
|
|
13832
13893
|
var OVERLAY = "docker-compose.devrouter-network.yml";
|
|
13833
13894
|
var MARKER = "# devrouter:managed workspace network";
|
|
@@ -13840,12 +13901,12 @@ function object3(value) {
|
|
|
13840
13901
|
function inspectNetworkComposeFiles(input) {
|
|
13841
13902
|
const authoredNetworks = {};
|
|
13842
13903
|
for (const file of input.plan.composeFiles) {
|
|
13843
|
-
const stat =
|
|
13904
|
+
const stat = import_node_fs34.default.lstatSync(file);
|
|
13844
13905
|
if (!stat.isFile() || stat.size > MAX_BYTES2)
|
|
13845
13906
|
throw new Error("Network Compose source is unavailable or too large.");
|
|
13846
13907
|
let source;
|
|
13847
13908
|
try {
|
|
13848
|
-
source = object3(import_yaml4.default.parse(
|
|
13909
|
+
source = object3(import_yaml4.default.parse(import_node_fs34.default.readFileSync(file, "utf8")));
|
|
13849
13910
|
} catch {
|
|
13850
13911
|
throw new Error("Network Compose source could not be parsed safely.");
|
|
13851
13912
|
}
|
|
@@ -13861,7 +13922,7 @@ function inspectNetworkComposeFiles(input) {
|
|
|
13861
13922
|
const env = managedComposeEnvironment(input.workspace);
|
|
13862
13923
|
delete env.DOCKER_CONTEXT;
|
|
13863
13924
|
delete env.DOCKER_HOST;
|
|
13864
|
-
const result = (0,
|
|
13925
|
+
const result = (0, import_node_child_process28.spawnSync)(
|
|
13865
13926
|
"docker",
|
|
13866
13927
|
[
|
|
13867
13928
|
"--host",
|
|
@@ -13895,8 +13956,8 @@ function inspectNetworkComposeFiles(input) {
|
|
|
13895
13956
|
function prepareNetworkComposeFiles(plan, subnet) {
|
|
13896
13957
|
const overlay = deriveComposeNetworkOverlay(subnet);
|
|
13897
13958
|
if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
|
|
13898
|
-
const overlayPath =
|
|
13899
|
-
const ignored = (0,
|
|
13959
|
+
const overlayPath = import_node_path39.default.join(plan.composeDirectory, OVERLAY);
|
|
13960
|
+
const ignored = (0, import_node_child_process28.spawnSync)("git", [
|
|
13900
13961
|
"-C",
|
|
13901
13962
|
plan.composeDirectory,
|
|
13902
13963
|
"check-ignore",
|
|
@@ -13910,9 +13971,9 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
13910
13971
|
const bytes2 = `${MARKER}
|
|
13911
13972
|
${import_yaml4.default.stringify(overlay.overlay)}`;
|
|
13912
13973
|
const assertOwnership = () => {
|
|
13913
|
-
if (!
|
|
13914
|
-
const stat =
|
|
13915
|
-
if (!stat.isFile() || stat.size > MAX_BYTES2 ||
|
|
13974
|
+
if (!import_node_fs34.default.existsSync(overlayPath)) return;
|
|
13975
|
+
const stat = import_node_fs34.default.lstatSync(overlayPath);
|
|
13976
|
+
if (!stat.isFile() || stat.size > MAX_BYTES2 || import_node_fs34.default.readFileSync(overlayPath, "utf8") !== bytes2)
|
|
13916
13977
|
throw new Error("Retained network overlay changed; repair is required.");
|
|
13917
13978
|
};
|
|
13918
13979
|
assertOwnership();
|
|
@@ -13938,7 +13999,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
13938
13999
|
}
|
|
13939
14000
|
|
|
13940
14001
|
// src/core/network-connected-route.ts
|
|
13941
|
-
var
|
|
14002
|
+
var import_node_child_process29 = require("child_process");
|
|
13942
14003
|
function bounds(cidr) {
|
|
13943
14004
|
const canonical = parseIPv4Cidr(cidr);
|
|
13944
14005
|
if (!canonical) throw new Error("Invalid connected route.");
|
|
@@ -13963,7 +14024,7 @@ function inspectClaimedBridge(claim2, networkId) {
|
|
|
13963
14024
|
const env = { ...process.env };
|
|
13964
14025
|
delete env.DOCKER_CONTEXT;
|
|
13965
14026
|
delete env.DOCKER_HOST;
|
|
13966
|
-
const result = (0,
|
|
14027
|
+
const result = (0, import_node_child_process29.spawnSync)(
|
|
13967
14028
|
"docker",
|
|
13968
14029
|
[
|
|
13969
14030
|
"--host",
|
|
@@ -13990,7 +14051,7 @@ function inspectClaimedBridge(claim2, networkId) {
|
|
|
13990
14051
|
const [first, last] = bounds(claim2.subnet);
|
|
13991
14052
|
const [address] = bounds(gateway);
|
|
13992
14053
|
if (address <= first || address >= last) throw new Error();
|
|
13993
|
-
const interfaces = (0,
|
|
14054
|
+
const interfaces = (0, import_node_child_process29.spawnSync)("ip", ["-j", "-d", "-4", "address", "show", "dev", bridge], {
|
|
13994
14055
|
encoding: "utf8",
|
|
13995
14056
|
timeout: 5e3,
|
|
13996
14057
|
maxBuffer: 65536
|
|
@@ -14428,11 +14489,11 @@ var DEFAULT_READINESS_TIMEOUT_MS = 12e4;
|
|
|
14428
14489
|
var POLL_INTERVAL_MS = 1e3;
|
|
14429
14490
|
function assertOverlay(container, repoPath) {
|
|
14430
14491
|
const workingDir = container.labels["com.docker.compose.project.working_dir"];
|
|
14431
|
-
if (!workingDir || !sameWorkspacePath(workingDir,
|
|
14492
|
+
if (!workingDir || !sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))) {
|
|
14432
14493
|
throw new Error(`Container '${container.id}' does not belong to the exact worktree.`);
|
|
14433
14494
|
}
|
|
14434
14495
|
const configFiles = (container.labels["com.docker.compose.project.config_files"] ?? "").split(",").filter(Boolean);
|
|
14435
|
-
const expectedOverlay =
|
|
14496
|
+
const expectedOverlay = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
|
|
14436
14497
|
if (!configFiles.some((configFile) => sameWorkspacePath(configFile, expectedOverlay))) {
|
|
14437
14498
|
throw new Error(`Container '${container.id}' was not started with ${DEVCONTAINER_OVERLAY}.`);
|
|
14438
14499
|
}
|
|
@@ -14446,7 +14507,7 @@ function assertWorktreeOwnership(container, repoPath) {
|
|
|
14446
14507
|
function isInsideWorktree(candidate, repoPath) {
|
|
14447
14508
|
const normalizedCandidate = comparableWorkspacePath(candidate);
|
|
14448
14509
|
const normalizedRoot = comparableWorkspacePath(repoPath);
|
|
14449
|
-
return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${
|
|
14510
|
+
return normalizedCandidate === normalizedRoot || normalizedCandidate.startsWith(`${normalizedRoot}${import_node_path40.default.sep}`);
|
|
14450
14511
|
}
|
|
14451
14512
|
function assertReady(container, label) {
|
|
14452
14513
|
if (!container.state.Running) {
|
|
@@ -14638,7 +14699,7 @@ function hasExactManagedComposeProject(repoPath, state) {
|
|
|
14638
14699
|
}).some((container) => {
|
|
14639
14700
|
const workingDir = container.labels["com.docker.compose.project.working_dir"];
|
|
14640
14701
|
return Boolean(
|
|
14641
|
-
workingDir && sameWorkspacePath(workingDir,
|
|
14702
|
+
workingDir && sameWorkspacePath(workingDir, import_node_path40.default.join(repoPath, ".devcontainer"))
|
|
14642
14703
|
);
|
|
14643
14704
|
});
|
|
14644
14705
|
} catch {
|
|
@@ -14746,7 +14807,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
|
|
|
14746
14807
|
target
|
|
14747
14808
|
});
|
|
14748
14809
|
if (target.kind === "linked") {
|
|
14749
|
-
const workspaceEnv = (0,
|
|
14810
|
+
const workspaceEnv = (0, import_node_child_process30.spawnSync)(
|
|
14750
14811
|
"docker",
|
|
14751
14812
|
["exec", appContainer.id, "printenv", "WORKSPACE"],
|
|
14752
14813
|
{ encoding: "utf-8", ...networkDockerOptions() }
|
|
@@ -14756,7 +14817,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
|
|
|
14756
14817
|
`Workspace app container must expose WORKSPACE='${target.workspace}' (got '${workspaceEnv.stdout.trim() || "(empty)"}').`
|
|
14757
14818
|
);
|
|
14758
14819
|
}
|
|
14759
|
-
const devrouterWorkspaceEnv = (0,
|
|
14820
|
+
const devrouterWorkspaceEnv = (0, import_node_child_process30.spawnSync)(
|
|
14760
14821
|
"docker",
|
|
14761
14822
|
["exec", appContainer.id, "printenv", "DEVROUTER_WORKSPACE"],
|
|
14762
14823
|
{ encoding: "utf-8", ...networkDockerOptions() }
|
|
@@ -14767,7 +14828,7 @@ async function waitForContainerPreflight(repoPath, target, upstreamHosts, timeou
|
|
|
14767
14828
|
);
|
|
14768
14829
|
}
|
|
14769
14830
|
}
|
|
14770
|
-
const gitCheck = (0,
|
|
14831
|
+
const gitCheck = (0, import_node_child_process30.spawnSync)(
|
|
14771
14832
|
"docker",
|
|
14772
14833
|
[
|
|
14773
14834
|
"exec",
|
|
@@ -15040,14 +15101,14 @@ function resolvePrimaryTarget(repoPath) {
|
|
|
15040
15101
|
}
|
|
15041
15102
|
function isPrimaryCheckout(repoPath) {
|
|
15042
15103
|
try {
|
|
15043
|
-
return
|
|
15104
|
+
return import_node_fs35.default.statSync(import_node_path40.default.join(repoPath, ".git")).isDirectory();
|
|
15044
15105
|
} catch {
|
|
15045
15106
|
return false;
|
|
15046
15107
|
}
|
|
15047
15108
|
}
|
|
15048
15109
|
function openUrls(urls) {
|
|
15049
15110
|
for (const url of urls) {
|
|
15050
|
-
const opened = (0,
|
|
15111
|
+
const opened = (0, import_node_child_process30.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
15051
15112
|
if (opened.status !== 0) {
|
|
15052
15113
|
process.stderr.write(`Warning: could not open '${url}'.
|
|
15053
15114
|
`);
|
|
@@ -15104,8 +15165,8 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
15104
15165
|
const target = options.repair ? resolveRepairTarget(repoPath, linked) : linked ? resolveLinkedTarget(repoPath) : resolvePrimaryTarget(repoPath);
|
|
15105
15166
|
let devpodId = target.devpodId;
|
|
15106
15167
|
if (target.kind === "linked") {
|
|
15107
|
-
const overlayPath =
|
|
15108
|
-
if (!
|
|
15168
|
+
const overlayPath = import_node_path40.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
|
|
15169
|
+
if (!import_node_fs35.default.existsSync(overlayPath)) {
|
|
15109
15170
|
throw new Error(`Missing required DevPod compose overlay: ${overlayPath}`);
|
|
15110
15171
|
}
|
|
15111
15172
|
}
|
|
@@ -15205,7 +15266,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
15205
15266
|
}
|
|
15206
15267
|
const apps = proxyAppsFromConfig(runtime.config);
|
|
15207
15268
|
const parsedUpstreams = apps.map((app) => parseUpstream(app.upstream));
|
|
15208
|
-
const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ??
|
|
15269
|
+
const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ?? import_node_path40.default.basename(repoPath)) ?? "app";
|
|
15209
15270
|
for (const [index, app] of apps.entries()) {
|
|
15210
15271
|
if (!parsedUpstreams[index].host.startsWith(`${aliasPrefix}-`)) {
|
|
15211
15272
|
const owner = target.kind === "linked" ? "workspace" : "checkout";
|
|
@@ -15330,7 +15391,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
15330
15391
|
transitionPhase = "service-start";
|
|
15331
15392
|
reportLifecycleProgress("service-start");
|
|
15332
15393
|
claimLifecycleEffect();
|
|
15333
|
-
const result = (0,
|
|
15394
|
+
const result = (0, import_node_child_process30.spawnSync)("docker", ["start", ...stopped.map((entry) => entry.id)], {
|
|
15334
15395
|
...networkDockerOptions(),
|
|
15335
15396
|
encoding: "utf-8",
|
|
15336
15397
|
timeout: DEFAULT_READINESS_TIMEOUT_MS,
|
|
@@ -16047,9 +16108,9 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
16047
16108
|
}
|
|
16048
16109
|
const repairLocked = () => {
|
|
16049
16110
|
const runtime = resolveWorkspaceRuntimeOrDefault(repoPath);
|
|
16050
|
-
|
|
16111
|
+
import_node_fs35.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
16051
16112
|
return withFileLock(
|
|
16052
|
-
|
|
16113
|
+
import_node_path40.default.join(DEVROUTER_HOME, `${runtime}-mutation.lock`),
|
|
16053
16114
|
{
|
|
16054
16115
|
activity: "Managed runtime repair",
|
|
16055
16116
|
target: repoPath,
|
|
@@ -16263,7 +16324,7 @@ async function executeLifecycleWorker(request, operation) {
|
|
|
16263
16324
|
const owned = containers.filter(
|
|
16264
16325
|
(container) => sameWorkspacePath(
|
|
16265
16326
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
16266
|
-
|
|
16327
|
+
import_node_path41.default.join(request.repoPath, ".devcontainer")
|
|
16267
16328
|
)
|
|
16268
16329
|
);
|
|
16269
16330
|
const projects = owned.map((container) => container.labels["com.docker.compose.project"]);
|
|
@@ -16374,7 +16435,7 @@ function proveLifecycleStopped() {
|
|
|
16374
16435
|
const remaining = inspectWorkspaceContainers().filter(
|
|
16375
16436
|
(container) => sameWorkspacePath(
|
|
16376
16437
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
16377
|
-
|
|
16438
|
+
import_node_path41.default.join(request.repoPath, ".devcontainer")
|
|
16378
16439
|
)
|
|
16379
16440
|
);
|
|
16380
16441
|
if (remaining.some(
|
|
@@ -16404,7 +16465,7 @@ function proveLifecycleStopped() {
|
|
|
16404
16465
|
return void 0;
|
|
16405
16466
|
});
|
|
16406
16467
|
if (settlement) {
|
|
16407
|
-
const capacity = createLifecycleCapacityStore(
|
|
16468
|
+
const capacity = createLifecycleCapacityStore(import_node_path41.default.join(DEVROUTER_HOME, "controller"));
|
|
16408
16469
|
for (let attempt = 0; ; attempt++) {
|
|
16409
16470
|
try {
|
|
16410
16471
|
const state = capacity.inspect();
|
|
@@ -16483,7 +16544,7 @@ async function devsyExecOutcome(repoPath, command, retainedProof) {
|
|
|
16483
16544
|
const launch = () => {
|
|
16484
16545
|
if (retainedProof) revalidateDevsyExecProof(repoPath, retainedProof);
|
|
16485
16546
|
claimLifecycleEffect();
|
|
16486
|
-
return (0,
|
|
16547
|
+
return (0, import_node_child_process31.spawn)("devsy", args, { stdio: "inherit" });
|
|
16487
16548
|
};
|
|
16488
16549
|
child = retainedProof ? withMutationLock("Execute retained workspace", repoPath, launch) : launch();
|
|
16489
16550
|
} catch (error) {
|
|
@@ -16531,7 +16592,7 @@ function ensureGuidance2(repoPath) {
|
|
|
16531
16592
|
return `Run 'devrouter ensure ${repoPath}' first.`;
|
|
16532
16593
|
}
|
|
16533
16594
|
function assertRunningDevpod(devpodId, repoPath) {
|
|
16534
|
-
const result = (0,
|
|
16595
|
+
const result = (0, import_node_child_process32.spawnSync)("devpod", ["status", devpodId, "--output", "json"], {
|
|
16535
16596
|
encoding: "utf-8"
|
|
16536
16597
|
});
|
|
16537
16598
|
if (result.status !== 0) {
|
|
@@ -16710,7 +16771,7 @@ async function devpodExecOutcome(repoPath, command) {
|
|
|
16710
16771
|
let child;
|
|
16711
16772
|
try {
|
|
16712
16773
|
claimLifecycleEffect();
|
|
16713
|
-
child = (0,
|
|
16774
|
+
child = (0, import_node_child_process32.spawn)("devpod", args, { stdio: ["inherit", "inherit", "pipe"] });
|
|
16714
16775
|
} catch (error) {
|
|
16715
16776
|
settled = true;
|
|
16716
16777
|
reject(
|
|
@@ -16767,12 +16828,12 @@ async function devpodExecOutcome(repoPath, command) {
|
|
|
16767
16828
|
}
|
|
16768
16829
|
|
|
16769
16830
|
// src/core/workspace-lifecycle.ts
|
|
16770
|
-
var
|
|
16771
|
-
var
|
|
16772
|
-
var
|
|
16831
|
+
var import_node_child_process33 = require("child_process");
|
|
16832
|
+
var import_node_fs37 = __toESM(require("fs"));
|
|
16833
|
+
var import_node_path42 = __toESM(require("path"));
|
|
16773
16834
|
|
|
16774
16835
|
// src/core/route-state.ts
|
|
16775
|
-
var
|
|
16836
|
+
var import_node_fs36 = __toESM(require("fs"));
|
|
16776
16837
|
function listRoutesForWorktreePath(worktreePath, routes = listHostRouteState()) {
|
|
16777
16838
|
return routes.filter((route) => sameWorkspacePath(route.repoPath, worktreePath));
|
|
16778
16839
|
}
|