@devrouter/cli 0.0.57 → 0.0.59
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/bin/devrouter-process +8 -0
- package/dist/devrouter-lifecycle-worker.js +229 -68
- package/dist/devrouter.js +155 -100
- package/package.json +1 -1
- package/upgrade-prompts/0.0.58.md +41 -0
- package/upgrade-prompts/0.0.59.md +34 -0
package/dist/devrouter.js
CHANGED
|
@@ -2291,6 +2291,38 @@ function parseRequiredUniqueStringArray(value, pathLabel) {
|
|
|
2291
2291
|
}
|
|
2292
2292
|
return parseUniqueStringArray(value, pathLabel);
|
|
2293
2293
|
}
|
|
2294
|
+
function parsePrepareCommand(value, pathLabel) {
|
|
2295
|
+
if (value === void 0) {
|
|
2296
|
+
return void 0;
|
|
2297
|
+
}
|
|
2298
|
+
if (!Array.isArray(value)) {
|
|
2299
|
+
throw new Error(`${pathLabel} must be a non-empty array of strings.`);
|
|
2300
|
+
}
|
|
2301
|
+
if (value.length === 0) {
|
|
2302
|
+
throw new Error(`${pathLabel} must be a non-empty array of strings.`);
|
|
2303
|
+
}
|
|
2304
|
+
if (value.length > MAX_PREPARE_ARGS) {
|
|
2305
|
+
throw new Error(`${pathLabel} exceeds the maximum of ${MAX_PREPARE_ARGS} arguments.`);
|
|
2306
|
+
}
|
|
2307
|
+
return value.map((item, index) => {
|
|
2308
|
+
if (typeof item !== "string") {
|
|
2309
|
+
throw new Error(`${pathLabel}[${index}] must be a string.`);
|
|
2310
|
+
}
|
|
2311
|
+
if (index === 0 && item.length === 0) {
|
|
2312
|
+
throw new Error(`${pathLabel}[0] must be a non-empty executable.`);
|
|
2313
|
+
}
|
|
2314
|
+
if (item.includes("\0")) {
|
|
2315
|
+
throw new Error(`${pathLabel}[${index}] must not contain null bytes.`);
|
|
2316
|
+
}
|
|
2317
|
+
const byteLength = Buffer.byteLength(item, "utf8");
|
|
2318
|
+
if (byteLength > MAX_PREPARE_ARG_BYTES) {
|
|
2319
|
+
throw new Error(
|
|
2320
|
+
`${pathLabel}[${index}] exceeds the maximum of ${MAX_PREPARE_ARG_BYTES} UTF-8 bytes.`
|
|
2321
|
+
);
|
|
2322
|
+
}
|
|
2323
|
+
return item;
|
|
2324
|
+
});
|
|
2325
|
+
}
|
|
2294
2326
|
function parseManagedRuntime(value, configPath) {
|
|
2295
2327
|
if (value === void 0) {
|
|
2296
2328
|
return void 0;
|
|
@@ -2303,7 +2335,7 @@ function parseManagedRuntime(value, configPath) {
|
|
|
2303
2335
|
);
|
|
2304
2336
|
ensureAllowedKeys(
|
|
2305
2337
|
devcontainer,
|
|
2306
|
-
["baseServices", "profileServices"],
|
|
2338
|
+
["baseServices", "profileServices", "prepareCommand"],
|
|
2307
2339
|
`${configPath}.managedRuntime.devcontainer`
|
|
2308
2340
|
);
|
|
2309
2341
|
const baseServices = parseRequiredUniqueStringArray(
|
|
@@ -2314,6 +2346,10 @@ function parseManagedRuntime(value, configPath) {
|
|
|
2314
2346
|
devcontainer.profileServices,
|
|
2315
2347
|
`${configPath}.managedRuntime.devcontainer.profileServices`
|
|
2316
2348
|
);
|
|
2349
|
+
const prepareCommand = parsePrepareCommand(
|
|
2350
|
+
devcontainer.prepareCommand,
|
|
2351
|
+
`${configPath}.managedRuntime.devcontainer.prepareCommand`
|
|
2352
|
+
);
|
|
2317
2353
|
const baseSet = new Set(baseServices);
|
|
2318
2354
|
const overlappingServices = profileServices.filter((service) => baseSet.has(service));
|
|
2319
2355
|
if (overlappingServices.length > 0) {
|
|
@@ -2334,7 +2370,11 @@ function parseManagedRuntime(value, configPath) {
|
|
|
2334
2370
|
);
|
|
2335
2371
|
}
|
|
2336
2372
|
return {
|
|
2337
|
-
devcontainer: {
|
|
2373
|
+
devcontainer: {
|
|
2374
|
+
baseServices,
|
|
2375
|
+
profileServices,
|
|
2376
|
+
...prepareCommand ? { prepareCommand } : {}
|
|
2377
|
+
},
|
|
2338
2378
|
processes
|
|
2339
2379
|
};
|
|
2340
2380
|
}
|
|
@@ -2781,7 +2821,7 @@ function loadRepoConfig(repoPath) {
|
|
|
2781
2821
|
const config = parseConfig(parsed ?? {}, configPath);
|
|
2782
2822
|
const requiredVersion = config.devrouter?.version;
|
|
2783
2823
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
2784
|
-
const cliVersion = true ? "0.0.
|
|
2824
|
+
const cliVersion = true ? "0.0.59" : "0.0.0-dev";
|
|
2785
2825
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
2786
2826
|
hasWarnedVersionMismatch = true;
|
|
2787
2827
|
process.stderr.write(
|
|
@@ -3125,7 +3165,7 @@ function resolveAppDependencies(config, app) {
|
|
|
3125
3165
|
}
|
|
3126
3166
|
return results;
|
|
3127
3167
|
}
|
|
3128
|
-
var import_node_fs7, import_node_path7, import_yaml2, hasWarnedVersionMismatch, CONFIG_FILE_NAME, DEFAULT_TCP_PROTOCOL, VALID_HOSTNAME_RE, DEVROUTER_VERSION_RE, VALID_ENV_NAME_RE, VALID_ENV_VAR_RE, UPSTREAM_TEMPLATE_RE, MAX_COMMAND_LENGTH, DEFAULT_HOST_STRATEGY, MAX_READINESS_PATH_LENGTH, MIME_TOKEN_RE, PROFILE_NAME_RE, MAX_PROFILES;
|
|
3168
|
+
var import_node_fs7, import_node_path7, import_yaml2, hasWarnedVersionMismatch, CONFIG_FILE_NAME, DEFAULT_TCP_PROTOCOL, VALID_HOSTNAME_RE, DEVROUTER_VERSION_RE, VALID_ENV_NAME_RE, VALID_ENV_VAR_RE, UPSTREAM_TEMPLATE_RE, MAX_COMMAND_LENGTH, MAX_PREPARE_ARGS, MAX_PREPARE_ARG_BYTES, DEFAULT_HOST_STRATEGY, MAX_READINESS_PATH_LENGTH, MIME_TOKEN_RE, PROFILE_NAME_RE, MAX_PROFILES;
|
|
3129
3169
|
var init_repo_config = __esm({
|
|
3130
3170
|
"src/core/repo-config.ts"() {
|
|
3131
3171
|
"use strict";
|
|
@@ -3144,6 +3184,8 @@ var init_repo_config = __esm({
|
|
|
3144
3184
|
VALID_ENV_VAR_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
3145
3185
|
UPSTREAM_TEMPLATE_RE = /^(?:\$\{WORKSPACE\}|[a-zA-Z0-9._-])+:\d{1,5}$/;
|
|
3146
3186
|
MAX_COMMAND_LENGTH = 4096;
|
|
3187
|
+
MAX_PREPARE_ARGS = 64;
|
|
3188
|
+
MAX_PREPARE_ARG_BYTES = 4096;
|
|
3147
3189
|
DEFAULT_HOST_STRATEGY = {
|
|
3148
3190
|
type: "auto",
|
|
3149
3191
|
denyPorts: [80, 443, 5432],
|
|
@@ -3323,6 +3365,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
3323
3365
|
"- A managed adapter plus `postCreateCommand` requires `waitFor` exactly `postCreateCommand` or `postStartCommand`; managed selective config preserves lifecycle fields and changes only `runServices`.",
|
|
3324
3366
|
"- 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.",
|
|
3325
3367
|
"- Managed adapters may use devrouter-process ensure --prepare-command <command> for synchronous dependency preparation under the process lock before app launch. Unchanged owned processes skip preparation; it participates in default fingerprints and must not daemonize or detach.",
|
|
3368
|
+
"- Host-generated Compose inputs may use managedRuntime.devcontainer.prepareCommand as literal argv. Ensure runs it once from the checkout root before Compose inspection, with a 60-second bound and no implicit shell. Keep .devrouter.yml unchanged. Diagnostics never run it; changed warm mounts require separate verification.",
|
|
3326
3369
|
"- Exact managed Devsy stop validates complete retained container membership, ownership and configuration before stopping residual services after a stopped primary. Unknown evidence blocks cleanup; original provider failures remain errors even after successful residual cleanup.",
|
|
3327
3370
|
"- 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.",
|
|
3328
3371
|
"- `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.",
|
|
@@ -3370,7 +3413,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
3370
3413
|
"- devrouter repo devcontainer write --repo <REPO_PATH> --yes",
|
|
3371
3414
|
"- devrouter repo devcontainer verify --repo <REPO_PATH> --json",
|
|
3372
3415
|
"- Normal primary or linked startup: devrouter ensure <REPO_PATH> --json",
|
|
3373
|
-
"- Degraded recovery: ordinary ensure
|
|
3416
|
+
"- Degraded recovery: ordinary ensure validates retained ownership, then reconciles the requested profile without starting dropped processes first. Same-profile repair and --repair retain the recorded-profile path and start only retained IDs without provider bootstrap/recreation. Stopped primary requires all project containers stopped and zero checkout routes. Failed transitions preserve degraded state without replaying its broken adapter.",
|
|
3374
3417
|
"- Managed selective startup: devrouter ensure <REPO_PATH> --profile <name> --json",
|
|
3375
3418
|
"- Container seed/migration: devrouter exec <REPO_PATH> -- <command...>",
|
|
3376
3419
|
"- Compatibility verification only after ensure: devrouter repo devcontainer verify --repo <REPO_PATH> --live --yes --json",
|
|
@@ -9166,7 +9209,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
9166
9209
|
const config = runtimeConfig.config;
|
|
9167
9210
|
loadedConfig = config;
|
|
9168
9211
|
loadedWorkspace = runtimeConfig.workspace;
|
|
9169
|
-
const cliVersion = true ? "0.0.
|
|
9212
|
+
const cliVersion = true ? "0.0.59" : "0.0.0-dev";
|
|
9170
9213
|
const configVersion = config.devrouter?.version;
|
|
9171
9214
|
if (configVersion && cliVersion !== "0.0.0-dev" && compareSemver(configVersion, cliVersion) > 0) {
|
|
9172
9215
|
addCheck(checks, {
|
|
@@ -11008,12 +11051,23 @@ var init_http_route_probe = __esm({
|
|
|
11008
11051
|
}
|
|
11009
11052
|
});
|
|
11010
11053
|
|
|
11054
|
+
// src/core/managed-host-preparation.ts
|
|
11055
|
+
var import_node_child_process21, import_node_fs27;
|
|
11056
|
+
var init_managed_host_preparation = __esm({
|
|
11057
|
+
"src/core/managed-host-preparation.ts"() {
|
|
11058
|
+
"use strict";
|
|
11059
|
+
import_node_child_process21 = require("child_process");
|
|
11060
|
+
import_node_fs27 = __toESM(require("fs"));
|
|
11061
|
+
init_repo_config();
|
|
11062
|
+
}
|
|
11063
|
+
});
|
|
11064
|
+
|
|
11011
11065
|
// src/core/traefik-route-health.ts
|
|
11012
11066
|
function sleep(ms) {
|
|
11013
11067
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11014
11068
|
}
|
|
11015
11069
|
function inspectRouterApi(protocol) {
|
|
11016
|
-
const result = (0,
|
|
11070
|
+
const result = (0, import_node_child_process22.spawnSync)(
|
|
11017
11071
|
"curl",
|
|
11018
11072
|
[
|
|
11019
11073
|
"--silent",
|
|
@@ -11112,7 +11166,7 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
|
|
|
11112
11166
|
throw new Error(
|
|
11113
11167
|
"Traefik routes did not reload; shared router restart is disabled for this operation."
|
|
11114
11168
|
);
|
|
11115
|
-
|
|
11169
|
+
import_node_fs28.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
11116
11170
|
return withFileLock(
|
|
11117
11171
|
ROUTER_RELOAD_LOCK_FILE,
|
|
11118
11172
|
{
|
|
@@ -11143,12 +11197,12 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
|
|
|
11143
11197
|
async function ensureTraefikRoutesRemoved(routes, options = {}) {
|
|
11144
11198
|
return ensureTraefikRouteExpectation(routes, "removed", options);
|
|
11145
11199
|
}
|
|
11146
|
-
var
|
|
11200
|
+
var import_node_child_process22, import_node_fs28, import_node_path28, ROUTER_API_BASE, ROUTER_RELOAD_LOCK_FILE, ROUTER_API_REQUEST_TIMEOUT_SECONDS, DEFAULT_INITIAL_TIMEOUT_MS, DEFAULT_RECOVERY_TIMEOUT_MS, DEFAULT_POLL_INTERVAL_MS, ROUTER_API_PAGE_SIZE;
|
|
11147
11201
|
var init_traefik_route_health = __esm({
|
|
11148
11202
|
"src/core/traefik-route-health.ts"() {
|
|
11149
11203
|
"use strict";
|
|
11150
|
-
|
|
11151
|
-
|
|
11204
|
+
import_node_child_process22 = require("child_process");
|
|
11205
|
+
import_node_fs28 = __toESM(require("fs"));
|
|
11152
11206
|
import_node_path28 = __toESM(require("path"));
|
|
11153
11207
|
init_file_lock();
|
|
11154
11208
|
init_host_routes();
|
|
@@ -11194,12 +11248,12 @@ function resolveLinkedTarget(repoPath) {
|
|
|
11194
11248
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
11195
11249
|
};
|
|
11196
11250
|
}
|
|
11197
|
-
var
|
|
11251
|
+
var import_node_child_process23, import_node_fs29, import_node_path29;
|
|
11198
11252
|
var init_workspace_ensure = __esm({
|
|
11199
11253
|
"src/core/workspace-ensure.ts"() {
|
|
11200
11254
|
"use strict";
|
|
11201
|
-
|
|
11202
|
-
|
|
11255
|
+
import_node_child_process23 = require("child_process");
|
|
11256
|
+
import_node_fs29 = __toESM(require("fs"));
|
|
11203
11257
|
import_node_path29 = __toESM(require("path"));
|
|
11204
11258
|
init_devcontainer_profile();
|
|
11205
11259
|
init_devpod_environment();
|
|
@@ -11208,6 +11262,7 @@ var init_workspace_ensure = __esm({
|
|
|
11208
11262
|
init_file_lock();
|
|
11209
11263
|
init_host_routes();
|
|
11210
11264
|
init_http_route_probe();
|
|
11265
|
+
init_managed_host_preparation();
|
|
11211
11266
|
init_managed_post_start();
|
|
11212
11267
|
init_managed_runtime_state();
|
|
11213
11268
|
init_managed_runtime_status();
|
|
@@ -11629,7 +11684,7 @@ async function runOpenCommand(name) {
|
|
|
11629
11684
|
);
|
|
11630
11685
|
return;
|
|
11631
11686
|
}
|
|
11632
|
-
const result = (0,
|
|
11687
|
+
const result = (0, import_node_child_process24.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
11633
11688
|
if (result.status !== 0) {
|
|
11634
11689
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
11635
11690
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -11637,11 +11692,11 @@ async function runOpenCommand(name) {
|
|
|
11637
11692
|
process.stdout.write(`Opened ${url}
|
|
11638
11693
|
`);
|
|
11639
11694
|
}
|
|
11640
|
-
var
|
|
11695
|
+
var import_node_child_process24;
|
|
11641
11696
|
var init_open = __esm({
|
|
11642
11697
|
"src/commands/open.ts"() {
|
|
11643
11698
|
"use strict";
|
|
11644
|
-
|
|
11699
|
+
import_node_child_process24 = require("child_process");
|
|
11645
11700
|
init_docker();
|
|
11646
11701
|
init_host_routes();
|
|
11647
11702
|
init_repo_config();
|
|
@@ -11664,7 +11719,7 @@ async function runLogsCommand(options) {
|
|
|
11664
11719
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
11665
11720
|
if (options.follow) {
|
|
11666
11721
|
args.splice(1, 0, "-f");
|
|
11667
|
-
const child = (0,
|
|
11722
|
+
const child = (0, import_node_child_process25.spawn)("docker", args, { stdio: "inherit" });
|
|
11668
11723
|
const onSignal = () => {
|
|
11669
11724
|
child.kill("SIGTERM");
|
|
11670
11725
|
};
|
|
@@ -11678,17 +11733,17 @@ async function runLogsCommand(options) {
|
|
|
11678
11733
|
});
|
|
11679
11734
|
});
|
|
11680
11735
|
} else {
|
|
11681
|
-
const result = (0,
|
|
11736
|
+
const result = (0, import_node_child_process25.spawnSync)("docker", args, { stdio: "inherit" });
|
|
11682
11737
|
if (result.status !== 0) {
|
|
11683
11738
|
throw new Error("Failed to retrieve router logs.");
|
|
11684
11739
|
}
|
|
11685
11740
|
}
|
|
11686
11741
|
}
|
|
11687
|
-
var
|
|
11742
|
+
var import_node_child_process25;
|
|
11688
11743
|
var init_logs = __esm({
|
|
11689
11744
|
"src/commands/logs.ts"() {
|
|
11690
11745
|
"use strict";
|
|
11691
|
-
|
|
11746
|
+
import_node_child_process25 = require("child_process");
|
|
11692
11747
|
init_docker();
|
|
11693
11748
|
init_router();
|
|
11694
11749
|
}
|
|
@@ -11728,11 +11783,11 @@ function asRecord3(value) {
|
|
|
11728
11783
|
return value;
|
|
11729
11784
|
}
|
|
11730
11785
|
function readJson(filePath) {
|
|
11731
|
-
if (!
|
|
11786
|
+
if (!import_node_fs30.default.existsSync(filePath)) {
|
|
11732
11787
|
return void 0;
|
|
11733
11788
|
}
|
|
11734
11789
|
try {
|
|
11735
|
-
return JSON.parse(
|
|
11790
|
+
return JSON.parse(import_node_fs30.default.readFileSync(filePath, "utf-8"));
|
|
11736
11791
|
} catch {
|
|
11737
11792
|
return void 0;
|
|
11738
11793
|
}
|
|
@@ -11779,7 +11834,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
11779
11834
|
["bun.lock", "bun"]
|
|
11780
11835
|
];
|
|
11781
11836
|
for (const [fileName, name] of lockfiles) {
|
|
11782
|
-
if (
|
|
11837
|
+
if (import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))) {
|
|
11783
11838
|
return { name, source: fileName };
|
|
11784
11839
|
}
|
|
11785
11840
|
}
|
|
@@ -11795,8 +11850,8 @@ function inspectNode(repoPath, pkg) {
|
|
|
11795
11850
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
11796
11851
|
}
|
|
11797
11852
|
const nvmrc = import_node_path31.default.join(repoPath, ".nvmrc");
|
|
11798
|
-
if (
|
|
11799
|
-
const version =
|
|
11853
|
+
if (import_node_fs30.default.existsSync(nvmrc)) {
|
|
11854
|
+
const version = import_node_fs30.default.readFileSync(nvmrc, "utf-8").trim();
|
|
11800
11855
|
return { version, source: ".nvmrc" };
|
|
11801
11856
|
}
|
|
11802
11857
|
return void 0;
|
|
@@ -11875,7 +11930,7 @@ function composeFiles(repoPath) {
|
|
|
11875
11930
|
...configuredComposeFiles(repoPath)
|
|
11876
11931
|
];
|
|
11877
11932
|
return Array.from(new Set(candidates)).filter(
|
|
11878
|
-
(fileName) =>
|
|
11933
|
+
(fileName) => import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))
|
|
11879
11934
|
);
|
|
11880
11935
|
}
|
|
11881
11936
|
function stringArray2(value) {
|
|
@@ -11913,7 +11968,7 @@ function inspectServices(repoPath) {
|
|
|
11913
11968
|
const services = [];
|
|
11914
11969
|
for (const fileName of composeFiles(repoPath)) {
|
|
11915
11970
|
try {
|
|
11916
|
-
const parsed = import_yaml6.default.parse(
|
|
11971
|
+
const parsed = import_yaml6.default.parse(import_node_fs30.default.readFileSync(import_node_path31.default.join(repoPath, fileName), "utf-8"));
|
|
11917
11972
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
11918
11973
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
11919
11974
|
const service = asRecord3(value);
|
|
@@ -11948,8 +12003,8 @@ function inspectServices(repoPath) {
|
|
|
11948
12003
|
return services;
|
|
11949
12004
|
}
|
|
11950
12005
|
function inspectEnvFiles(repoPath) {
|
|
11951
|
-
const files =
|
|
11952
|
-
const content =
|
|
12006
|
+
const files = import_node_fs30.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
12007
|
+
const content = import_node_fs30.default.readFileSync(import_node_path31.default.join(repoPath, fileName), "utf-8");
|
|
11953
12008
|
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();
|
|
11954
12009
|
return { path: fileName, names };
|
|
11955
12010
|
});
|
|
@@ -11964,17 +12019,17 @@ function inspectEnvFiles(repoPath) {
|
|
|
11964
12019
|
}
|
|
11965
12020
|
function inspectDevcontainer(repoPath) {
|
|
11966
12021
|
const dir = import_node_path31.default.join(repoPath, ".devcontainer");
|
|
11967
|
-
if (!
|
|
12022
|
+
if (!import_node_fs30.default.existsSync(dir)) {
|
|
11968
12023
|
return { exists: false, files: [] };
|
|
11969
12024
|
}
|
|
11970
12025
|
return {
|
|
11971
12026
|
exists: true,
|
|
11972
|
-
files:
|
|
12027
|
+
files: import_node_fs30.default.readdirSync(dir).filter((fileName) => import_node_fs30.default.statSync(import_node_path31.default.join(dir, fileName)).isFile()).sort().map((fileName) => `.devcontainer/${fileName}`)
|
|
11973
12028
|
};
|
|
11974
12029
|
}
|
|
11975
12030
|
function inspectDevrouter(repoPath) {
|
|
11976
12031
|
const configPath = getRepoConfigPath(repoPath);
|
|
11977
|
-
if (!
|
|
12032
|
+
if (!import_node_fs30.default.existsSync(configPath)) {
|
|
11978
12033
|
return {
|
|
11979
12034
|
exists: false,
|
|
11980
12035
|
configPath,
|
|
@@ -12018,15 +12073,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
12018
12073
|
["AGENTS.md", "agents"],
|
|
12019
12074
|
["CLAUDE.md", "claude"]
|
|
12020
12075
|
]) {
|
|
12021
|
-
if (
|
|
12076
|
+
if (import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))) {
|
|
12022
12077
|
results.push({ path: fileName, kind });
|
|
12023
12078
|
}
|
|
12024
12079
|
}
|
|
12025
12080
|
const skillsDir = import_node_path31.default.join(repoPath, ".agents", "skills");
|
|
12026
|
-
if (
|
|
12027
|
-
for (const name of
|
|
12081
|
+
if (import_node_fs30.default.existsSync(skillsDir)) {
|
|
12082
|
+
for (const name of import_node_fs30.default.readdirSync(skillsDir).sort()) {
|
|
12028
12083
|
const skillPath = import_node_path31.default.join(skillsDir, name, "SKILL.md");
|
|
12029
|
-
if (
|
|
12084
|
+
if (import_node_fs30.default.existsSync(skillPath)) {
|
|
12030
12085
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
12031
12086
|
}
|
|
12032
12087
|
}
|
|
@@ -12088,11 +12143,11 @@ function inspectRepo(options = {}) {
|
|
|
12088
12143
|
issues: buildIssues(reportWithoutIssues)
|
|
12089
12144
|
};
|
|
12090
12145
|
}
|
|
12091
|
-
var
|
|
12146
|
+
var import_node_fs30, import_node_path31, import_yaml6;
|
|
12092
12147
|
var init_repo_inspect = __esm({
|
|
12093
12148
|
"src/core/repo-inspect.ts"() {
|
|
12094
12149
|
"use strict";
|
|
12095
|
-
|
|
12150
|
+
import_node_fs30 = __toESM(require("fs"));
|
|
12096
12151
|
import_node_path31 = __toESM(require("path"));
|
|
12097
12152
|
import_yaml6 = __toESM(require("yaml"));
|
|
12098
12153
|
init_repo_config();
|
|
@@ -12198,7 +12253,7 @@ function requiredFileChecks(repoPath) {
|
|
|
12198
12253
|
".devcontainer/docker-compose.yml",
|
|
12199
12254
|
".devrouter.yml"
|
|
12200
12255
|
];
|
|
12201
|
-
const missing = required.filter((fileName) => !
|
|
12256
|
+
const missing = required.filter((fileName) => !import_node_fs31.default.existsSync(import_node_path32.default.join(repoPath, fileName)));
|
|
12202
12257
|
return {
|
|
12203
12258
|
id: "repo.devcontainer.verify-files",
|
|
12204
12259
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -12423,11 +12478,11 @@ async function verifyDevcontainer(options = {}) {
|
|
|
12423
12478
|
nextSteps: collectNextSteps3(checks)
|
|
12424
12479
|
};
|
|
12425
12480
|
}
|
|
12426
|
-
var
|
|
12481
|
+
var import_node_fs31, import_node_path32;
|
|
12427
12482
|
var init_devcontainer_verify = __esm({
|
|
12428
12483
|
"src/core/devcontainer-verify.ts"() {
|
|
12429
12484
|
"use strict";
|
|
12430
|
-
|
|
12485
|
+
import_node_fs31 = __toESM(require("fs"));
|
|
12431
12486
|
import_node_path32 = __toESM(require("path"));
|
|
12432
12487
|
init_capabilities();
|
|
12433
12488
|
init_doctor();
|
|
@@ -12771,7 +12826,7 @@ function plannedFiles(repoPath, version) {
|
|
|
12771
12826
|
}
|
|
12772
12827
|
function classifyFile(repoPath, file) {
|
|
12773
12828
|
const absolutePath = import_node_path33.default.join(repoPath, file.relativePath);
|
|
12774
|
-
if (!
|
|
12829
|
+
if (!import_node_fs32.default.existsSync(absolutePath)) {
|
|
12775
12830
|
return {
|
|
12776
12831
|
path: file.relativePath,
|
|
12777
12832
|
action: "create",
|
|
@@ -12779,7 +12834,7 @@ function classifyFile(repoPath, file) {
|
|
|
12779
12834
|
bytes: Buffer.byteLength(file.content)
|
|
12780
12835
|
};
|
|
12781
12836
|
}
|
|
12782
|
-
const current =
|
|
12837
|
+
const current = import_node_fs32.default.readFileSync(absolutePath, "utf-8");
|
|
12783
12838
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
12784
12839
|
return {
|
|
12785
12840
|
path: file.relativePath,
|
|
@@ -12837,10 +12892,10 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
12837
12892
|
}
|
|
12838
12893
|
function writeFile(repoPath, file) {
|
|
12839
12894
|
const absolutePath = import_node_path33.default.join(repoPath, file.relativePath);
|
|
12840
|
-
|
|
12841
|
-
|
|
12895
|
+
import_node_fs32.default.mkdirSync(import_node_path33.default.dirname(absolutePath), { recursive: true });
|
|
12896
|
+
import_node_fs32.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
12842
12897
|
if (file.executable) {
|
|
12843
|
-
|
|
12898
|
+
import_node_fs32.default.chmodSync(absolutePath, 493);
|
|
12844
12899
|
}
|
|
12845
12900
|
}
|
|
12846
12901
|
function writeDevcontainer(options = {}) {
|
|
@@ -12878,11 +12933,11 @@ function writeDevcontainer(options = {}) {
|
|
|
12878
12933
|
nextSteps: postWriteNextSteps(repoPath)
|
|
12879
12934
|
};
|
|
12880
12935
|
}
|
|
12881
|
-
var
|
|
12936
|
+
var import_node_fs32, import_node_path33, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
12882
12937
|
var init_devcontainer_write = __esm({
|
|
12883
12938
|
"src/core/devcontainer-write.ts"() {
|
|
12884
12939
|
"use strict";
|
|
12885
|
-
|
|
12940
|
+
import_node_fs32 = __toESM(require("fs"));
|
|
12886
12941
|
import_node_path33 = __toESM(require("path"));
|
|
12887
12942
|
init_repo_config();
|
|
12888
12943
|
init_repo_inspect();
|
|
@@ -13296,7 +13351,7 @@ function loadContract(repoPath, contractPath) {
|
|
|
13296
13351
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
13297
13352
|
let metadata;
|
|
13298
13353
|
try {
|
|
13299
|
-
metadata =
|
|
13354
|
+
metadata = import_node_fs33.default.lstatSync(absolutePath);
|
|
13300
13355
|
} catch (error) {
|
|
13301
13356
|
fail(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
13302
13357
|
}
|
|
@@ -13306,10 +13361,10 @@ function loadContract(repoPath, contractPath) {
|
|
|
13306
13361
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
13307
13362
|
fail(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
13308
13363
|
}
|
|
13309
|
-
const realRepo =
|
|
13310
|
-
const realContract =
|
|
13364
|
+
const realRepo = import_node_fs33.default.realpathSync(repoPath);
|
|
13365
|
+
const realContract = import_node_fs33.default.realpathSync(absolutePath);
|
|
13311
13366
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
13312
|
-
const source =
|
|
13367
|
+
const source = import_node_fs33.default.readFileSync(absolutePath, "utf-8");
|
|
13313
13368
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
13314
13369
|
fail(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
13315
13370
|
}
|
|
@@ -13329,11 +13384,11 @@ function resolveProfilePlan(options) {
|
|
|
13329
13384
|
contractPath: loaded.contractPath
|
|
13330
13385
|
});
|
|
13331
13386
|
}
|
|
13332
|
-
var
|
|
13387
|
+
var import_node_fs33, import_node_path34, import_yaml7, CONTRACT_VERSION, MAX_CONTRACT_BYTES, MAX_APP_MAPPINGS, MAX_BINDING_KEYS, MAX_BINDING_VALUES, MAX_LITERAL_LENGTH, BINDING_KEY;
|
|
13333
13388
|
var init_profile_plan = __esm({
|
|
13334
13389
|
"src/core/profile-plan.ts"() {
|
|
13335
13390
|
"use strict";
|
|
13336
|
-
|
|
13391
|
+
import_node_fs33 = __toESM(require("fs"));
|
|
13337
13392
|
import_node_path34 = __toESM(require("path"));
|
|
13338
13393
|
import_yaml7 = require("yaml");
|
|
13339
13394
|
init_paths();
|
|
@@ -13779,10 +13834,10 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
13779
13834
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
13780
13835
|
}
|
|
13781
13836
|
const cachePath = import_node_path36.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
13782
|
-
|
|
13837
|
+
import_node_fs34.default.mkdirSync(cachePath, { recursive: true });
|
|
13783
13838
|
const overlayPath = import_node_path36.default.join(cachePath, "compose.devrouter.yml");
|
|
13784
13839
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
13785
|
-
|
|
13840
|
+
import_node_fs34.default.writeFileSync(overlayPath, import_yaml8.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
13786
13841
|
return {
|
|
13787
13842
|
overlayPath,
|
|
13788
13843
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -13796,7 +13851,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
13796
13851
|
fileArgs.push("-f", resolved);
|
|
13797
13852
|
}
|
|
13798
13853
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
13799
|
-
const result = (0,
|
|
13854
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13800
13855
|
encoding: "utf-8",
|
|
13801
13856
|
cwd: repoPath
|
|
13802
13857
|
});
|
|
@@ -13824,7 +13879,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
13824
13879
|
"--services",
|
|
13825
13880
|
...services
|
|
13826
13881
|
];
|
|
13827
|
-
const result = (0,
|
|
13882
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13828
13883
|
encoding: "utf-8",
|
|
13829
13884
|
cwd: repoPath
|
|
13830
13885
|
});
|
|
@@ -13850,7 +13905,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
13850
13905
|
fileArgs.push("-f", resolved);
|
|
13851
13906
|
}
|
|
13852
13907
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
13853
|
-
const result = (0,
|
|
13908
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13854
13909
|
encoding: "utf-8",
|
|
13855
13910
|
cwd: repoPath
|
|
13856
13911
|
});
|
|
@@ -13876,7 +13931,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
13876
13931
|
String(tail),
|
|
13877
13932
|
...services
|
|
13878
13933
|
];
|
|
13879
|
-
(0,
|
|
13934
|
+
(0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13880
13935
|
stdio: "inherit",
|
|
13881
13936
|
cwd: repoPath
|
|
13882
13937
|
});
|
|
@@ -13888,7 +13943,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
13888
13943
|
fileArgs.push("-f", resolved);
|
|
13889
13944
|
}
|
|
13890
13945
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
13891
|
-
const result = (0,
|
|
13946
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13892
13947
|
encoding: "utf-8",
|
|
13893
13948
|
cwd: repoPath
|
|
13894
13949
|
});
|
|
@@ -13902,13 +13957,13 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
13902
13957
|
const port = Number(match[1]);
|
|
13903
13958
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
13904
13959
|
}
|
|
13905
|
-
var
|
|
13960
|
+
var import_node_child_process26, import_node_crypto11, import_node_fs34, import_node_path36, import_yaml8;
|
|
13906
13961
|
var init_docker_run = __esm({
|
|
13907
13962
|
"src/core/docker-run.ts"() {
|
|
13908
13963
|
"use strict";
|
|
13909
|
-
|
|
13964
|
+
import_node_child_process26 = require("child_process");
|
|
13910
13965
|
import_node_crypto11 = require("crypto");
|
|
13911
|
-
|
|
13966
|
+
import_node_fs34 = __toESM(require("fs"));
|
|
13912
13967
|
import_node_path36 = __toESM(require("path"));
|
|
13913
13968
|
import_yaml8 = __toESM(require("yaml"));
|
|
13914
13969
|
init_docker_error_guidance();
|
|
@@ -13999,7 +14054,7 @@ function isProcessRunning(pid) {
|
|
|
13999
14054
|
}
|
|
14000
14055
|
}
|
|
14001
14056
|
function readProcessTree(rootPid) {
|
|
14002
|
-
const result = (0,
|
|
14057
|
+
const result = (0, import_node_child_process27.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
14003
14058
|
if (result.status !== 0) {
|
|
14004
14059
|
return [rootPid];
|
|
14005
14060
|
}
|
|
@@ -14110,12 +14165,12 @@ function detectListeningPorts(pids) {
|
|
|
14110
14165
|
if (pids.length === 0) {
|
|
14111
14166
|
return [];
|
|
14112
14167
|
}
|
|
14113
|
-
const result = (0,
|
|
14168
|
+
const result = (0, import_node_child_process27.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
14114
14169
|
encoding: "utf-8"
|
|
14115
14170
|
});
|
|
14116
14171
|
if (result.error && result.error.code === "ENOENT") {
|
|
14117
14172
|
if (process.platform === "linux") {
|
|
14118
|
-
const ssResult = (0,
|
|
14173
|
+
const ssResult = (0, import_node_child_process27.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
14119
14174
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
14120
14175
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
14121
14176
|
}
|
|
@@ -14174,7 +14229,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
14174
14229
|
app.hostRun.command,
|
|
14175
14230
|
true
|
|
14176
14231
|
) : app.hostRun.command;
|
|
14177
|
-
const child = (0,
|
|
14232
|
+
const child = (0, import_node_child_process27.spawn)(spawnCommand, {
|
|
14178
14233
|
cwd: commandCwd,
|
|
14179
14234
|
stdio: "inherit",
|
|
14180
14235
|
shell: true,
|
|
@@ -14542,7 +14597,7 @@ async function execWithAppEnv(options) {
|
|
|
14542
14597
|
options.command[0],
|
|
14543
14598
|
true
|
|
14544
14599
|
);
|
|
14545
|
-
child = (0,
|
|
14600
|
+
child = (0, import_node_child_process27.spawn)(wrapped, {
|
|
14546
14601
|
cwd: deps.repoPath,
|
|
14547
14602
|
stdio: "inherit",
|
|
14548
14603
|
shell: true,
|
|
@@ -14556,7 +14611,7 @@ async function execWithAppEnv(options) {
|
|
|
14556
14611
|
false
|
|
14557
14612
|
);
|
|
14558
14613
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
14559
|
-
child = (0,
|
|
14614
|
+
child = (0, import_node_child_process27.spawn)(cmd, wrappedArgs, {
|
|
14560
14615
|
cwd: deps.repoPath,
|
|
14561
14616
|
stdio: "inherit",
|
|
14562
14617
|
shell: false,
|
|
@@ -14564,7 +14619,7 @@ async function execWithAppEnv(options) {
|
|
|
14564
14619
|
});
|
|
14565
14620
|
}
|
|
14566
14621
|
} else if (options.shell) {
|
|
14567
|
-
child = (0,
|
|
14622
|
+
child = (0, import_node_child_process27.spawn)(options.command[0], {
|
|
14568
14623
|
cwd: deps.repoPath,
|
|
14569
14624
|
stdio: "inherit",
|
|
14570
14625
|
shell: true,
|
|
@@ -14572,7 +14627,7 @@ async function execWithAppEnv(options) {
|
|
|
14572
14627
|
});
|
|
14573
14628
|
} else {
|
|
14574
14629
|
const [command, ...args] = options.command;
|
|
14575
|
-
child = (0,
|
|
14630
|
+
child = (0, import_node_child_process27.spawn)(command, args, {
|
|
14576
14631
|
cwd: deps.repoPath,
|
|
14577
14632
|
stdio: "inherit",
|
|
14578
14633
|
shell: false,
|
|
@@ -14593,11 +14648,11 @@ async function execWithAppEnv(options) {
|
|
|
14593
14648
|
deps.stopDeps();
|
|
14594
14649
|
}
|
|
14595
14650
|
}
|
|
14596
|
-
var
|
|
14651
|
+
var import_node_child_process27, import_node_net, import_node_process, import_promises, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
|
|
14597
14652
|
var init_app_run = __esm({
|
|
14598
14653
|
"src/core/app-run.ts"() {
|
|
14599
14654
|
"use strict";
|
|
14600
|
-
|
|
14655
|
+
import_node_child_process27 = require("child_process");
|
|
14601
14656
|
import_node_net = __toESM(require("net"));
|
|
14602
14657
|
import_node_process = require("process");
|
|
14603
14658
|
import_promises = require("readline/promises");
|
|
@@ -14731,13 +14786,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14731
14786
|
const startedAt = Date.now();
|
|
14732
14787
|
let rootStat;
|
|
14733
14788
|
try {
|
|
14734
|
-
rootStat =
|
|
14789
|
+
rootStat = import_node_fs35.default.lstatSync(worktreePath);
|
|
14735
14790
|
} catch (error) {
|
|
14736
14791
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
14737
14792
|
}
|
|
14738
14793
|
let rootEntries;
|
|
14739
14794
|
try {
|
|
14740
|
-
rootEntries =
|
|
14795
|
+
rootEntries = import_node_fs35.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
14741
14796
|
} catch (error) {
|
|
14742
14797
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
14743
14798
|
}
|
|
@@ -14766,7 +14821,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14766
14821
|
const entryPath = import_node_path37.default.join(dirPath, entry.name);
|
|
14767
14822
|
let entryStat;
|
|
14768
14823
|
try {
|
|
14769
|
-
entryStat =
|
|
14824
|
+
entryStat = import_node_fs35.default.lstatSync(entryPath);
|
|
14770
14825
|
} catch (error) {
|
|
14771
14826
|
if (error?.code === "ENOENT") continue;
|
|
14772
14827
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -14776,7 +14831,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14776
14831
|
if (!entryStat.isDirectory()) continue;
|
|
14777
14832
|
let childEntries;
|
|
14778
14833
|
try {
|
|
14779
|
-
childEntries =
|
|
14834
|
+
childEntries = import_node_fs35.default.readdirSync(entryPath, { withFileTypes: true });
|
|
14780
14835
|
} catch (error) {
|
|
14781
14836
|
unreadableReason = describeIncompleteWalk(error);
|
|
14782
14837
|
break;
|
|
@@ -14840,11 +14895,11 @@ function describeError(error, worktreePath) {
|
|
|
14840
14895
|
}
|
|
14841
14896
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
14842
14897
|
}
|
|
14843
|
-
var
|
|
14898
|
+
var import_node_fs35, import_node_path37, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
14844
14899
|
var init_workspace_consumption = __esm({
|
|
14845
14900
|
"src/core/workspace-consumption.ts"() {
|
|
14846
14901
|
"use strict";
|
|
14847
|
-
|
|
14902
|
+
import_node_fs35 = __toESM(require("fs"));
|
|
14848
14903
|
import_node_path37 = __toESM(require("path"));
|
|
14849
14904
|
init_devpod_environment();
|
|
14850
14905
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
@@ -14946,7 +15001,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
14946
15001
|
}
|
|
14947
15002
|
function readGitSnapshot(worktree, commandRunner) {
|
|
14948
15003
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
14949
|
-
if (worktree.prunable || !
|
|
15004
|
+
if (worktree.prunable || !import_node_fs36.default.existsSync(comparablePath)) {
|
|
14950
15005
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
14951
15006
|
}
|
|
14952
15007
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -15520,12 +15575,12 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
15520
15575
|
workspaces: rows
|
|
15521
15576
|
};
|
|
15522
15577
|
}
|
|
15523
|
-
var
|
|
15578
|
+
var import_node_child_process28, import_node_fs36, DEFAULT_INACTIVE_FOR, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
15524
15579
|
var init_workspace_cleanup = __esm({
|
|
15525
15580
|
"src/core/workspace-cleanup.ts"() {
|
|
15526
15581
|
"use strict";
|
|
15527
|
-
|
|
15528
|
-
|
|
15582
|
+
import_node_child_process28 = require("child_process");
|
|
15583
|
+
import_node_fs36 = __toESM(require("fs"));
|
|
15529
15584
|
init_devpod_workspaces();
|
|
15530
15585
|
init_host_routes();
|
|
15531
15586
|
init_repo_config();
|
|
@@ -15542,7 +15597,7 @@ var init_workspace_cleanup = __esm({
|
|
|
15542
15597
|
];
|
|
15543
15598
|
defaultCommandRunner = (command, args, input2) => {
|
|
15544
15599
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
15545
|
-
const result = (0,
|
|
15600
|
+
const result = (0, import_node_child_process28.spawnSync)(command, args, {
|
|
15546
15601
|
encoding: "utf-8",
|
|
15547
15602
|
env: environment,
|
|
15548
15603
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -15575,7 +15630,7 @@ function defaultWorktreePath(mainRepo, ws) {
|
|
|
15575
15630
|
return import_node_path38.default.join(mainRepo, "trees", ws);
|
|
15576
15631
|
}
|
|
15577
15632
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
15578
|
-
const ignored = (0,
|
|
15633
|
+
const ignored = (0, import_node_child_process29.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
15579
15634
|
encoding: "utf-8"
|
|
15580
15635
|
});
|
|
15581
15636
|
if (ignored.status !== 0) {
|
|
@@ -15697,13 +15752,13 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
15697
15752
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
15698
15753
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
15699
15754
|
}
|
|
15700
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
15755
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs37.default.existsSync(target.worktreePath)) return;
|
|
15701
15756
|
if (target.worktree.locked) {
|
|
15702
15757
|
throw new Error(
|
|
15703
15758
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
15704
15759
|
);
|
|
15705
15760
|
}
|
|
15706
|
-
const status = (0,
|
|
15761
|
+
const status = (0, import_node_child_process29.spawnSync)(
|
|
15707
15762
|
"git",
|
|
15708
15763
|
["-C", target.worktreePath, "status", "--porcelain", "--untracked-files=normal"],
|
|
15709
15764
|
{ encoding: "utf-8" }
|
|
@@ -15737,7 +15792,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15737
15792
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
15738
15793
|
);
|
|
15739
15794
|
const generatedPath = candidatePaths.find(
|
|
15740
|
-
(candidate) => !
|
|
15795
|
+
(candidate) => !import_node_fs37.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
15741
15796
|
);
|
|
15742
15797
|
const selectedPath = opts.path ? import_node_path38.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
15743
15798
|
if (!selectedPath) {
|
|
@@ -15748,7 +15803,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15748
15803
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
15749
15804
|
);
|
|
15750
15805
|
}
|
|
15751
|
-
if (
|
|
15806
|
+
if (import_node_fs37.default.existsSync(selectedPath)) {
|
|
15752
15807
|
const registered = worktrees.find(
|
|
15753
15808
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
15754
15809
|
);
|
|
@@ -15767,11 +15822,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15767
15822
|
return selectedPath;
|
|
15768
15823
|
}
|
|
15769
15824
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
15770
|
-
const add = (0,
|
|
15825
|
+
const add = (0, import_node_child_process29.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
15771
15826
|
encoding: "utf-8"
|
|
15772
15827
|
});
|
|
15773
15828
|
if (add.status !== 0) {
|
|
15774
|
-
const addNew = (0,
|
|
15829
|
+
const addNew = (0, import_node_child_process29.spawnSync)(
|
|
15775
15830
|
"git",
|
|
15776
15831
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
15777
15832
|
{ encoding: "utf-8" }
|
|
@@ -15888,8 +15943,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
15888
15943
|
}
|
|
15889
15944
|
const result = await mutateWorkspaceRuntime("delete", resolved, worktrees, opts.quiet);
|
|
15890
15945
|
if (removeWorktree) {
|
|
15891
|
-
if (resolved.worktree && !resolved.worktree.prunable &&
|
|
15892
|
-
const rm = (0,
|
|
15946
|
+
if (resolved.worktree && !resolved.worktree.prunable && import_node_fs37.default.existsSync(resolved.worktreePath)) {
|
|
15947
|
+
const rm = (0, import_node_child_process29.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved.worktreePath], {
|
|
15893
15948
|
encoding: "utf-8"
|
|
15894
15949
|
});
|
|
15895
15950
|
if (rm.status !== 0) {
|
|
@@ -15907,7 +15962,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
15907
15962
|
}
|
|
15908
15963
|
return result;
|
|
15909
15964
|
};
|
|
15910
|
-
return resolved.worktree && !resolved.worktree.prunable &&
|
|
15965
|
+
return resolved.worktree && !resolved.worktree.prunable && import_node_fs37.default.existsSync(resolved.worktreePath) ? withLifecycleOperationLock(resolved.worktreePath, operation) : operation();
|
|
15911
15966
|
}
|
|
15912
15967
|
async function workspaceStop(target, opts = {}) {
|
|
15913
15968
|
return runWorkspaceLifecycle("stop", target, opts);
|
|
@@ -15915,12 +15970,12 @@ async function workspaceStop(target, opts = {}) {
|
|
|
15915
15970
|
async function workspaceDown(target, opts = {}) {
|
|
15916
15971
|
return runWorkspaceLifecycle("down", target, opts);
|
|
15917
15972
|
}
|
|
15918
|
-
var
|
|
15973
|
+
var import_node_child_process29, import_node_fs37, import_node_path38, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
15919
15974
|
var init_workspace_lifecycle = __esm({
|
|
15920
15975
|
"src/core/workspace-lifecycle.ts"() {
|
|
15921
15976
|
"use strict";
|
|
15922
|
-
|
|
15923
|
-
|
|
15977
|
+
import_node_child_process29 = require("child_process");
|
|
15978
|
+
import_node_fs37 = __toESM(require("fs"));
|
|
15924
15979
|
import_node_path38 = __toESM(require("path"));
|
|
15925
15980
|
init_devpod_mutation();
|
|
15926
15981
|
init_devpod_workspaces();
|
|
@@ -16080,7 +16135,7 @@ var init_version = __esm({
|
|
|
16080
16135
|
|
|
16081
16136
|
// src/cli.ts
|
|
16082
16137
|
var import_commander = require("commander");
|
|
16083
|
-
var CLI_VERSION = true ? "0.0.
|
|
16138
|
+
var CLI_VERSION = true ? "0.0.59" : "0.0.0-dev";
|
|
16084
16139
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
16085
16140
|
function withErrorHandling(action2) {
|
|
16086
16141
|
return async (...args) => {
|