@devrouter/cli 0.0.41 → 0.0.43
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/dist/devrouter.js +309 -239
- package/package.json +2 -1
- package/upgrade-prompts/0.0.42.md +39 -0
- package/upgrade-prompts/0.0.43.md +38 -0
package/dist/devrouter.js
CHANGED
|
@@ -51,6 +51,7 @@ function buildDevrouterSection() {
|
|
|
51
51
|
"- Managed selective profile: `devrouter ensure . --profile <name> --json`",
|
|
52
52
|
"- Host/docker runtime app only: `devrouter app run <host-app> --repo . --yes`",
|
|
53
53
|
"- `devrouter ls`",
|
|
54
|
+
"- Managed devcontainer source configs with `postCreateCommand` and a managed post-start adapter must set `waitFor` exactly to `postCreateCommand` or `postStartCommand`; generated managed configs preserve lifecycle fields and change only `runServices`.",
|
|
54
55
|
DEVROUTER_END_SENTINEL
|
|
55
56
|
].join("\n");
|
|
56
57
|
}
|
|
@@ -293,6 +294,10 @@ profiles:
|
|
|
293
294
|
- Inspect managed desired, active, and drift state with \`devrouter status\` and
|
|
294
295
|
\`devrouter doctor\`; values such as credentials and environment contents are
|
|
295
296
|
never written to managed runtime state.
|
|
297
|
+
- A managed adapter paired with \`postCreateCommand\` requires \`waitFor\` exactly
|
|
298
|
+
\`postCreateCommand\` or \`postStartCommand\` before provider mutation. Generated
|
|
299
|
+
selective configuration preserves lifecycle fields and changes only
|
|
300
|
+
\`runServices\`.
|
|
296
301
|
|
|
297
302
|
## Env var injection
|
|
298
303
|
|
|
@@ -1658,12 +1663,12 @@ var init_host_routes = __esm({
|
|
|
1658
1663
|
|
|
1659
1664
|
// src/core/repo-config.ts
|
|
1660
1665
|
function compareSemver(a, b) {
|
|
1661
|
-
const
|
|
1666
|
+
const parse2 = (v) => {
|
|
1662
1667
|
const match = v.trim().match(/^v?(\d+)\.(\d+)\.(\d+)$/);
|
|
1663
1668
|
return match ? { major: Number(match[1]), minor: Number(match[2]), patch: Number(match[3]) } : { major: 0, minor: 0, patch: 0 };
|
|
1664
1669
|
};
|
|
1665
|
-
const left =
|
|
1666
|
-
const right =
|
|
1670
|
+
const left = parse2(a);
|
|
1671
|
+
const right = parse2(b);
|
|
1667
1672
|
if (left.major !== right.major) return left.major - right.major;
|
|
1668
1673
|
if (left.minor !== right.minor) return left.minor - right.minor;
|
|
1669
1674
|
return left.patch - right.patch;
|
|
@@ -2504,7 +2509,7 @@ function loadRepoConfig(repoPath) {
|
|
|
2504
2509
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
2505
2510
|
const requiredVersion = config.devrouter?.version;
|
|
2506
2511
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
2507
|
-
const cliVersion = true ? "0.0.
|
|
2512
|
+
const cliVersion = true ? "0.0.43" : "0.0.0-dev";
|
|
2508
2513
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
2509
2514
|
hasWarnedVersionMismatch = true;
|
|
2510
2515
|
process.stderr.write(
|
|
@@ -3035,6 +3040,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
3035
3040
|
`- When a workspace is active: hosts auto-namespace (\`web.localhost\` \u2192 \`web.<ws>.localhost\`), \`${WORKSPACE_PLACEHOLDER}\` in \`upstream\` is substituted with the token, and the docker \`router\` key is suffixed per workspace. Managed ensure rejects every HTTP/TCP upstream outside that exact alias namespace before mutation. The runtime config is computed in memory only \u2014 the committed \`.devrouter.yml\` is never rewritten.`,
|
|
3036
3041
|
"- TLS: namespaced hosts (`web.<ws>.localhost`) are not covered by the `*.localhost` wildcard; devrouter auto-extends the mkcert cert SANs for active hosts when TLS is enabled.",
|
|
3037
3042
|
"- Lifecycle: after one-time setup, use `devrouter ensure .` for both primary and linked checkouts; never branch on checkout kind or use live verify as startup. Managed consumer images contain no devrouter package/helper: ensure delivers its matching helper at runtime and invokes an exact captured snapshot of the repository-owned post-start adapter. Keep `.devrouter.yml` as the only consumer-side version pin. Use `devrouter stop .` for a non-destructive pause, `devrouter stop . --delete` only for explicit exact-owner cleanup without removing the checkout, and `devrouter exec . -- <command...>` for container commands. Never substitute raw DevPod/Devsy mutations; they bypass the machine-global ownership lock. `workspace up` creates linked worktrees; destructive worktree removal and GC remain ledger-scoped.",
|
|
3043
|
+
"- A managed adapter plus `postCreateCommand` requires `waitFor` exactly `postCreateCommand` or `postStartCommand`; managed selective config preserves lifecycle fields and changes only `runServices`.",
|
|
3038
3044
|
"- Managed process reuse fingerprints command argv, workspace identity, and the exact adapter snapshot. If a non-secret runtime value also affects reuse, set `DEVROUTER_PROCESS_FINGERPRINT_ENV` to its comma-separated environment names; secret-like names are rejected and raw values are never persisted.",
|
|
3039
3045
|
"- Owner status is `present`, `missing`, `locked`, or `conflict`. Dirty or locked full down fails before side effects. `workspace gc` is a dry run; only `--yes` deletes exact eligible missing resources and records, never Git worktrees, branches, or prune state.",
|
|
3040
3046
|
"- `devrouter workspace cleanup --repo . --inactive-for 30d --check-merged --json` is report-only and never mutates the workspace runtime, routes, ownership, Git, Docker, applications, worktrees, or branches. It reports ownership, workspace runtime registration, runtime state (`running|stopped|busy|not-found|absent|unknown`), checkout, advisory activity, route, and integration evidence. Local DevPod/Devsy list/status checks always run; `--check-merged` alone enables read-only origin and matching GitHub/GitLab checks. Treat `not-found` as stale runtime after Docker pruning; busy, unavailable, or conflicting evidence suppresses destructive suggestions. Explicit `gc`/`down` can remove exact stale registration only after expected-ID `NotFound` proof and ownership revalidation. Runtime `lastUsed` remains advisory.",
|
|
@@ -4005,12 +4011,64 @@ var init_docker = __esm({
|
|
|
4005
4011
|
}
|
|
4006
4012
|
});
|
|
4007
4013
|
|
|
4014
|
+
// src/core/devcontainer-config.ts
|
|
4015
|
+
function isObject(value) {
|
|
4016
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4017
|
+
}
|
|
4018
|
+
function parseDevcontainerConfig(contents, sourcePath) {
|
|
4019
|
+
const errors = [];
|
|
4020
|
+
const parsed = (0, import_jsonc_parser.parse)(contents, errors, {
|
|
4021
|
+
allowTrailingComma: true,
|
|
4022
|
+
disallowComments: false
|
|
4023
|
+
});
|
|
4024
|
+
if (errors.length > 0) {
|
|
4025
|
+
const first = errors[0];
|
|
4026
|
+
throw new Error(
|
|
4027
|
+
`Could not parse Dev Container source config '${sourcePath}' as JSONC at offset ${first.offset}.`
|
|
4028
|
+
);
|
|
4029
|
+
}
|
|
4030
|
+
if (!isObject(parsed)) {
|
|
4031
|
+
throw new Error(`Dev Container source config '${sourcePath}' must contain an object.`);
|
|
4032
|
+
}
|
|
4033
|
+
return parsed;
|
|
4034
|
+
}
|
|
4035
|
+
function readDevcontainerConfig(repoPath) {
|
|
4036
|
+
const sourcePath = import_node_path8.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
4037
|
+
if (!import_node_fs9.default.existsSync(sourcePath) || !import_node_fs9.default.lstatSync(sourcePath).isFile()) {
|
|
4038
|
+
throw new Error(`Managed Dev Container source config does not exist: ${sourcePath}`);
|
|
4039
|
+
}
|
|
4040
|
+
const sourceContents = import_node_fs9.default.readFileSync(sourcePath, "utf-8");
|
|
4041
|
+
return {
|
|
4042
|
+
sourcePath,
|
|
4043
|
+
sourceContents,
|
|
4044
|
+
source: parseDevcontainerConfig(sourceContents, sourcePath)
|
|
4045
|
+
};
|
|
4046
|
+
}
|
|
4047
|
+
function assertManagedDevcontainerLifecycle(repoPath) {
|
|
4048
|
+
const { sourcePath, source } = readDevcontainerConfig(repoPath);
|
|
4049
|
+
if (source.postCreateCommand === void 0) return;
|
|
4050
|
+
if (source.waitFor === "postCreateCommand" || source.waitFor === "postStartCommand") return;
|
|
4051
|
+
const actual = source.waitFor === void 0 ? "is missing" : typeof source.waitFor === "string" ? "is an unsupported string" : "is not a string";
|
|
4052
|
+
throw new Error(
|
|
4053
|
+
`Managed Dev Container source '${sourcePath}' defines postCreateCommand, but waitFor ${actual}. Set waitFor to 'postCreateCommand' or 'postStartCommand' before retrying devrouter ensure.`
|
|
4054
|
+
);
|
|
4055
|
+
}
|
|
4056
|
+
var import_node_fs9, import_node_path8, import_jsonc_parser;
|
|
4057
|
+
var init_devcontainer_config = __esm({
|
|
4058
|
+
"src/core/devcontainer-config.ts"() {
|
|
4059
|
+
"use strict";
|
|
4060
|
+
import_node_fs9 = __toESM(require("fs"));
|
|
4061
|
+
import_node_path8 = __toESM(require("path"));
|
|
4062
|
+
import_jsonc_parser = require("jsonc-parser");
|
|
4063
|
+
}
|
|
4064
|
+
});
|
|
4065
|
+
|
|
4008
4066
|
// src/core/managed-post-start.ts
|
|
4009
4067
|
function renderDeliveryScript(targetPath) {
|
|
4010
4068
|
if (!/^\/tmp\/devrouter\/bin\/[a-zA-Z0-9._-]+$/.test(targetPath)) {
|
|
4011
4069
|
throw new Error(`Unsafe managed runtime delivery path: ${targetPath}`);
|
|
4012
4070
|
}
|
|
4013
|
-
const temporaryPrefix =
|
|
4071
|
+
const temporaryPrefix = import_node_path9.default.posix.basename(targetPath);
|
|
4014
4072
|
return `set -eu
|
|
4015
4073
|
umask 077
|
|
4016
4074
|
runtime_root=/tmp/devrouter
|
|
@@ -4045,8 +4103,8 @@ function deliverRuntimeFile(containerId, targetPath, contents, label) {
|
|
|
4045
4103
|
}
|
|
4046
4104
|
}
|
|
4047
4105
|
function readRegularFileBytes(filePath) {
|
|
4048
|
-
if (!
|
|
4049
|
-
return
|
|
4106
|
+
if (!import_node_fs10.default.existsSync(filePath) || !import_node_fs10.default.lstatSync(filePath).isFile()) return void 0;
|
|
4107
|
+
return import_node_fs10.default.readFileSync(filePath);
|
|
4050
4108
|
}
|
|
4051
4109
|
function readRegularFile(filePath) {
|
|
4052
4110
|
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
@@ -4056,21 +4114,21 @@ function adapterFingerprint(adapter) {
|
|
|
4056
4114
|
}
|
|
4057
4115
|
function resolveProcessHelperPath() {
|
|
4058
4116
|
const candidates = [
|
|
4059
|
-
|
|
4060
|
-
|
|
4117
|
+
import_node_path9.default.resolve(__dirname, "..", "bin", "devrouter-process"),
|
|
4118
|
+
import_node_path9.default.resolve(__dirname, "..", "..", "bin", "devrouter-process")
|
|
4061
4119
|
];
|
|
4062
|
-
const helperPath = candidates.find((candidate) =>
|
|
4120
|
+
const helperPath = candidates.find((candidate) => import_node_fs10.default.existsSync(candidate));
|
|
4063
4121
|
if (!helperPath) {
|
|
4064
4122
|
throw new Error("Could not locate the packaged devrouter-process helper.");
|
|
4065
4123
|
}
|
|
4066
4124
|
return helperPath;
|
|
4067
4125
|
}
|
|
4068
4126
|
function resolveManagedPostStartPlan(repoPath) {
|
|
4069
|
-
const adapterPath =
|
|
4127
|
+
const adapterPath = import_node_path9.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
4070
4128
|
const adapterBytes = readRegularFileBytes(adapterPath);
|
|
4071
4129
|
const adapterText = adapterBytes?.toString("utf-8");
|
|
4072
|
-
const dockerfilePath =
|
|
4073
|
-
const devcontainerPath =
|
|
4130
|
+
const dockerfilePath = import_node_path9.default.join(repoPath, ".devcontainer", "Dockerfile");
|
|
4131
|
+
const devcontainerPath = import_node_path9.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
4074
4132
|
const dockerfile = readRegularFile(dockerfilePath) ?? "";
|
|
4075
4133
|
const devcontainer = readRegularFile(devcontainerPath) ?? "";
|
|
4076
4134
|
const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
|
|
@@ -4093,6 +4151,7 @@ function resolveManagedPostStartPlan(repoPath) {
|
|
|
4093
4151
|
}
|
|
4094
4152
|
return { kind: "unmanaged" };
|
|
4095
4153
|
}
|
|
4154
|
+
assertManagedDevcontainerLifecycle(repoPath);
|
|
4096
4155
|
if (adapter.includes("DEVROUTER_PROCESS_HELPER")) {
|
|
4097
4156
|
return {
|
|
4098
4157
|
kind: "runtime",
|
|
@@ -4110,7 +4169,7 @@ function resolveManagedPostStartPlan(repoPath) {
|
|
|
4110
4169
|
}
|
|
4111
4170
|
function runManagedPostStart(options) {
|
|
4112
4171
|
if (options.plan.kind !== "runtime") return;
|
|
4113
|
-
const helper =
|
|
4172
|
+
const helper = import_node_fs10.default.readFileSync(resolveProcessHelperPath());
|
|
4114
4173
|
deliverRuntimeFile(
|
|
4115
4174
|
options.container.id,
|
|
4116
4175
|
RUNTIME_HELPER_PATH,
|
|
@@ -4198,14 +4257,15 @@ function runManagedProcessAction(options) {
|
|
|
4198
4257
|
}
|
|
4199
4258
|
return "drifted";
|
|
4200
4259
|
}
|
|
4201
|
-
var import_node_child_process5, import_node_crypto3,
|
|
4260
|
+
var import_node_child_process5, import_node_crypto3, import_node_fs10, import_node_path9, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH, ADAPTER_WRAPPER;
|
|
4202
4261
|
var init_managed_post_start = __esm({
|
|
4203
4262
|
"src/core/managed-post-start.ts"() {
|
|
4204
4263
|
"use strict";
|
|
4205
4264
|
import_node_child_process5 = require("child_process");
|
|
4206
4265
|
import_node_crypto3 = require("crypto");
|
|
4207
|
-
|
|
4208
|
-
|
|
4266
|
+
import_node_fs10 = __toESM(require("fs"));
|
|
4267
|
+
import_node_path9 = __toESM(require("path"));
|
|
4268
|
+
init_devcontainer_config();
|
|
4209
4269
|
MANAGED_MARKER = "devrouter:managed devcontainer";
|
|
4210
4270
|
MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
|
|
4211
4271
|
RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
|
|
@@ -4271,7 +4331,7 @@ function isLoopbackHost(host) {
|
|
|
4271
4331
|
return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
|
|
4272
4332
|
}
|
|
4273
4333
|
function inspectCompose(composeFile, _workspace) {
|
|
4274
|
-
if (!
|
|
4334
|
+
if (!import_node_fs11.default.existsSync(composeFile)) {
|
|
4275
4335
|
return {
|
|
4276
4336
|
aliases: [],
|
|
4277
4337
|
publishedPorts: [],
|
|
@@ -4280,7 +4340,7 @@ function inspectCompose(composeFile, _workspace) {
|
|
|
4280
4340
|
};
|
|
4281
4341
|
}
|
|
4282
4342
|
try {
|
|
4283
|
-
const raw =
|
|
4343
|
+
const raw = import_node_fs11.default.readFileSync(composeFile, "utf-8");
|
|
4284
4344
|
const parsed = import_yaml3.default.parse(raw);
|
|
4285
4345
|
const root = asRecord(parsed);
|
|
4286
4346
|
const services = asRecord(root?.services);
|
|
@@ -4337,11 +4397,11 @@ function routedProxyApps(config) {
|
|
|
4337
4397
|
);
|
|
4338
4398
|
}
|
|
4339
4399
|
function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
4340
|
-
const devcontainerDir =
|
|
4341
|
-
if (!
|
|
4400
|
+
const devcontainerDir = import_node_path10.default.join(repoPath, ".devcontainer");
|
|
4401
|
+
if (!import_node_fs11.default.existsSync(devcontainerDir)) {
|
|
4342
4402
|
return [];
|
|
4343
4403
|
}
|
|
4344
|
-
const compose = inspectCompose(
|
|
4404
|
+
const compose = inspectCompose(import_node_path10.default.join(devcontainerDir, "docker-compose.yml"), workspace);
|
|
4345
4405
|
const checks = [];
|
|
4346
4406
|
if (compose.parseError) {
|
|
4347
4407
|
checks.push({
|
|
@@ -4368,9 +4428,9 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
4368
4428
|
details: compose.publishedPorts.length > 0 ? compose.publishedPorts.join(", ") : void 0,
|
|
4369
4429
|
suggestion: compose.parseError || compose.publishedPorts.length > 0 ? "Remove published ports and route services through devnet aliases with devrouter proxy apps." : void 0
|
|
4370
4430
|
});
|
|
4371
|
-
const dockerfilePath =
|
|
4372
|
-
const dockerfileExists =
|
|
4373
|
-
const dockerfile = dockerfileExists ?
|
|
4431
|
+
const dockerfilePath = import_node_path10.default.join(devcontainerDir, "Dockerfile");
|
|
4432
|
+
const dockerfileExists = import_node_fs11.default.existsSync(dockerfilePath);
|
|
4433
|
+
const dockerfile = dockerfileExists ? import_node_fs11.default.readFileSync(dockerfilePath, "utf-8") : "";
|
|
4374
4434
|
const devrouterArtifacts = ["@devrouter/cli", "devrouter-process"].filter(
|
|
4375
4435
|
(artifact) => dockerfile.includes(artifact)
|
|
4376
4436
|
);
|
|
@@ -4425,12 +4485,12 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
4425
4485
|
});
|
|
4426
4486
|
return checks;
|
|
4427
4487
|
}
|
|
4428
|
-
var
|
|
4488
|
+
var import_node_fs11, import_node_path10, import_yaml3;
|
|
4429
4489
|
var init_devcontainer_diagnostics = __esm({
|
|
4430
4490
|
"src/core/devcontainer-diagnostics.ts"() {
|
|
4431
4491
|
"use strict";
|
|
4432
|
-
|
|
4433
|
-
|
|
4492
|
+
import_node_fs11 = __toESM(require("fs"));
|
|
4493
|
+
import_node_path10 = __toESM(require("path"));
|
|
4434
4494
|
import_yaml3 = __toESM(require("yaml"));
|
|
4435
4495
|
init_managed_post_start();
|
|
4436
4496
|
}
|
|
@@ -4438,18 +4498,18 @@ var init_devcontainer_diagnostics = __esm({
|
|
|
4438
4498
|
|
|
4439
4499
|
// src/core/paths.ts
|
|
4440
4500
|
function assertPathWithinRepo(filePath, repoRoot, label) {
|
|
4441
|
-
const resolvedRoot =
|
|
4442
|
-
const resolved =
|
|
4443
|
-
if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot +
|
|
4501
|
+
const resolvedRoot = import_node_path11.default.resolve(repoRoot);
|
|
4502
|
+
const resolved = import_node_path11.default.resolve(repoRoot, filePath);
|
|
4503
|
+
if (resolved !== resolvedRoot && !resolved.startsWith(resolvedRoot + import_node_path11.default.sep)) {
|
|
4444
4504
|
throw new Error(`${label} path '${filePath}' escapes the repository root.`);
|
|
4445
4505
|
}
|
|
4446
4506
|
return resolved;
|
|
4447
4507
|
}
|
|
4448
|
-
var
|
|
4508
|
+
var import_node_path11;
|
|
4449
4509
|
var init_paths = __esm({
|
|
4450
4510
|
"src/core/paths.ts"() {
|
|
4451
4511
|
"use strict";
|
|
4452
|
-
|
|
4512
|
+
import_node_path11 = __toESM(require("path"));
|
|
4453
4513
|
}
|
|
4454
4514
|
});
|
|
4455
4515
|
|
|
@@ -4534,11 +4594,11 @@ function reconcileRouteRunConflict(repoPath, app) {
|
|
|
4534
4594
|
}
|
|
4535
4595
|
}
|
|
4536
4596
|
}
|
|
4537
|
-
var
|
|
4597
|
+
var import_node_fs12;
|
|
4538
4598
|
var init_route_state = __esm({
|
|
4539
4599
|
"src/core/route-state.ts"() {
|
|
4540
4600
|
"use strict";
|
|
4541
|
-
|
|
4601
|
+
import_node_fs12 = __toESM(require("fs"));
|
|
4542
4602
|
init_host_routes();
|
|
4543
4603
|
init_workspace();
|
|
4544
4604
|
}
|
|
@@ -4707,7 +4767,7 @@ function stateKey(repoPath, workspace) {
|
|
|
4707
4767
|
return (0, import_node_crypto4.createHash)("sha256").update(`${repoPath}\0${workspace ?? ""}`, "utf-8").digest("hex");
|
|
4708
4768
|
}
|
|
4709
4769
|
function managedRuntimeStatePath(repoPath, workspace) {
|
|
4710
|
-
return
|
|
4770
|
+
return import_node_path12.default.join(DEVROUTER_HOME, "managed-runtime", `${stateKey(repoPath, workspace)}.json`);
|
|
4711
4771
|
}
|
|
4712
4772
|
function isStringArray(value) {
|
|
4713
4773
|
return Array.isArray(value) && value.every((item) => typeof item === "string") && new Set(value).size === value.length;
|
|
@@ -4770,10 +4830,10 @@ function validateState(value, repoPath, workspace) {
|
|
|
4770
4830
|
}
|
|
4771
4831
|
function readManagedRuntimeState(repoPath, workspace) {
|
|
4772
4832
|
const statePath = managedRuntimeStatePath(repoPath, workspace);
|
|
4773
|
-
if (!
|
|
4833
|
+
if (!import_node_fs13.default.existsSync(statePath)) return void 0;
|
|
4774
4834
|
let parsed;
|
|
4775
4835
|
try {
|
|
4776
|
-
parsed = JSON.parse(
|
|
4836
|
+
parsed = JSON.parse(import_node_fs13.default.readFileSync(statePath, "utf-8"));
|
|
4777
4837
|
} catch (error) {
|
|
4778
4838
|
throw new Error(`Could not parse managed runtime state: ${String(error)}`);
|
|
4779
4839
|
}
|
|
@@ -4795,20 +4855,20 @@ function markManagedRuntimeDegraded(state, transitionPhase) {
|
|
|
4795
4855
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
4796
4856
|
});
|
|
4797
4857
|
}
|
|
4798
|
-
var import_node_crypto4,
|
|
4858
|
+
var import_node_crypto4, import_node_fs13, import_node_path12;
|
|
4799
4859
|
var init_managed_runtime_state = __esm({
|
|
4800
4860
|
"src/core/managed-runtime-state.ts"() {
|
|
4801
4861
|
"use strict";
|
|
4802
4862
|
import_node_crypto4 = require("crypto");
|
|
4803
|
-
|
|
4804
|
-
|
|
4863
|
+
import_node_fs13 = __toESM(require("fs"));
|
|
4864
|
+
import_node_path12 = __toESM(require("path"));
|
|
4805
4865
|
init_atomic_file();
|
|
4806
4866
|
init_router();
|
|
4807
4867
|
}
|
|
4808
4868
|
});
|
|
4809
4869
|
|
|
4810
4870
|
// src/core/devcontainer-profile.ts
|
|
4811
|
-
function
|
|
4871
|
+
function isObject2(value) {
|
|
4812
4872
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
4813
4873
|
}
|
|
4814
4874
|
function nonEmptyString(value, label) {
|
|
@@ -4852,14 +4912,14 @@ function resolveComposeFiles(source, repoPath, linked) {
|
|
|
4852
4912
|
"managedRuntime requires .devcontainer/devcontainer.json to define dockerComposeFile."
|
|
4853
4913
|
);
|
|
4854
4914
|
}
|
|
4855
|
-
const directory =
|
|
4915
|
+
const directory = import_node_path13.default.join(repoPath, ".devcontainer");
|
|
4856
4916
|
const files = references.map((reference) => {
|
|
4857
4917
|
const resolved2 = assertPathWithinRepo(
|
|
4858
4918
|
resolveComposeReference(reference, linked),
|
|
4859
4919
|
directory,
|
|
4860
4920
|
"dockerComposeFile"
|
|
4861
4921
|
);
|
|
4862
|
-
if (!
|
|
4922
|
+
if (!import_node_fs14.default.existsSync(resolved2) || !import_node_fs14.default.lstatSync(resolved2).isFile()) {
|
|
4863
4923
|
throw new Error(`Managed Dev Container compose file does not exist: ${resolved2}`);
|
|
4864
4924
|
}
|
|
4865
4925
|
return resolved2;
|
|
@@ -4867,13 +4927,13 @@ function resolveComposeFiles(source, repoPath, linked) {
|
|
|
4867
4927
|
for (const file of files) {
|
|
4868
4928
|
let parsed;
|
|
4869
4929
|
try {
|
|
4870
|
-
parsed = import_yaml4.default.parse(
|
|
4930
|
+
parsed = import_yaml4.default.parse(import_node_fs14.default.readFileSync(file, "utf-8"));
|
|
4871
4931
|
} catch (error) {
|
|
4872
4932
|
throw new Error(
|
|
4873
4933
|
`Could not parse managed Dev Container compose file '${file}': ${String(error)}`
|
|
4874
4934
|
);
|
|
4875
4935
|
}
|
|
4876
|
-
if (!
|
|
4936
|
+
if (!isObject2(parsed) || !isObject2(parsed.services)) {
|
|
4877
4937
|
throw new Error(`Managed Dev Container compose file '${file}' has no services map.`);
|
|
4878
4938
|
}
|
|
4879
4939
|
}
|
|
@@ -4916,12 +4976,12 @@ function assertIgnoredGeneratedPath(repoPath, generatedPath) {
|
|
|
4916
4976
|
}
|
|
4917
4977
|
}
|
|
4918
4978
|
function assertGeneratedPathOwnership(generatedPath) {
|
|
4919
|
-
if (!
|
|
4920
|
-
const stat =
|
|
4979
|
+
if (!import_node_fs14.default.existsSync(generatedPath)) return;
|
|
4980
|
+
const stat = import_node_fs14.default.lstatSync(generatedPath);
|
|
4921
4981
|
if (!stat.isFile() || stat.isSymbolicLink()) {
|
|
4922
4982
|
throw new Error(`Managed Dev Container path '${generatedPath}' is not a regular file.`);
|
|
4923
4983
|
}
|
|
4924
|
-
const firstLine2 =
|
|
4984
|
+
const firstLine2 = import_node_fs14.default.readFileSync(generatedPath, "utf-8").split(/\r?\n/, 1)[0];
|
|
4925
4985
|
if (firstLine2 !== MANAGED_DEVCONTAINER_MARKER) {
|
|
4926
4986
|
throw new Error(
|
|
4927
4987
|
`Managed Dev Container path '${generatedPath}' exists without the devrouter ownership marker.`
|
|
@@ -4945,21 +5005,7 @@ function inspectManagedDevcontainerConfig(options) {
|
|
|
4945
5005
|
if (!managedRuntime) {
|
|
4946
5006
|
throw new Error("Cannot prepare a managed Dev Container without managedRuntime.");
|
|
4947
5007
|
}
|
|
4948
|
-
const sourcePath =
|
|
4949
|
-
if (!import_node_fs13.default.existsSync(sourcePath) || !import_node_fs13.default.lstatSync(sourcePath).isFile()) {
|
|
4950
|
-
throw new Error(`Managed Dev Container source config does not exist: ${sourcePath}`);
|
|
4951
|
-
}
|
|
4952
|
-
const sourceContents = import_node_fs13.default.readFileSync(sourcePath, "utf-8");
|
|
4953
|
-
let parsed;
|
|
4954
|
-
try {
|
|
4955
|
-
parsed = import_yaml4.default.parse(sourceContents);
|
|
4956
|
-
} catch (error) {
|
|
4957
|
-
throw new Error(`Could not parse managed Dev Container source config: ${String(error)}`);
|
|
4958
|
-
}
|
|
4959
|
-
if (!isObject(parsed)) {
|
|
4960
|
-
throw new Error("Managed Dev Container source config must contain an object.");
|
|
4961
|
-
}
|
|
4962
|
-
const source = parsed;
|
|
5008
|
+
const { sourcePath, sourceContents, source } = readDevcontainerConfig(options.repoPath);
|
|
4963
5009
|
const primaryService = nonEmptyString(source.service, "devcontainer.service");
|
|
4964
5010
|
const compose = resolveComposeFiles(source, options.repoPath, options.linked);
|
|
4965
5011
|
const composeServiceSet = new Set(compose.services);
|
|
@@ -5011,7 +5057,7 @@ function inspectManagedDevcontainerConfig(options) {
|
|
|
5011
5057
|
const contents = `${MANAGED_DEVCONTAINER_MARKER}
|
|
5012
5058
|
${JSON.stringify(effective, null, 2)}
|
|
5013
5059
|
`;
|
|
5014
|
-
const generatedPath =
|
|
5060
|
+
const generatedPath = import_node_path13.default.join(options.repoPath, MANAGED_DEVCONTAINER_PATH);
|
|
5015
5061
|
assertIgnoredGeneratedPath(options.repoPath, generatedPath);
|
|
5016
5062
|
assertGeneratedPathOwnership(generatedPath);
|
|
5017
5063
|
return {
|
|
@@ -5038,13 +5084,13 @@ function writeManagedDevcontainerConfig(plan) {
|
|
|
5038
5084
|
function inspectManagedDevcontainerGeneratedConfig(plan) {
|
|
5039
5085
|
let stat;
|
|
5040
5086
|
try {
|
|
5041
|
-
stat =
|
|
5087
|
+
stat = import_node_fs14.default.lstatSync(plan.generatedPath);
|
|
5042
5088
|
} catch (error) {
|
|
5043
5089
|
if (error.code === "ENOENT") return { status: "missing" };
|
|
5044
5090
|
throw error;
|
|
5045
5091
|
}
|
|
5046
5092
|
if (!stat.isFile() || stat.isSymbolicLink()) return { status: "foreign" };
|
|
5047
|
-
const contents =
|
|
5093
|
+
const contents = import_node_fs14.default.readFileSync(plan.generatedPath, "utf-8");
|
|
5048
5094
|
if (!contents.startsWith(`${MANAGED_DEVCONTAINER_MARKER}
|
|
5049
5095
|
`)) {
|
|
5050
5096
|
return { status: "foreign" };
|
|
@@ -5056,17 +5102,17 @@ function inspectManagedDevcontainerGeneratedConfig(plan) {
|
|
|
5056
5102
|
};
|
|
5057
5103
|
}
|
|
5058
5104
|
function removeManagedDevcontainerConfig(plan) {
|
|
5059
|
-
if (!
|
|
5060
|
-
const stat =
|
|
5105
|
+
if (!import_node_fs14.default.existsSync(plan.generatedPath)) return;
|
|
5106
|
+
const stat = import_node_fs14.default.lstatSync(plan.generatedPath);
|
|
5061
5107
|
if (!stat.isFile()) {
|
|
5062
5108
|
throw new Error(`Managed Dev Container path '${plan.generatedPath}' is not a regular file.`);
|
|
5063
5109
|
}
|
|
5064
|
-
const contents =
|
|
5110
|
+
const contents = import_node_fs14.default.readFileSync(plan.generatedPath, "utf-8");
|
|
5065
5111
|
if (!contents.startsWith(`${MANAGED_DEVCONTAINER_MARKER}
|
|
5066
5112
|
`)) {
|
|
5067
5113
|
throw new Error(`Managed Dev Container path '${plan.generatedPath}' is not devrouter-owned.`);
|
|
5068
5114
|
}
|
|
5069
|
-
|
|
5115
|
+
import_node_fs14.default.unlinkSync(plan.generatedPath);
|
|
5070
5116
|
}
|
|
5071
5117
|
function assertSafeContainerId(containerId) {
|
|
5072
5118
|
if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(containerId)) {
|
|
@@ -5131,16 +5177,17 @@ function stopExactManagedService(containerId, service) {
|
|
|
5131
5177
|
throw new Error(`Could not stop exact managed service '${service}' (${containerId}).`);
|
|
5132
5178
|
}
|
|
5133
5179
|
}
|
|
5134
|
-
var import_node_child_process6, import_node_crypto5,
|
|
5180
|
+
var import_node_child_process6, import_node_crypto5, import_node_fs14, import_node_path13, import_yaml4, MANAGED_DEVCONTAINER_PATH, MANAGED_DEVCONTAINER_MARKER;
|
|
5135
5181
|
var init_devcontainer_profile = __esm({
|
|
5136
5182
|
"src/core/devcontainer-profile.ts"() {
|
|
5137
5183
|
"use strict";
|
|
5138
5184
|
import_node_child_process6 = require("child_process");
|
|
5139
5185
|
import_node_crypto5 = require("crypto");
|
|
5140
|
-
|
|
5141
|
-
|
|
5186
|
+
import_node_fs14 = __toESM(require("fs"));
|
|
5187
|
+
import_node_path13 = __toESM(require("path"));
|
|
5142
5188
|
import_yaml4 = __toESM(require("yaml"));
|
|
5143
5189
|
init_atomic_file();
|
|
5190
|
+
init_devcontainer_config();
|
|
5144
5191
|
init_paths();
|
|
5145
5192
|
MANAGED_DEVCONTAINER_PATH = ".devcontainer/devcontainer.devrouter.json";
|
|
5146
5193
|
MANAGED_DEVCONTAINER_MARKER = "// devrouter:managed devcontainer profile";
|
|
@@ -5178,7 +5225,7 @@ function inspectWorkspaceContainers(options) {
|
|
|
5178
5225
|
function workspaceAppContainers(containers, repoPath) {
|
|
5179
5226
|
return containers.filter((container) => {
|
|
5180
5227
|
const workingDir = container.labels["com.docker.compose.project.working_dir"];
|
|
5181
|
-
return Boolean(workingDir && sameWorkspacePath(workingDir,
|
|
5228
|
+
return Boolean(workingDir && sameWorkspacePath(workingDir, import_node_path14.default.join(repoPath, ".devcontainer"))) && container.mounts.some(
|
|
5182
5229
|
(mount) => mount.Type === "bind" && sameWorkspacePath(mount.Source, repoPath)
|
|
5183
5230
|
);
|
|
5184
5231
|
});
|
|
@@ -5186,7 +5233,7 @@ function workspaceAppContainers(containers, repoPath) {
|
|
|
5186
5233
|
function hasExactComposeIdentity(container, options) {
|
|
5187
5234
|
if (options.composeProject !== void 0 && container.labels["com.docker.compose.project"] !== options.composeProject || container.labels["com.docker.compose.service"] !== options.service || !sameWorkspacePath(
|
|
5188
5235
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
5189
|
-
|
|
5236
|
+
import_node_path14.default.join(options.repoPath, ".devcontainer")
|
|
5190
5237
|
)) {
|
|
5191
5238
|
return false;
|
|
5192
5239
|
}
|
|
@@ -5195,7 +5242,7 @@ function hasExactComposeIdentity(container, options) {
|
|
|
5195
5242
|
const actualFiles = (container.labels["com.docker.compose.project.config_files"] ?? "").split(",").map((file) => file.trim()).filter(Boolean);
|
|
5196
5243
|
const providerGeneratedFiles = actualFiles.filter((file) => {
|
|
5197
5244
|
const normalized = file.replaceAll("\\", "/");
|
|
5198
|
-
return
|
|
5245
|
+
return /\/(?:\.devpod\/agent\/contexts\/[^/]+\/workspaces\/[^/]+|\.devsy\/contexts\/[^/]+\/workspaces\/[^/]+\/agent)\/\.docker-compose\/docker-compose\.devcontainer\.containerFeatures-[^/]+\.yml$/.test(
|
|
5199
5246
|
normalized
|
|
5200
5247
|
);
|
|
5201
5248
|
});
|
|
@@ -5223,12 +5270,12 @@ function resolveRunningWorkspaceContainer(repoPath) {
|
|
|
5223
5270
|
}
|
|
5224
5271
|
return { id: container.id, workspacePath: repoMount.Destination };
|
|
5225
5272
|
}
|
|
5226
|
-
var import_node_child_process7,
|
|
5273
|
+
var import_node_child_process7, import_node_path14, SAFE_INSPECT_TEMPLATE, SIZE_INSPECT_TEMPLATE;
|
|
5227
5274
|
var init_devpod_environment = __esm({
|
|
5228
5275
|
"src/core/devpod-environment.ts"() {
|
|
5229
5276
|
"use strict";
|
|
5230
5277
|
import_node_child_process7 = require("child_process");
|
|
5231
|
-
|
|
5278
|
+
import_node_path14 = __toESM(require("path"));
|
|
5232
5279
|
init_workspace();
|
|
5233
5280
|
SAFE_INSPECT_TEMPLATE = '{"id":{{json .Id}},"state":{"Running":{{json .State.Running}},"Health":{{with (index .State "Health")}}{"Status":{{json .Status}}}{{else}}null{{end}}},"labels":{"com.docker.compose.project":{{json (index .Config.Labels "com.docker.compose.project")}},"com.docker.compose.service":{{json (index .Config.Labels "com.docker.compose.service")}},"com.docker.compose.project.working_dir":{{json (index .Config.Labels "com.docker.compose.project.working_dir")}},"com.docker.compose.project.config_files":{{json (index .Config.Labels "com.docker.compose.project.config_files")}}},"mounts":{{json .Mounts}},"networks":{{json .NetworkSettings.Networks}}}';
|
|
5234
5281
|
SIZE_INSPECT_TEMPLATE = SAFE_INSPECT_TEMPLATE.replace(
|
|
@@ -5682,7 +5729,7 @@ function toRepoStatus(repoPath) {
|
|
|
5682
5729
|
const resolvedRepoPath = resolveRepoPath(repoPath);
|
|
5683
5730
|
const configPath = getRepoConfigPath(resolvedRepoPath);
|
|
5684
5731
|
const explicitRepo = typeof repoPath === "string" && repoPath.trim().length > 0;
|
|
5685
|
-
const configExists =
|
|
5732
|
+
const configExists = import_node_fs15.default.existsSync(configPath);
|
|
5686
5733
|
if (!explicitRepo && !configExists) {
|
|
5687
5734
|
return void 0;
|
|
5688
5735
|
}
|
|
@@ -5830,11 +5877,11 @@ async function collectRouterStatus(repoPath) {
|
|
|
5830
5877
|
}
|
|
5831
5878
|
};
|
|
5832
5879
|
}
|
|
5833
|
-
var
|
|
5880
|
+
var import_node_fs15;
|
|
5834
5881
|
var init_status = __esm({
|
|
5835
5882
|
"src/core/status.ts"() {
|
|
5836
5883
|
"use strict";
|
|
5837
|
-
|
|
5884
|
+
import_node_fs15 = __toESM(require("fs"));
|
|
5838
5885
|
init_docker();
|
|
5839
5886
|
init_managed_runtime_state();
|
|
5840
5887
|
init_managed_runtime_status();
|
|
@@ -5873,8 +5920,8 @@ function tlsSetupCommand(repoPath) {
|
|
|
5873
5920
|
}
|
|
5874
5921
|
function getMkcertRootCAPath(options = {}) {
|
|
5875
5922
|
ensureMkcert();
|
|
5876
|
-
const rootCAPath =
|
|
5877
|
-
if (!
|
|
5923
|
+
const rootCAPath = import_node_path15.default.join(runOrThrow("mkcert", ["-CAROOT"]), "rootCA.pem");
|
|
5924
|
+
if (!import_node_fs16.default.existsSync(rootCAPath)) {
|
|
5878
5925
|
throw new Error(
|
|
5879
5926
|
`mkcert root CA was not found at '${rootCAPath}'. Run: ${tlsSetupCommand(options.repoPath)}`
|
|
5880
5927
|
);
|
|
@@ -5940,10 +5987,10 @@ function findUncoveredCertificateHosts(requiredHosts, certificateHosts) {
|
|
|
5940
5987
|
);
|
|
5941
5988
|
}
|
|
5942
5989
|
function readCurrentCertificateHosts() {
|
|
5943
|
-
if (!
|
|
5990
|
+
if (!import_node_fs16.default.existsSync(CERT_FILE)) {
|
|
5944
5991
|
return [];
|
|
5945
5992
|
}
|
|
5946
|
-
const pem =
|
|
5993
|
+
const pem = import_node_fs16.default.readFileSync(CERT_FILE, "utf-8");
|
|
5947
5994
|
return parseCertificateDnsHosts(pem);
|
|
5948
5995
|
}
|
|
5949
5996
|
function currentCertificateHostsOrEmpty() {
|
|
@@ -6032,14 +6079,14 @@ Run: ${tlsSetupCommand(options.repoPath)}`
|
|
|
6032
6079
|
);
|
|
6033
6080
|
}
|
|
6034
6081
|
}
|
|
6035
|
-
var import_node_child_process8, import_node_crypto6,
|
|
6082
|
+
var import_node_child_process8, import_node_crypto6, import_node_fs16, import_node_path15, DEFAULT_TLS_CERT_HOSTS;
|
|
6036
6083
|
var init_tls = __esm({
|
|
6037
6084
|
"src/core/tls.ts"() {
|
|
6038
6085
|
"use strict";
|
|
6039
6086
|
import_node_child_process8 = require("child_process");
|
|
6040
6087
|
import_node_crypto6 = require("crypto");
|
|
6041
|
-
|
|
6042
|
-
|
|
6088
|
+
import_node_fs16 = __toESM(require("fs"));
|
|
6089
|
+
import_node_path15 = __toESM(require("path"));
|
|
6043
6090
|
init_docker();
|
|
6044
6091
|
init_host_routes();
|
|
6045
6092
|
init_router();
|
|
@@ -6220,7 +6267,7 @@ function isRuntimeInstalled(runtime) {
|
|
|
6220
6267
|
function readWorkspaceRuntimeConfig() {
|
|
6221
6268
|
let raw;
|
|
6222
6269
|
try {
|
|
6223
|
-
raw = JSON.parse(
|
|
6270
|
+
raw = JSON.parse(import_node_fs17.default.readFileSync(RUNTIME_CONFIG_FILE, "utf-8"));
|
|
6224
6271
|
} catch {
|
|
6225
6272
|
return {};
|
|
6226
6273
|
}
|
|
@@ -6241,7 +6288,7 @@ function readWorkspaceRuntimeConfig() {
|
|
|
6241
6288
|
function inspectWorkspaceRuntimeConfig() {
|
|
6242
6289
|
let rawText;
|
|
6243
6290
|
try {
|
|
6244
|
-
rawText =
|
|
6291
|
+
rawText = import_node_fs17.default.readFileSync(RUNTIME_CONFIG_FILE, "utf-8");
|
|
6245
6292
|
} catch {
|
|
6246
6293
|
return { exists: false, config: {}, problems: [] };
|
|
6247
6294
|
}
|
|
@@ -6292,7 +6339,7 @@ function writeWorkspaceRuntimeConfig(config) {
|
|
|
6292
6339
|
}
|
|
6293
6340
|
next.devsyInactivityTimeout = timeout;
|
|
6294
6341
|
}
|
|
6295
|
-
|
|
6342
|
+
import_node_fs17.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
6296
6343
|
writeFileAtomically(RUNTIME_CONFIG_FILE, `${JSON.stringify(next, null, 2)}
|
|
6297
6344
|
`);
|
|
6298
6345
|
}
|
|
@@ -6400,20 +6447,20 @@ function resetWorkspaceRuntimeCaches() {
|
|
|
6400
6447
|
cachedRuntime = void 0;
|
|
6401
6448
|
cachedSnapshots = void 0;
|
|
6402
6449
|
}
|
|
6403
|
-
var import_node_child_process11,
|
|
6450
|
+
var import_node_child_process11, import_node_fs17, import_node_path16, SUPPORTED_RUNTIMES2, RUNTIME_CONFIG_FILE, INACTIVITY_TIMEOUT_PATTERN, cachedRuntime, cachedSnapshots, UnsupportedWorkspaceRuntimeError, WorkspaceRuntimeOwnershipError;
|
|
6404
6451
|
var init_workspace_runtime = __esm({
|
|
6405
6452
|
"src/core/workspace-runtime.ts"() {
|
|
6406
6453
|
"use strict";
|
|
6407
6454
|
import_node_child_process11 = require("child_process");
|
|
6408
|
-
|
|
6409
|
-
|
|
6455
|
+
import_node_fs17 = __toESM(require("fs"));
|
|
6456
|
+
import_node_path16 = __toESM(require("path"));
|
|
6410
6457
|
init_atomic_file();
|
|
6411
6458
|
init_devpod_registry();
|
|
6412
6459
|
init_devsy_workspaces();
|
|
6413
6460
|
init_router();
|
|
6414
6461
|
init_workspace();
|
|
6415
6462
|
SUPPORTED_RUNTIMES2 = ["devpod", "devsy"];
|
|
6416
|
-
RUNTIME_CONFIG_FILE =
|
|
6463
|
+
RUNTIME_CONFIG_FILE = import_node_path16.default.join(DEVROUTER_HOME, "workspace-runtime.json");
|
|
6417
6464
|
INACTIVITY_TIMEOUT_PATTERN = /^(?:\d+(?:ms|s|m|h))+$/;
|
|
6418
6465
|
UnsupportedWorkspaceRuntimeError = class extends Error {
|
|
6419
6466
|
};
|
|
@@ -6491,12 +6538,12 @@ function parseMinimumNodeMajor(value) {
|
|
|
6491
6538
|
return Number(match[1]);
|
|
6492
6539
|
}
|
|
6493
6540
|
function readPackageJson(repoPath) {
|
|
6494
|
-
const packagePath =
|
|
6495
|
-
if (!
|
|
6541
|
+
const packagePath = import_node_path17.default.join(repoPath, "package.json");
|
|
6542
|
+
if (!import_node_fs18.default.existsSync(packagePath)) {
|
|
6496
6543
|
return void 0;
|
|
6497
6544
|
}
|
|
6498
6545
|
try {
|
|
6499
|
-
return JSON.parse(
|
|
6546
|
+
return JSON.parse(import_node_fs18.default.readFileSync(packagePath, "utf-8"));
|
|
6500
6547
|
} catch {
|
|
6501
6548
|
return void 0;
|
|
6502
6549
|
}
|
|
@@ -6636,13 +6683,13 @@ function buildGlobalToolChecks(repoPath) {
|
|
|
6636
6683
|
checks.push(nodeToolchainCheck(repoPath));
|
|
6637
6684
|
return checks;
|
|
6638
6685
|
}
|
|
6639
|
-
var import_node_child_process12,
|
|
6686
|
+
var import_node_child_process12, import_node_fs18, import_node_path17;
|
|
6640
6687
|
var init_tool_diagnostics = __esm({
|
|
6641
6688
|
"src/core/tool-diagnostics.ts"() {
|
|
6642
6689
|
"use strict";
|
|
6643
6690
|
import_node_child_process12 = require("child_process");
|
|
6644
|
-
|
|
6645
|
-
|
|
6691
|
+
import_node_fs18 = __toESM(require("fs"));
|
|
6692
|
+
import_node_path17 = __toESM(require("path"));
|
|
6646
6693
|
init_workspace_runtime();
|
|
6647
6694
|
}
|
|
6648
6695
|
});
|
|
@@ -6758,8 +6805,18 @@ var init_devpod_workspaces = __esm({
|
|
|
6758
6805
|
});
|
|
6759
6806
|
|
|
6760
6807
|
// src/core/devsy-mutation.ts
|
|
6808
|
+
function failedStartMayHaveAttached(devsyId, repoPath) {
|
|
6809
|
+
try {
|
|
6810
|
+
const attached = listDevsyWorkspaces();
|
|
6811
|
+
const attachedId = devsyId ?? selectDevsyWorkspace(attached, repoPath)?.id;
|
|
6812
|
+
if (!attachedId) return false;
|
|
6813
|
+
return inspectDevsyWorkspaceOwnership(attached, attachedId, repoPath).status !== "absent";
|
|
6814
|
+
} catch {
|
|
6815
|
+
return true;
|
|
6816
|
+
}
|
|
6817
|
+
}
|
|
6761
6818
|
function withMutationLock(activity, target, operation) {
|
|
6762
|
-
|
|
6819
|
+
import_node_fs19.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
6763
6820
|
return withFileLockSync(
|
|
6764
6821
|
DEVSY_MUTATION_LOCK_FILE,
|
|
6765
6822
|
{ activity, target: `'${target}'`, waitMs: DEVSY_MUTATION_WAIT_MS },
|
|
@@ -6878,7 +6935,11 @@ function startDevsyWorkspace(options) {
|
|
|
6878
6935
|
env
|
|
6879
6936
|
});
|
|
6880
6937
|
if (result.status !== 0) {
|
|
6881
|
-
|
|
6938
|
+
const message = `devsy workspace up failed for '${devsyId ?? options.repoPath}'.`;
|
|
6939
|
+
if (failedStartMayHaveAttached(devsyId, options.repoPath)) {
|
|
6940
|
+
throw new DevsyStartPostconditionError(message);
|
|
6941
|
+
}
|
|
6942
|
+
throw new Error(message);
|
|
6882
6943
|
}
|
|
6883
6944
|
try {
|
|
6884
6945
|
const attached = listDevsyWorkspaces();
|
|
@@ -6900,17 +6961,17 @@ function startDevsyWorkspace(options) {
|
|
|
6900
6961
|
}
|
|
6901
6962
|
});
|
|
6902
6963
|
}
|
|
6903
|
-
var import_node_child_process14,
|
|
6964
|
+
var import_node_child_process14, import_node_fs19, import_node_path18, DEVSY_MUTATION_LOCK_FILE, DEVSY_MUTATION_WAIT_MS, DevsyStartPostconditionError;
|
|
6904
6965
|
var init_devsy_mutation = __esm({
|
|
6905
6966
|
"src/core/devsy-mutation.ts"() {
|
|
6906
6967
|
"use strict";
|
|
6907
6968
|
import_node_child_process14 = require("child_process");
|
|
6908
|
-
|
|
6909
|
-
|
|
6969
|
+
import_node_fs19 = __toESM(require("fs"));
|
|
6970
|
+
import_node_path18 = __toESM(require("path"));
|
|
6910
6971
|
init_devsy_workspaces();
|
|
6911
6972
|
init_file_lock();
|
|
6912
6973
|
init_router();
|
|
6913
|
-
DEVSY_MUTATION_LOCK_FILE =
|
|
6974
|
+
DEVSY_MUTATION_LOCK_FILE = import_node_path18.default.join(DEVROUTER_HOME, "devsy-mutation.lock");
|
|
6914
6975
|
DEVSY_MUTATION_WAIT_MS = 6e4;
|
|
6915
6976
|
DevsyStartPostconditionError = class extends Error {
|
|
6916
6977
|
};
|
|
@@ -6919,7 +6980,7 @@ var init_devsy_mutation = __esm({
|
|
|
6919
6980
|
|
|
6920
6981
|
// src/core/devpod-mutation.ts
|
|
6921
6982
|
function withMutationLock2(activity, target, operation) {
|
|
6922
|
-
|
|
6983
|
+
import_node_fs20.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
6923
6984
|
return withFileLockSync(
|
|
6924
6985
|
DEVPOD_MUTATION_LOCK_FILE,
|
|
6925
6986
|
{ activity, target: `'${target}'`, waitMs: DEVPOD_MUTATION_WAIT_MS },
|
|
@@ -6999,17 +7060,25 @@ function deleteOwnedDevpodWorkspace(devpodId, worktreePath) {
|
|
|
6999
7060
|
}
|
|
7000
7061
|
function startDevpodWorkspace(options) {
|
|
7001
7062
|
if (resolveWorkspaceRuntimeOrDefault(options.repoPath) === "devsy") {
|
|
7002
|
-
|
|
7003
|
-
|
|
7004
|
-
|
|
7005
|
-
|
|
7006
|
-
|
|
7007
|
-
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7063
|
+
try {
|
|
7064
|
+
const result = startDevsyWorkspace({
|
|
7065
|
+
repoPath: options.repoPath,
|
|
7066
|
+
devsyId: options.devpodId,
|
|
7067
|
+
devcontainerPath: options.devcontainerPath,
|
|
7068
|
+
recreate: options.recreate,
|
|
7069
|
+
quiet: options.quiet,
|
|
7070
|
+
workspace: options.workspace,
|
|
7071
|
+
inactivityTimeout: readWorkspaceRuntimeConfig().devsyInactivityTimeout
|
|
7072
|
+
});
|
|
7073
|
+
resetWorkspaceRuntimeCaches();
|
|
7074
|
+
return result;
|
|
7075
|
+
} catch (error) {
|
|
7076
|
+
if (error instanceof DevsyStartPostconditionError) {
|
|
7077
|
+
resetWorkspaceRuntimeCaches();
|
|
7078
|
+
throw new DevpodStartPostconditionError(error.message);
|
|
7079
|
+
}
|
|
7080
|
+
throw error;
|
|
7081
|
+
}
|
|
7013
7082
|
}
|
|
7014
7083
|
const activity = options.recreate ? "DevPod recreate" : "DevPod start";
|
|
7015
7084
|
return withMutationLock2(activity, options.repoPath, () => {
|
|
@@ -7079,19 +7148,19 @@ function startDevpodWorkspace(options) {
|
|
|
7079
7148
|
}
|
|
7080
7149
|
});
|
|
7081
7150
|
}
|
|
7082
|
-
var import_node_child_process15,
|
|
7151
|
+
var import_node_child_process15, import_node_fs20, import_node_path19, DEVPOD_MUTATION_LOCK_FILE, DEVPOD_MUTATION_WAIT_MS, DevpodStartPostconditionError;
|
|
7083
7152
|
var init_devpod_mutation = __esm({
|
|
7084
7153
|
"src/core/devpod-mutation.ts"() {
|
|
7085
7154
|
"use strict";
|
|
7086
7155
|
import_node_child_process15 = require("child_process");
|
|
7087
|
-
|
|
7088
|
-
|
|
7156
|
+
import_node_fs20 = __toESM(require("fs"));
|
|
7157
|
+
import_node_path19 = __toESM(require("path"));
|
|
7089
7158
|
init_devpod_workspaces();
|
|
7090
7159
|
init_devsy_mutation();
|
|
7091
7160
|
init_file_lock();
|
|
7092
7161
|
init_router();
|
|
7093
7162
|
init_workspace_runtime();
|
|
7094
|
-
DEVPOD_MUTATION_LOCK_FILE =
|
|
7163
|
+
DEVPOD_MUTATION_LOCK_FILE = import_node_path19.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
|
|
7095
7164
|
DEVPOD_MUTATION_WAIT_MS = 6e4;
|
|
7096
7165
|
DevpodStartPostconditionError = class extends Error {
|
|
7097
7166
|
};
|
|
@@ -7113,7 +7182,7 @@ function resolveGitCommonDir(repoPath) {
|
|
|
7113
7182
|
if (result.status !== 0 || !output2) {
|
|
7114
7183
|
throw commandError("Could not resolve the Git common directory", repoPath, result.stderr);
|
|
7115
7184
|
}
|
|
7116
|
-
return comparableWorkspacePath(
|
|
7185
|
+
return comparableWorkspacePath(import_node_path20.default.isAbsolute(output2) ? output2 : import_node_path20.default.resolve(repoPath, output2));
|
|
7117
7186
|
}
|
|
7118
7187
|
function resolveGitTopLevel(repoPath) {
|
|
7119
7188
|
const result = (0, import_node_child_process16.spawnSync)("git", ["-C", repoPath, "rev-parse", "--show-toplevel"], {
|
|
@@ -7164,7 +7233,7 @@ function listGitWorktrees(repoPath) {
|
|
|
7164
7233
|
return worktrees;
|
|
7165
7234
|
}
|
|
7166
7235
|
function ownershipDirectory(repoPath) {
|
|
7167
|
-
return
|
|
7236
|
+
return import_node_path20.default.join(resolveGitCommonDir(repoPath), OWNERSHIP_DIR);
|
|
7168
7237
|
}
|
|
7169
7238
|
function validateWorkspace(value, label) {
|
|
7170
7239
|
if (typeof value !== "string" || wsFromBranch(value) !== value) {
|
|
@@ -7192,7 +7261,7 @@ function validateRecord(value, expectedWorkspace) {
|
|
|
7192
7261
|
`workspace ownership file '${expectedWorkspace}' contains identity '${workspace}'`
|
|
7193
7262
|
);
|
|
7194
7263
|
}
|
|
7195
|
-
if (typeof candidate.worktreePath !== "string" || !
|
|
7264
|
+
if (typeof candidate.worktreePath !== "string" || !import_node_path20.default.isAbsolute(candidate.worktreePath)) {
|
|
7196
7265
|
throw new Error("invalid workspace ownership worktreePath");
|
|
7197
7266
|
}
|
|
7198
7267
|
if (candidate.branch !== null && typeof candidate.branch !== "string") {
|
|
@@ -7212,7 +7281,7 @@ function validateRecord(value, expectedWorkspace) {
|
|
|
7212
7281
|
function readRecordFile(filePath, expectedWorkspace) {
|
|
7213
7282
|
let parsed;
|
|
7214
7283
|
try {
|
|
7215
|
-
parsed = JSON.parse(
|
|
7284
|
+
parsed = JSON.parse(import_node_fs21.default.readFileSync(filePath, "utf-8"));
|
|
7216
7285
|
} catch (error) {
|
|
7217
7286
|
if (error instanceof SyntaxError) {
|
|
7218
7287
|
throw new Error(`invalid workspace ownership JSON at '${filePath}'`);
|
|
@@ -7228,7 +7297,7 @@ function listWorkspaceOwnership(repoPath) {
|
|
|
7228
7297
|
function listWorkspaceOwnershipInDirectory(directory) {
|
|
7229
7298
|
let entries;
|
|
7230
7299
|
try {
|
|
7231
|
-
entries =
|
|
7300
|
+
entries = import_node_fs21.default.readdirSync(directory, { withFileTypes: true });
|
|
7232
7301
|
} catch (error) {
|
|
7233
7302
|
if (error.code === "ENOENT") return [];
|
|
7234
7303
|
throw error;
|
|
@@ -7236,14 +7305,14 @@ function listWorkspaceOwnershipInDirectory(directory) {
|
|
|
7236
7305
|
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).sort((left, right) => left.name.localeCompare(right.name)).map((entry) => {
|
|
7237
7306
|
const workspace = entry.name.slice(0, -".json".length);
|
|
7238
7307
|
validateWorkspace(workspace, "filename");
|
|
7239
|
-
return readRecordFile(
|
|
7308
|
+
return readRecordFile(import_node_path20.default.join(directory, entry.name), workspace);
|
|
7240
7309
|
});
|
|
7241
7310
|
}
|
|
7242
7311
|
function writeWorkspaceOwnershipInDirectory(directory, input2) {
|
|
7243
7312
|
const workspace = validateWorkspace(input2.workspace, "workspace");
|
|
7244
7313
|
const devpodId = validateWorkspace(input2.devpodId, "devpodId");
|
|
7245
7314
|
const worktreePath = comparableWorkspacePath(input2.worktreePath);
|
|
7246
|
-
const filePath =
|
|
7315
|
+
const filePath = import_node_path20.default.join(directory, `${workspace}.json`);
|
|
7247
7316
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7248
7317
|
const records = listWorkspaceOwnershipInDirectory(directory);
|
|
7249
7318
|
const existing = records.find((record2) => record2.workspace === workspace);
|
|
@@ -7279,9 +7348,9 @@ function writeWorkspaceOwnershipInDirectory(directory, input2) {
|
|
|
7279
7348
|
return record;
|
|
7280
7349
|
}
|
|
7281
7350
|
function removeWorkspaceOwnershipInDirectory(directory, workspace) {
|
|
7282
|
-
const filePath =
|
|
7351
|
+
const filePath = import_node_path20.default.join(directory, `${validateWorkspace(workspace, "workspace")}.json`);
|
|
7283
7352
|
try {
|
|
7284
|
-
|
|
7353
|
+
import_node_fs21.default.rmSync(filePath);
|
|
7285
7354
|
return true;
|
|
7286
7355
|
} catch (error) {
|
|
7287
7356
|
if (error.code === "ENOENT") return false;
|
|
@@ -7292,7 +7361,7 @@ function sameOwnershipRecord(left, right) {
|
|
|
7292
7361
|
return left.version === right.version && left.workspace === right.workspace && sameWorkspacePath(left.worktreePath, right.worktreePath) && left.branch === right.branch && left.devpodId === right.devpodId && left.createdAt === right.createdAt && left.updatedAt === right.updatedAt;
|
|
7293
7362
|
}
|
|
7294
7363
|
function removeWorkspaceOwnershipIfMatchesInDirectory(directory, expected) {
|
|
7295
|
-
const filePath =
|
|
7364
|
+
const filePath = import_node_path20.default.join(
|
|
7296
7365
|
directory,
|
|
7297
7366
|
`${validateWorkspace(expected.workspace, "workspace")}.json`
|
|
7298
7367
|
);
|
|
@@ -7304,14 +7373,14 @@ function removeWorkspaceOwnershipIfMatchesInDirectory(directory, expected) {
|
|
|
7304
7373
|
throw error;
|
|
7305
7374
|
}
|
|
7306
7375
|
if (!sameOwnershipRecord(current, expected)) return "changed";
|
|
7307
|
-
|
|
7376
|
+
import_node_fs21.default.rmSync(filePath);
|
|
7308
7377
|
return "removed";
|
|
7309
7378
|
}
|
|
7310
7379
|
function withWorkspaceOwnershipTransaction(repoPath, operation) {
|
|
7311
7380
|
const directory = ownershipDirectory(repoPath);
|
|
7312
|
-
|
|
7381
|
+
import_node_fs21.default.mkdirSync(directory, { recursive: true });
|
|
7313
7382
|
return withFileLockSync(
|
|
7314
|
-
|
|
7383
|
+
import_node_path20.default.join(directory, ".lock"),
|
|
7315
7384
|
{ activity: "workspace ownership transaction", target: `'${repoPath}'`, waitMs: 5e3 },
|
|
7316
7385
|
() => operation({
|
|
7317
7386
|
list: () => listWorkspaceOwnershipInDirectory(directory),
|
|
@@ -7342,7 +7411,7 @@ function inspectWorkspaceOwnership(record, worktrees, devpods) {
|
|
|
7342
7411
|
if (worktree?.locked) {
|
|
7343
7412
|
return { ownerStatus: "locked", devpodStatus, worktree };
|
|
7344
7413
|
}
|
|
7345
|
-
if ((!worktree || worktree.prunable) &&
|
|
7414
|
+
if ((!worktree || worktree.prunable) && import_node_fs21.default.existsSync(record.worktreePath)) {
|
|
7346
7415
|
return { ownerStatus: "conflict", devpodStatus, worktree };
|
|
7347
7416
|
}
|
|
7348
7417
|
if (!worktree || worktree.prunable) {
|
|
@@ -7366,20 +7435,20 @@ function listMissingWorkspaceOwnership(repoPath) {
|
|
|
7366
7435
|
(record) => inspectWorkspaceOwnership(record, worktrees, void 0).ownerStatus === "missing"
|
|
7367
7436
|
);
|
|
7368
7437
|
}
|
|
7369
|
-
var import_node_child_process16,
|
|
7438
|
+
var import_node_child_process16, import_node_fs21, import_node_path20, READ_ONLY_GIT_ENV, OWNERSHIP_VERSION, OWNERSHIP_DIR;
|
|
7370
7439
|
var init_workspace_ownership = __esm({
|
|
7371
7440
|
"src/core/workspace-ownership.ts"() {
|
|
7372
7441
|
"use strict";
|
|
7373
7442
|
import_node_child_process16 = require("child_process");
|
|
7374
|
-
|
|
7375
|
-
|
|
7443
|
+
import_node_fs21 = __toESM(require("fs"));
|
|
7444
|
+
import_node_path20 = __toESM(require("path"));
|
|
7376
7445
|
init_atomic_file();
|
|
7377
7446
|
init_devpod_workspaces();
|
|
7378
7447
|
init_file_lock();
|
|
7379
7448
|
init_workspace();
|
|
7380
7449
|
READ_ONLY_GIT_ENV = { ...process.env, GIT_OPTIONAL_LOCKS: "0" };
|
|
7381
7450
|
OWNERSHIP_VERSION = 1;
|
|
7382
|
-
OWNERSHIP_DIR =
|
|
7451
|
+
OWNERSHIP_DIR = import_node_path20.default.join("devrouter", "workspaces");
|
|
7383
7452
|
}
|
|
7384
7453
|
});
|
|
7385
7454
|
|
|
@@ -7393,10 +7462,10 @@ function inRepositoryWorkspaceScope(repoPath, worktreePath, livePaths) {
|
|
|
7393
7462
|
if (livePaths.some((candidate) => sameWorkspacePath(candidate, worktreePath))) return true;
|
|
7394
7463
|
const comparableRepo = comparableWorkspacePath(repoPath);
|
|
7395
7464
|
const comparableWorktree = comparableWorkspacePath(worktreePath);
|
|
7396
|
-
const localRoot =
|
|
7465
|
+
const localRoot = import_node_path21.default.join(comparableRepo, "trees") + import_node_path21.default.sep;
|
|
7397
7466
|
if (comparableWorktree.startsWith(localRoot)) return true;
|
|
7398
|
-
const legacyPrefix = `${
|
|
7399
|
-
return
|
|
7467
|
+
const legacyPrefix = `${import_node_path21.default.basename(comparableRepo)}-`;
|
|
7468
|
+
return import_node_path21.default.dirname(comparableWorktree) === import_node_path21.default.dirname(comparableRepo) && import_node_path21.default.basename(comparableWorktree).startsWith(legacyPrefix);
|
|
7400
7469
|
}
|
|
7401
7470
|
function previewActions(devpodStatus, routeCount, includeRecord) {
|
|
7402
7471
|
const actions = [
|
|
@@ -7648,11 +7717,11 @@ function applyWorkspaceGc(plan) {
|
|
|
7648
7717
|
candidates
|
|
7649
7718
|
};
|
|
7650
7719
|
}
|
|
7651
|
-
var
|
|
7720
|
+
var import_node_path21;
|
|
7652
7721
|
var init_workspace_gc = __esm({
|
|
7653
7722
|
"src/core/workspace-gc.ts"() {
|
|
7654
7723
|
"use strict";
|
|
7655
|
-
|
|
7724
|
+
import_node_path21 = __toESM(require("path"));
|
|
7656
7725
|
init_devpod_mutation();
|
|
7657
7726
|
init_devpod_workspaces();
|
|
7658
7727
|
init_host_routes();
|
|
@@ -7722,11 +7791,11 @@ function inspectPostgresCredentials(repoPath, config) {
|
|
|
7722
7791
|
parseErrors.push(`${app.name}: ${composeFile} (${message})`);
|
|
7723
7792
|
continue;
|
|
7724
7793
|
}
|
|
7725
|
-
if (!
|
|
7794
|
+
if (!import_node_fs22.default.existsSync(absolutePath)) {
|
|
7726
7795
|
continue;
|
|
7727
7796
|
}
|
|
7728
7797
|
try {
|
|
7729
|
-
const raw =
|
|
7798
|
+
const raw = import_node_fs22.default.readFileSync(absolutePath, "utf-8");
|
|
7730
7799
|
const parsed = import_yaml5.default.parse(raw);
|
|
7731
7800
|
const root = asRecord2(parsed);
|
|
7732
7801
|
const services = asRecord2(root?.services);
|
|
@@ -8005,7 +8074,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
8005
8074
|
const config = runtimeConfig.config;
|
|
8006
8075
|
loadedConfig = config;
|
|
8007
8076
|
loadedWorkspace = runtimeConfig.workspace;
|
|
8008
|
-
const cliVersion = true ? "0.0.
|
|
8077
|
+
const cliVersion = true ? "0.0.43" : "0.0.0-dev";
|
|
8009
8078
|
const configVersion = config.devrouter?.version;
|
|
8010
8079
|
if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
|
|
8011
8080
|
addCheck(checks, {
|
|
@@ -8035,9 +8104,9 @@ async function buildDoctorReport(options = {}) {
|
|
|
8035
8104
|
(app) => app.docker.composeFiles.map((filePath) => ({
|
|
8036
8105
|
app: app.name,
|
|
8037
8106
|
filePath,
|
|
8038
|
-
absolutePath:
|
|
8107
|
+
absolutePath: import_node_path22.default.resolve(repo.path, filePath)
|
|
8039
8108
|
}))
|
|
8040
|
-
).filter((entry) => !
|
|
8109
|
+
).filter((entry) => !import_node_fs22.default.existsSync(entry.absolutePath));
|
|
8041
8110
|
addCheck(checks, {
|
|
8042
8111
|
id: "repo.compose-files",
|
|
8043
8112
|
level: missingComposeFiles.length === 0 ? "ok" : "error",
|
|
@@ -8080,8 +8149,8 @@ async function buildDoctorReport(options = {}) {
|
|
|
8080
8149
|
const missingHostCwds = config.apps.filter((app) => app.runtime === "host").map((app) => ({
|
|
8081
8150
|
app: app.name,
|
|
8082
8151
|
cwd: app.hostRun.cwd,
|
|
8083
|
-
absolutePath:
|
|
8084
|
-
})).filter((entry) => !
|
|
8152
|
+
absolutePath: import_node_path22.default.resolve(repo.path, app.hostRun.cwd)
|
|
8153
|
+
})).filter((entry) => !import_node_fs22.default.existsSync(entry.absolutePath));
|
|
8085
8154
|
addCheck(checks, {
|
|
8086
8155
|
id: "repo.host-cwd",
|
|
8087
8156
|
level: missingHostCwds.length === 0 ? "ok" : "error",
|
|
@@ -8225,12 +8294,12 @@ async function buildDoctorReport(options = {}) {
|
|
|
8225
8294
|
nextSteps
|
|
8226
8295
|
};
|
|
8227
8296
|
}
|
|
8228
|
-
var
|
|
8297
|
+
var import_node_fs22, import_node_path22, import_yaml5, POSTGRES_DEFAULTS;
|
|
8229
8298
|
var init_doctor = __esm({
|
|
8230
8299
|
"src/core/doctor.ts"() {
|
|
8231
8300
|
"use strict";
|
|
8232
|
-
|
|
8233
|
-
|
|
8301
|
+
import_node_fs22 = __toESM(require("fs"));
|
|
8302
|
+
import_node_path22 = __toESM(require("path"));
|
|
8234
8303
|
import_yaml5 = __toESM(require("yaml"));
|
|
8235
8304
|
init_docker();
|
|
8236
8305
|
init_host_routes();
|
|
@@ -8725,11 +8794,11 @@ var init_route_publication = __esm({
|
|
|
8725
8794
|
// src/core/workspace-ensure.ts
|
|
8726
8795
|
function assertOverlay(container, repoPath) {
|
|
8727
8796
|
const workingDir = container.labels["com.docker.compose.project.working_dir"];
|
|
8728
|
-
if (!workingDir || !sameWorkspacePath(workingDir,
|
|
8797
|
+
if (!workingDir || !sameWorkspacePath(workingDir, import_node_path23.default.join(repoPath, ".devcontainer"))) {
|
|
8729
8798
|
throw new Error(`Container '${container.id}' does not belong to the exact worktree.`);
|
|
8730
8799
|
}
|
|
8731
8800
|
const configFiles = (container.labels["com.docker.compose.project.config_files"] ?? "").split(",").filter(Boolean);
|
|
8732
|
-
const expectedOverlay =
|
|
8801
|
+
const expectedOverlay = import_node_path23.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
|
|
8733
8802
|
if (!configFiles.some((configFile) => sameWorkspacePath(configFile, expectedOverlay))) {
|
|
8734
8803
|
throw new Error(`Container '${container.id}' was not started with ${DEVCONTAINER_OVERLAY}.`);
|
|
8735
8804
|
}
|
|
@@ -9114,7 +9183,7 @@ function resolvePrimaryTarget(repoPath) {
|
|
|
9114
9183
|
}
|
|
9115
9184
|
function isPrimaryCheckout(repoPath) {
|
|
9116
9185
|
try {
|
|
9117
|
-
return
|
|
9186
|
+
return import_node_fs23.default.statSync(import_node_path23.default.join(repoPath, ".git")).isDirectory();
|
|
9118
9187
|
} catch {
|
|
9119
9188
|
return false;
|
|
9120
9189
|
}
|
|
@@ -9164,8 +9233,8 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
9164
9233
|
const target = linked ? resolveLinkedTarget(repoPath) : resolvePrimaryTarget(repoPath);
|
|
9165
9234
|
let devpodId = target.devpodId;
|
|
9166
9235
|
if (target.kind === "linked") {
|
|
9167
|
-
const overlayPath =
|
|
9168
|
-
if (!
|
|
9236
|
+
const overlayPath = import_node_path23.default.join(repoPath, ".devcontainer", DEVCONTAINER_OVERLAY);
|
|
9237
|
+
if (!import_node_fs23.default.existsSync(overlayPath)) {
|
|
9169
9238
|
throw new Error(`Missing required DevPod compose overlay: ${overlayPath}`);
|
|
9170
9239
|
}
|
|
9171
9240
|
}
|
|
@@ -9232,7 +9301,7 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
9232
9301
|
}
|
|
9233
9302
|
const apps = proxyAppsFromConfig(runtime.config);
|
|
9234
9303
|
const parsedUpstreams = apps.map((app) => parseUpstream(app.upstream));
|
|
9235
|
-
const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ??
|
|
9304
|
+
const aliasPrefix = target.kind === "linked" ? target.workspace : wsFromBranch(runtime.config.project?.name ?? import_node_path23.default.basename(repoPath)) ?? "app";
|
|
9236
9305
|
for (const [index, app] of apps.entries()) {
|
|
9237
9306
|
if (!parsedUpstreams[index].host.startsWith(`${aliasPrefix}-`)) {
|
|
9238
9307
|
const owner = target.kind === "linked" ? "workspace" : "checkout";
|
|
@@ -9676,13 +9745,13 @@ async function workspaceEnsure(requestedRepoPath, options = {}) {
|
|
|
9676
9745
|
}
|
|
9677
9746
|
});
|
|
9678
9747
|
}
|
|
9679
|
-
var import_node_child_process19,
|
|
9748
|
+
var import_node_child_process19, import_node_fs23, import_node_path23, DEVCONTAINER_OVERLAY, DEFAULT_READINESS_TIMEOUT_MS, POLL_INTERVAL_MS;
|
|
9680
9749
|
var init_workspace_ensure = __esm({
|
|
9681
9750
|
"src/core/workspace-ensure.ts"() {
|
|
9682
9751
|
"use strict";
|
|
9683
9752
|
import_node_child_process19 = require("child_process");
|
|
9684
|
-
|
|
9685
|
-
|
|
9753
|
+
import_node_fs23 = __toESM(require("fs"));
|
|
9754
|
+
import_node_path23 = __toESM(require("path"));
|
|
9686
9755
|
init_devcontainer_profile();
|
|
9687
9756
|
init_devpod_environment();
|
|
9688
9757
|
init_devpod_mutation();
|
|
@@ -9762,7 +9831,7 @@ function warnMissingWorkspaceOwnership(repoPath) {
|
|
|
9762
9831
|
);
|
|
9763
9832
|
}
|
|
9764
9833
|
function defaultWorktreePath(mainRepo, ws) {
|
|
9765
|
-
return
|
|
9834
|
+
return import_node_path24.default.join(mainRepo, "trees", ws);
|
|
9766
9835
|
}
|
|
9767
9836
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
9768
9837
|
const ignored = (0, import_node_child_process20.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
@@ -9770,12 +9839,12 @@ function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
|
9770
9839
|
});
|
|
9771
9840
|
if (ignored.status !== 0) {
|
|
9772
9841
|
throw new Error(
|
|
9773
|
-
`Default worktree root '${
|
|
9842
|
+
`Default worktree root '${import_node_path24.default.join(mainRepo, "trees")}' is not ignored. Add 'trees/' to '${import_node_path24.default.join(mainRepo, ".gitignore")}' or use --path.`
|
|
9774
9843
|
);
|
|
9775
9844
|
}
|
|
9776
9845
|
}
|
|
9777
9846
|
function legacyDefaultWorktreePath(mainRepo, ws) {
|
|
9778
|
-
return
|
|
9847
|
+
return import_node_path24.default.join(import_node_path24.default.dirname(mainRepo), `${import_node_path24.default.basename(mainRepo)}-${ws}`);
|
|
9779
9848
|
}
|
|
9780
9849
|
function teardownFallbackPath(mainRepo, workspace) {
|
|
9781
9850
|
const candidates = [
|
|
@@ -9887,7 +9956,7 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
9887
9956
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
9888
9957
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
9889
9958
|
}
|
|
9890
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
9959
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs24.default.existsSync(target.worktreePath)) return;
|
|
9891
9960
|
if (target.worktree.locked) {
|
|
9892
9961
|
throw new Error(
|
|
9893
9962
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
@@ -9914,8 +9983,8 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
9914
9983
|
if (!ws) {
|
|
9915
9984
|
throw new Error(`Branch '${branch}' does not yield a valid workspace token.`);
|
|
9916
9985
|
}
|
|
9917
|
-
const worktreePath = opts.path ?
|
|
9918
|
-
if (
|
|
9986
|
+
const worktreePath = opts.path ? import_node_path24.default.resolve(opts.path) : defaultWorktreePath(mainRepo, ws);
|
|
9987
|
+
if (import_node_fs24.default.existsSync(worktreePath)) {
|
|
9919
9988
|
const registered = listGitWorktrees(mainRepo).find(
|
|
9920
9989
|
(worktree) => sameWorkspacePath(worktree.path, worktreePath)
|
|
9921
9990
|
);
|
|
@@ -10040,7 +10109,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
10040
10109
|
opts.quiet
|
|
10041
10110
|
);
|
|
10042
10111
|
if (removeWorktree) {
|
|
10043
|
-
if (resolved.worktree && !resolved.worktree.prunable &&
|
|
10112
|
+
if (resolved.worktree && !resolved.worktree.prunable && import_node_fs24.default.existsSync(resolved.worktreePath)) {
|
|
10044
10113
|
const rm = (0, import_node_child_process20.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved.worktreePath], {
|
|
10045
10114
|
encoding: "utf-8"
|
|
10046
10115
|
});
|
|
@@ -10059,7 +10128,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
10059
10128
|
}
|
|
10060
10129
|
return result;
|
|
10061
10130
|
};
|
|
10062
|
-
return resolved.worktree && !resolved.worktree.prunable &&
|
|
10131
|
+
return resolved.worktree && !resolved.worktree.prunable && import_node_fs24.default.existsSync(resolved.worktreePath) ? withWorkspaceLifecycleLock(resolved.worktreePath, operation) : operation();
|
|
10063
10132
|
}
|
|
10064
10133
|
async function mutateWorkspaceOwnedPath(action2, worktreePath, opts = {}) {
|
|
10065
10134
|
const mainRepo = resolveRepoPath(opts.repoPath);
|
|
@@ -10094,13 +10163,13 @@ async function workspaceStop(target, opts = {}) {
|
|
|
10094
10163
|
async function workspaceDown(target, opts = {}) {
|
|
10095
10164
|
return runWorkspaceLifecycle("down", target, opts);
|
|
10096
10165
|
}
|
|
10097
|
-
var import_node_child_process20,
|
|
10166
|
+
var import_node_child_process20, import_node_fs24, import_node_path24;
|
|
10098
10167
|
var init_workspace_lifecycle = __esm({
|
|
10099
10168
|
"src/core/workspace-lifecycle.ts"() {
|
|
10100
10169
|
"use strict";
|
|
10101
10170
|
import_node_child_process20 = require("child_process");
|
|
10102
|
-
|
|
10103
|
-
|
|
10171
|
+
import_node_fs24 = __toESM(require("fs"));
|
|
10172
|
+
import_node_path24 = __toESM(require("path"));
|
|
10104
10173
|
init_devpod_mutation();
|
|
10105
10174
|
init_devpod_workspaces();
|
|
10106
10175
|
init_repo_config();
|
|
@@ -10668,17 +10737,17 @@ function asRecord3(value) {
|
|
|
10668
10737
|
return value;
|
|
10669
10738
|
}
|
|
10670
10739
|
function readJson(filePath) {
|
|
10671
|
-
if (!
|
|
10740
|
+
if (!import_node_fs25.default.existsSync(filePath)) {
|
|
10672
10741
|
return void 0;
|
|
10673
10742
|
}
|
|
10674
10743
|
try {
|
|
10675
|
-
return JSON.parse(
|
|
10744
|
+
return JSON.parse(import_node_fs25.default.readFileSync(filePath, "utf-8"));
|
|
10676
10745
|
} catch {
|
|
10677
10746
|
return void 0;
|
|
10678
10747
|
}
|
|
10679
10748
|
}
|
|
10680
10749
|
function relative(repoPath, filePath) {
|
|
10681
|
-
return
|
|
10750
|
+
return import_node_path25.default.relative(repoPath, filePath) || ".";
|
|
10682
10751
|
}
|
|
10683
10752
|
function redactEnvAssignments(value) {
|
|
10684
10753
|
return value.replace(
|
|
@@ -10719,7 +10788,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
10719
10788
|
["bun.lock", "bun"]
|
|
10720
10789
|
];
|
|
10721
10790
|
for (const [fileName, name] of lockfiles) {
|
|
10722
|
-
if (
|
|
10791
|
+
if (import_node_fs25.default.existsSync(import_node_path25.default.join(repoPath, fileName))) {
|
|
10723
10792
|
return { name, source: fileName };
|
|
10724
10793
|
}
|
|
10725
10794
|
}
|
|
@@ -10734,9 +10803,9 @@ function inspectNode(repoPath, pkg) {
|
|
|
10734
10803
|
if (typeof engines?.node === "string") {
|
|
10735
10804
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
10736
10805
|
}
|
|
10737
|
-
const nvmrc =
|
|
10738
|
-
if (
|
|
10739
|
-
const version =
|
|
10806
|
+
const nvmrc = import_node_path25.default.join(repoPath, ".nvmrc");
|
|
10807
|
+
if (import_node_fs25.default.existsSync(nvmrc)) {
|
|
10808
|
+
const version = import_node_fs25.default.readFileSync(nvmrc, "utf-8").trim();
|
|
10740
10809
|
return { version, source: ".nvmrc" };
|
|
10741
10810
|
}
|
|
10742
10811
|
return void 0;
|
|
@@ -10797,7 +10866,7 @@ function configuredComposeFiles(repoPath) {
|
|
|
10797
10866
|
const files = config.apps.filter(
|
|
10798
10867
|
(app) => app.runtime === "docker"
|
|
10799
10868
|
).flatMap((app) => app.docker.composeFiles).filter(
|
|
10800
|
-
(fileName) => !
|
|
10869
|
+
(fileName) => !import_node_path25.default.isAbsolute(fileName) && !import_node_path25.default.normalize(fileName).startsWith("..")
|
|
10801
10870
|
);
|
|
10802
10871
|
return Array.from(new Set(files));
|
|
10803
10872
|
} catch {
|
|
@@ -10815,7 +10884,7 @@ function composeFiles(repoPath) {
|
|
|
10815
10884
|
...configuredComposeFiles(repoPath)
|
|
10816
10885
|
];
|
|
10817
10886
|
return Array.from(new Set(candidates)).filter(
|
|
10818
|
-
(fileName) =>
|
|
10887
|
+
(fileName) => import_node_fs25.default.existsSync(import_node_path25.default.join(repoPath, fileName))
|
|
10819
10888
|
);
|
|
10820
10889
|
}
|
|
10821
10890
|
function stringArray2(value) {
|
|
@@ -10853,7 +10922,7 @@ function inspectServices(repoPath) {
|
|
|
10853
10922
|
const services = [];
|
|
10854
10923
|
for (const fileName of composeFiles(repoPath)) {
|
|
10855
10924
|
try {
|
|
10856
|
-
const parsed = import_yaml6.default.parse(
|
|
10925
|
+
const parsed = import_yaml6.default.parse(import_node_fs25.default.readFileSync(import_node_path25.default.join(repoPath, fileName), "utf-8"));
|
|
10857
10926
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
10858
10927
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
10859
10928
|
const service = asRecord3(value);
|
|
@@ -10888,8 +10957,8 @@ function inspectServices(repoPath) {
|
|
|
10888
10957
|
return services;
|
|
10889
10958
|
}
|
|
10890
10959
|
function inspectEnvFiles(repoPath) {
|
|
10891
|
-
const files =
|
|
10892
|
-
const content =
|
|
10960
|
+
const files = import_node_fs25.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
10961
|
+
const content = import_node_fs25.default.readFileSync(import_node_path25.default.join(repoPath, fileName), "utf-8");
|
|
10893
10962
|
const names = content.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#") && line.includes("=")).map((line) => line.split("=")[0]?.trim()).filter((name) => Boolean(name)).sort();
|
|
10894
10963
|
return { path: fileName, names };
|
|
10895
10964
|
});
|
|
@@ -10903,18 +10972,18 @@ function inspectEnvFiles(repoPath) {
|
|
|
10903
10972
|
};
|
|
10904
10973
|
}
|
|
10905
10974
|
function inspectDevcontainer(repoPath) {
|
|
10906
|
-
const dir =
|
|
10907
|
-
if (!
|
|
10975
|
+
const dir = import_node_path25.default.join(repoPath, ".devcontainer");
|
|
10976
|
+
if (!import_node_fs25.default.existsSync(dir)) {
|
|
10908
10977
|
return { exists: false, files: [] };
|
|
10909
10978
|
}
|
|
10910
10979
|
return {
|
|
10911
10980
|
exists: true,
|
|
10912
|
-
files:
|
|
10981
|
+
files: import_node_fs25.default.readdirSync(dir).filter((fileName) => import_node_fs25.default.statSync(import_node_path25.default.join(dir, fileName)).isFile()).sort().map((fileName) => `.devcontainer/${fileName}`)
|
|
10913
10982
|
};
|
|
10914
10983
|
}
|
|
10915
10984
|
function inspectDevrouter(repoPath) {
|
|
10916
10985
|
const configPath = getRepoConfigPath(repoPath);
|
|
10917
|
-
if (!
|
|
10986
|
+
if (!import_node_fs25.default.existsSync(configPath)) {
|
|
10918
10987
|
return {
|
|
10919
10988
|
exists: false,
|
|
10920
10989
|
configPath,
|
|
@@ -10958,15 +11027,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
10958
11027
|
["AGENTS.md", "agents"],
|
|
10959
11028
|
["CLAUDE.md", "claude"]
|
|
10960
11029
|
]) {
|
|
10961
|
-
if (
|
|
11030
|
+
if (import_node_fs25.default.existsSync(import_node_path25.default.join(repoPath, fileName))) {
|
|
10962
11031
|
results.push({ path: fileName, kind });
|
|
10963
11032
|
}
|
|
10964
11033
|
}
|
|
10965
|
-
const skillsDir =
|
|
10966
|
-
if (
|
|
10967
|
-
for (const name of
|
|
10968
|
-
const skillPath =
|
|
10969
|
-
if (
|
|
11034
|
+
const skillsDir = import_node_path25.default.join(repoPath, ".agents", "skills");
|
|
11035
|
+
if (import_node_fs25.default.existsSync(skillsDir)) {
|
|
11036
|
+
for (const name of import_node_fs25.default.readdirSync(skillsDir).sort()) {
|
|
11037
|
+
const skillPath = import_node_path25.default.join(skillsDir, name, "SKILL.md");
|
|
11038
|
+
if (import_node_fs25.default.existsSync(skillPath)) {
|
|
10970
11039
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
10971
11040
|
}
|
|
10972
11041
|
}
|
|
@@ -11009,7 +11078,7 @@ function buildIssues(report) {
|
|
|
11009
11078
|
}
|
|
11010
11079
|
function inspectRepo(options = {}) {
|
|
11011
11080
|
const repoPath = resolveRepoPath(options.repo);
|
|
11012
|
-
const pkg = readJson(
|
|
11081
|
+
const pkg = readJson(import_node_path25.default.join(repoPath, "package.json"));
|
|
11013
11082
|
const scripts = inspectScripts(pkg);
|
|
11014
11083
|
const reportWithoutIssues = {
|
|
11015
11084
|
repoPath,
|
|
@@ -11028,12 +11097,12 @@ function inspectRepo(options = {}) {
|
|
|
11028
11097
|
issues: buildIssues(reportWithoutIssues)
|
|
11029
11098
|
};
|
|
11030
11099
|
}
|
|
11031
|
-
var
|
|
11100
|
+
var import_node_fs25, import_node_path25, import_yaml6;
|
|
11032
11101
|
var init_repo_inspect = __esm({
|
|
11033
11102
|
"src/core/repo-inspect.ts"() {
|
|
11034
11103
|
"use strict";
|
|
11035
|
-
|
|
11036
|
-
|
|
11104
|
+
import_node_fs25 = __toESM(require("fs"));
|
|
11105
|
+
import_node_path25 = __toESM(require("path"));
|
|
11037
11106
|
import_yaml6 = __toESM(require("yaml"));
|
|
11038
11107
|
init_repo_config();
|
|
11039
11108
|
}
|
|
@@ -11138,7 +11207,7 @@ function requiredFileChecks(repoPath) {
|
|
|
11138
11207
|
".devcontainer/docker-compose.yml",
|
|
11139
11208
|
".devrouter.yml"
|
|
11140
11209
|
];
|
|
11141
|
-
const missing = required.filter((fileName) => !
|
|
11210
|
+
const missing = required.filter((fileName) => !import_node_fs26.default.existsSync(import_node_path26.default.join(repoPath, fileName)));
|
|
11142
11211
|
return {
|
|
11143
11212
|
id: "repo.devcontainer.verify-files",
|
|
11144
11213
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -11357,12 +11426,12 @@ async function verifyDevcontainer(options = {}) {
|
|
|
11357
11426
|
nextSteps: collectNextSteps3(checks)
|
|
11358
11427
|
};
|
|
11359
11428
|
}
|
|
11360
|
-
var
|
|
11429
|
+
var import_node_fs26, import_node_path26;
|
|
11361
11430
|
var init_devcontainer_verify = __esm({
|
|
11362
11431
|
"src/core/devcontainer-verify.ts"() {
|
|
11363
11432
|
"use strict";
|
|
11364
|
-
|
|
11365
|
-
|
|
11433
|
+
import_node_fs26 = __toESM(require("fs"));
|
|
11434
|
+
import_node_path26 = __toESM(require("path"));
|
|
11366
11435
|
init_capabilities();
|
|
11367
11436
|
init_doctor();
|
|
11368
11437
|
init_host_routes();
|
|
@@ -11508,6 +11577,7 @@ function renderDevcontainerJson(projectName) {
|
|
|
11508
11577
|
"service": "app",
|
|
11509
11578
|
"workspaceFolder": "/workspaces/${projectName}",
|
|
11510
11579
|
"postCreateCommand": "bash .devcontainer/post-create.sh",
|
|
11580
|
+
"waitFor": "postCreateCommand",
|
|
11511
11581
|
"customizations": {
|
|
11512
11582
|
"devrouter": {
|
|
11513
11583
|
"managed": "${MANAGED_MARKER2}"
|
|
@@ -11658,7 +11728,7 @@ function packageManagerIssues(repo) {
|
|
|
11658
11728
|
}
|
|
11659
11729
|
function plannedFiles(repoPath, version) {
|
|
11660
11730
|
const repo = inspectRepo({ repo: repoPath });
|
|
11661
|
-
const projectName = sanitizeProjectName(
|
|
11731
|
+
const projectName = sanitizeProjectName(import_node_path27.default.basename(repo.repoPath));
|
|
11662
11732
|
const nodeMajor = majorVersion(repo.node?.version, "24");
|
|
11663
11733
|
const pnpmVersion = repo.packageManager?.name === "pnpm" && repo.packageManager.version ? repo.packageManager.version : DEFAULT_PNPM_VERSION;
|
|
11664
11734
|
const port = inferPort2(repo);
|
|
@@ -11703,8 +11773,8 @@ function plannedFiles(repoPath, version) {
|
|
|
11703
11773
|
};
|
|
11704
11774
|
}
|
|
11705
11775
|
function classifyFile(repoPath, file) {
|
|
11706
|
-
const absolutePath =
|
|
11707
|
-
if (!
|
|
11776
|
+
const absolutePath = import_node_path27.default.join(repoPath, file.relativePath);
|
|
11777
|
+
if (!import_node_fs27.default.existsSync(absolutePath)) {
|
|
11708
11778
|
return {
|
|
11709
11779
|
path: file.relativePath,
|
|
11710
11780
|
action: "create",
|
|
@@ -11712,7 +11782,7 @@ function classifyFile(repoPath, file) {
|
|
|
11712
11782
|
bytes: Buffer.byteLength(file.content)
|
|
11713
11783
|
};
|
|
11714
11784
|
}
|
|
11715
|
-
const current =
|
|
11785
|
+
const current = import_node_fs27.default.readFileSync(absolutePath, "utf-8");
|
|
11716
11786
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
11717
11787
|
return {
|
|
11718
11788
|
path: file.relativePath,
|
|
@@ -11769,11 +11839,11 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
11769
11839
|
};
|
|
11770
11840
|
}
|
|
11771
11841
|
function writeFile(repoPath, file) {
|
|
11772
|
-
const absolutePath =
|
|
11773
|
-
|
|
11774
|
-
|
|
11842
|
+
const absolutePath = import_node_path27.default.join(repoPath, file.relativePath);
|
|
11843
|
+
import_node_fs27.default.mkdirSync(import_node_path27.default.dirname(absolutePath), { recursive: true });
|
|
11844
|
+
import_node_fs27.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
11775
11845
|
if (file.executable) {
|
|
11776
|
-
|
|
11846
|
+
import_node_fs27.default.chmodSync(absolutePath, 493);
|
|
11777
11847
|
}
|
|
11778
11848
|
}
|
|
11779
11849
|
function writeDevcontainer(options = {}) {
|
|
@@ -11811,12 +11881,12 @@ function writeDevcontainer(options = {}) {
|
|
|
11811
11881
|
nextSteps: postWriteNextSteps(repoPath)
|
|
11812
11882
|
};
|
|
11813
11883
|
}
|
|
11814
|
-
var
|
|
11884
|
+
var import_node_fs27, import_node_path27, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
11815
11885
|
var init_devcontainer_write = __esm({
|
|
11816
11886
|
"src/core/devcontainer-write.ts"() {
|
|
11817
11887
|
"use strict";
|
|
11818
|
-
|
|
11819
|
-
|
|
11888
|
+
import_node_fs27 = __toESM(require("fs"));
|
|
11889
|
+
import_node_path27 = __toESM(require("path"));
|
|
11820
11890
|
init_repo_config();
|
|
11821
11891
|
init_repo_inspect();
|
|
11822
11892
|
MANAGED_MARKER2 = "devrouter:managed devcontainer";
|
|
@@ -12207,7 +12277,7 @@ function sanitizeRouterId(value) {
|
|
|
12207
12277
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
12208
12278
|
}
|
|
12209
12279
|
function repoHash(repoPath) {
|
|
12210
|
-
return (0, import_node_crypto8.createHash)("sha1").update(
|
|
12280
|
+
return (0, import_node_crypto8.createHash)("sha1").update(import_node_path28.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
12211
12281
|
}
|
|
12212
12282
|
function asDockerApp(app) {
|
|
12213
12283
|
return app.runtime === "docker";
|
|
@@ -12286,11 +12356,11 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
12286
12356
|
if (dockerApps.length === 0) {
|
|
12287
12357
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
12288
12358
|
}
|
|
12289
|
-
const cachePath =
|
|
12290
|
-
|
|
12291
|
-
const overlayPath =
|
|
12359
|
+
const cachePath = import_node_path28.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
12360
|
+
import_node_fs28.default.mkdirSync(cachePath, { recursive: true });
|
|
12361
|
+
const overlayPath = import_node_path28.default.join(cachePath, "compose.devrouter.yml");
|
|
12292
12362
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
12293
|
-
|
|
12363
|
+
import_node_fs28.default.writeFileSync(overlayPath, import_yaml7.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
12294
12364
|
return {
|
|
12295
12365
|
overlayPath,
|
|
12296
12366
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -12410,14 +12480,14 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
12410
12480
|
const port = Number(match[1]);
|
|
12411
12481
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
12412
12482
|
}
|
|
12413
|
-
var import_node_child_process25, import_node_crypto8,
|
|
12483
|
+
var import_node_child_process25, import_node_crypto8, import_node_fs28, import_node_path28, import_yaml7;
|
|
12414
12484
|
var init_docker_run = __esm({
|
|
12415
12485
|
"src/core/docker-run.ts"() {
|
|
12416
12486
|
"use strict";
|
|
12417
12487
|
import_node_child_process25 = require("child_process");
|
|
12418
12488
|
import_node_crypto8 = require("crypto");
|
|
12419
|
-
|
|
12420
|
-
|
|
12489
|
+
import_node_fs28 = __toESM(require("fs"));
|
|
12490
|
+
import_node_path28 = __toESM(require("path"));
|
|
12421
12491
|
import_yaml7 = __toESM(require("yaml"));
|
|
12422
12492
|
init_docker_error_guidance();
|
|
12423
12493
|
init_paths();
|
|
@@ -13239,13 +13309,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
13239
13309
|
const startedAt = Date.now();
|
|
13240
13310
|
let rootStat;
|
|
13241
13311
|
try {
|
|
13242
|
-
rootStat =
|
|
13312
|
+
rootStat = import_node_fs29.default.lstatSync(worktreePath);
|
|
13243
13313
|
} catch (error) {
|
|
13244
13314
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
13245
13315
|
}
|
|
13246
13316
|
let rootEntries;
|
|
13247
13317
|
try {
|
|
13248
|
-
rootEntries =
|
|
13318
|
+
rootEntries = import_node_fs29.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
13249
13319
|
} catch (error) {
|
|
13250
13320
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
13251
13321
|
}
|
|
@@ -13271,10 +13341,10 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
13271
13341
|
timedOut = true;
|
|
13272
13342
|
break;
|
|
13273
13343
|
}
|
|
13274
|
-
const entryPath =
|
|
13344
|
+
const entryPath = import_node_path29.default.join(dirPath, entry.name);
|
|
13275
13345
|
let entryStat;
|
|
13276
13346
|
try {
|
|
13277
|
-
entryStat =
|
|
13347
|
+
entryStat = import_node_fs29.default.lstatSync(entryPath);
|
|
13278
13348
|
} catch (error) {
|
|
13279
13349
|
if (error?.code === "ENOENT") continue;
|
|
13280
13350
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -13284,7 +13354,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
13284
13354
|
if (!entryStat.isDirectory()) continue;
|
|
13285
13355
|
let childEntries;
|
|
13286
13356
|
try {
|
|
13287
|
-
childEntries =
|
|
13357
|
+
childEntries = import_node_fs29.default.readdirSync(entryPath, { withFileTypes: true });
|
|
13288
13358
|
} catch (error) {
|
|
13289
13359
|
unreadableReason = describeIncompleteWalk(error);
|
|
13290
13360
|
break;
|
|
@@ -13348,12 +13418,12 @@ function describeError(error, worktreePath) {
|
|
|
13348
13418
|
}
|
|
13349
13419
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
13350
13420
|
}
|
|
13351
|
-
var
|
|
13421
|
+
var import_node_fs29, import_node_path29, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
13352
13422
|
var init_workspace_consumption = __esm({
|
|
13353
13423
|
"src/core/workspace-consumption.ts"() {
|
|
13354
13424
|
"use strict";
|
|
13355
|
-
|
|
13356
|
-
|
|
13425
|
+
import_node_fs29 = __toESM(require("fs"));
|
|
13426
|
+
import_node_path29 = __toESM(require("path"));
|
|
13357
13427
|
init_devpod_environment();
|
|
13358
13428
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
13359
13429
|
BLOCK_SIZE_BYTES = 512;
|
|
@@ -13454,7 +13524,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
13454
13524
|
}
|
|
13455
13525
|
function readGitSnapshot(worktree, commandRunner) {
|
|
13456
13526
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
13457
|
-
if (worktree.prunable || !
|
|
13527
|
+
if (worktree.prunable || !import_node_fs30.default.existsSync(comparablePath)) {
|
|
13458
13528
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
13459
13529
|
}
|
|
13460
13530
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -13979,7 +14049,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
13979
14049
|
containers = measureContainersFn(worktreePaths);
|
|
13980
14050
|
} catch (error) {
|
|
13981
14051
|
const reason = `container measurement failed: ${describeCause(error)}`;
|
|
13982
|
-
containers = new Map(worktreePaths.map((
|
|
14052
|
+
containers = new Map(worktreePaths.map((path29) => [path29, unknownContainers(reason)]));
|
|
13983
14053
|
}
|
|
13984
14054
|
}
|
|
13985
14055
|
const rows = records.map((record) => {
|
|
@@ -14028,12 +14098,12 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
14028
14098
|
workspaces: rows
|
|
14029
14099
|
};
|
|
14030
14100
|
}
|
|
14031
|
-
var import_node_child_process27,
|
|
14101
|
+
var import_node_child_process27, import_node_fs30, DEFAULT_INACTIVE_FOR, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
14032
14102
|
var init_workspace_cleanup = __esm({
|
|
14033
14103
|
"src/core/workspace-cleanup.ts"() {
|
|
14034
14104
|
"use strict";
|
|
14035
14105
|
import_node_child_process27 = require("child_process");
|
|
14036
|
-
|
|
14106
|
+
import_node_fs30 = __toESM(require("fs"));
|
|
14037
14107
|
init_devpod_workspaces();
|
|
14038
14108
|
init_host_routes();
|
|
14039
14109
|
init_repo_config();
|
|
@@ -14210,7 +14280,7 @@ var init_version = __esm({
|
|
|
14210
14280
|
|
|
14211
14281
|
// src/cli.ts
|
|
14212
14282
|
var import_commander = require("commander");
|
|
14213
|
-
var CLI_VERSION = true ? "0.0.
|
|
14283
|
+
var CLI_VERSION = true ? "0.0.43" : "0.0.0-dev";
|
|
14214
14284
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
14215
14285
|
function withErrorHandling(action2) {
|
|
14216
14286
|
return async (...args) => {
|