@devrouter/cli 0.0.56 → 0.0.58
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-lifecycle-worker.js +237 -73
- package/dist/devrouter.js +163 -105
- package/package.json +1 -1
- package/upgrade-prompts/0.0.57.md +33 -0
- package/upgrade-prompts/0.0.58.md +41 -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.58" : "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.58" : "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, {
|
|
@@ -9803,6 +9846,9 @@ var init_up = __esm({
|
|
|
9803
9846
|
function isReliabilityId(value) {
|
|
9804
9847
|
return typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,127}$/.test(value);
|
|
9805
9848
|
}
|
|
9849
|
+
function isReliabilityProfile(value) {
|
|
9850
|
+
return typeof value === "string" && value.length <= 4096 && value.split(",").every((name) => isReliabilityId(name.trim()));
|
|
9851
|
+
}
|
|
9806
9852
|
function isReliabilityCounter(value) {
|
|
9807
9853
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
9808
9854
|
}
|
|
@@ -9833,7 +9879,7 @@ function validOperation(value) {
|
|
|
9833
9879
|
function assertReliabilityState(value) {
|
|
9834
9880
|
const intentRevision = record(value) ? value.intentRevision : void 0;
|
|
9835
9881
|
const valid = record(value) && value.contractVersion === RELIABILITY_CONTRACT_VERSION && oneOf(value.executionPolicy, ["manual", "capacity-managed"]) && (value.executionPolicy === "manual" ? value.admission === "not-applicable" && value.chargeHeld === false : value.admission !== "not-applicable") && boundedArray(value.operationHistory) && uniqueIds(value.operationHistory, "key") && uniqueIds(value.operationHistory, "id") && value.operationHistory.every(
|
|
9836
|
-
(entry) => record(entry) &&
|
|
9882
|
+
(entry) => record(entry) && isReliabilityProfile(entry.profile) && record(entry.consumer) && isReliabilityId(entry.consumer.id) && typeof entry.consumer.pinned === "boolean" && boundedArray(entry.consumer.requiredCapabilities) && entry.consumer.requiredCapabilities.every(isReliabilityId) && new Set(entry.consumer.requiredCapabilities).size === entry.consumer.requiredCapabilities.length && validOperation(entry)
|
|
9837
9883
|
) && isReliabilityCounter(value.observationsAfterMs) && isReliabilityId(value.environmentId) && isReliabilityCounter(value.intentRevision) && isReliabilityCounter(value.runtimeGeneration) && isReliabilityCounter(value.controllerEpoch) && oneOf(value.desired, ["running", "parked-for-capacity", "stopped-by-user"]) && oneOf(value.phase, [
|
|
9838
9884
|
"idle",
|
|
9839
9885
|
"queued",
|
|
@@ -9842,7 +9888,7 @@ function assertReliabilityState(value) {
|
|
|
9842
9888
|
"stable",
|
|
9843
9889
|
"recovering",
|
|
9844
9890
|
"stopping"
|
|
9845
|
-
]) && (value.profile === null ||
|
|
9891
|
+
]) && (value.profile === null || isReliabilityProfile(value.profile)) && oneOf(value.admission, [
|
|
9846
9892
|
"admitted",
|
|
9847
9893
|
"waiting",
|
|
9848
9894
|
"unknown",
|
|
@@ -9851,7 +9897,7 @@ function assertReliabilityState(value) {
|
|
|
9851
9897
|
]) && typeof value.chargeHeld === "boolean" && record(value.stopProof) && typeof value.stopProof.workloadsStopped === "boolean" && typeof value.stopProof.routesRemoved === "boolean" && boundedArray(value.consumers) && uniqueIds(value.consumers, "id") && value.consumers.every(
|
|
9852
9898
|
(consumer) => record(consumer) && typeof consumer.pinned === "boolean" && boundedArray(consumer.requiredCapabilities) && consumer.requiredCapabilities.every(isReliabilityId) && new Set(consumer.requiredCapabilities).size === consumer.requiredCapabilities.length
|
|
9853
9899
|
) && boundedArray(value.requests) && uniqueIds(value.requests, "key") && value.requests.every(
|
|
9854
|
-
(request) => record(request) && oneOf(request.mode, ["start", "attach"]) && isReliabilityId(request.consumerId) && isReliabilityId(request.operationId) &&
|
|
9900
|
+
(request) => record(request) && oneOf(request.mode, ["start", "attach"]) && isReliabilityId(request.consumerId) && isReliabilityId(request.operationId) && isReliabilityProfile(request.profile) && isReliabilityCounter(request.intentRevision) && isReliabilityCounter(intentRevision) && request.intentRevision <= intentRevision
|
|
9855
9901
|
) && boundedArray(value.observations) && uniqueIds(value.observations, "capability") && value.observations.every(
|
|
9856
9902
|
(observation) => record(observation) && oneOf(observation.infrastructure, ["healthy", "failed", "unknown"]) && oneOf(observation.application, ["verified", "unready", "unverified"]) && isReliabilityCounter(observation.observedAtMs) && isReliabilityCounter(observation.validForMs)
|
|
9857
9903
|
) && (value.operation === null || validOperation(value.operation)) && (value.executionPolicy !== "manual" || value.desired !== "parked-for-capacity" && value.incident === null) && (value.incident === null || record(value.incident) && isReliabilityId(value.incident.id) && isReliabilityCounter(value.incident.correctiveActionsTaken) && isReliabilityCounter(value.incident.actionLimit) && value.incident.actionLimit > 0 && value.incident.correctiveActionsTaken <= value.incident.actionLimit);
|
|
@@ -9925,10 +9971,10 @@ function assertReliabilityEvent(value) {
|
|
|
9925
9971
|
let valid = false;
|
|
9926
9972
|
switch (value.type) {
|
|
9927
9973
|
case "request":
|
|
9928
|
-
valid = oneOf2(value.mode, ["start", "attach"]) && isReliabilityId(value.key) && isReliabilityId(value.operationId) &&
|
|
9974
|
+
valid = oneOf2(value.mode, ["start", "attach"]) && isReliabilityId(value.key) && isReliabilityId(value.operationId) && isReliabilityProfile(value.profile) && isConsumer(value.consumer);
|
|
9929
9975
|
break;
|
|
9930
9976
|
case "operation-request":
|
|
9931
|
-
valid = oneOf2(value.kind, ["ensure", "exec"]) && isReliabilityId(value.key) && isReliabilityId(value.operationId) &&
|
|
9977
|
+
valid = oneOf2(value.kind, ["ensure", "exec"]) && isReliabilityId(value.key) && isReliabilityId(value.operationId) && isReliabilityProfile(value.profile) && isConsumer(value.consumer) && typeof value.runtimeRunning === "boolean";
|
|
9932
9978
|
break;
|
|
9933
9979
|
case "drained":
|
|
9934
9980
|
valid = isReliabilityId(value.operationId);
|
|
@@ -11005,12 +11051,23 @@ var init_http_route_probe = __esm({
|
|
|
11005
11051
|
}
|
|
11006
11052
|
});
|
|
11007
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
|
+
|
|
11008
11065
|
// src/core/traefik-route-health.ts
|
|
11009
11066
|
function sleep(ms) {
|
|
11010
11067
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11011
11068
|
}
|
|
11012
11069
|
function inspectRouterApi(protocol) {
|
|
11013
|
-
const result = (0,
|
|
11070
|
+
const result = (0, import_node_child_process22.spawnSync)(
|
|
11014
11071
|
"curl",
|
|
11015
11072
|
[
|
|
11016
11073
|
"--silent",
|
|
@@ -11109,7 +11166,7 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
|
|
|
11109
11166
|
throw new Error(
|
|
11110
11167
|
"Traefik routes did not reload; shared router restart is disabled for this operation."
|
|
11111
11168
|
);
|
|
11112
|
-
|
|
11169
|
+
import_node_fs28.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
11113
11170
|
return withFileLock(
|
|
11114
11171
|
ROUTER_RELOAD_LOCK_FILE,
|
|
11115
11172
|
{
|
|
@@ -11140,12 +11197,12 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
|
|
|
11140
11197
|
async function ensureTraefikRoutesRemoved(routes, options = {}) {
|
|
11141
11198
|
return ensureTraefikRouteExpectation(routes, "removed", options);
|
|
11142
11199
|
}
|
|
11143
|
-
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;
|
|
11144
11201
|
var init_traefik_route_health = __esm({
|
|
11145
11202
|
"src/core/traefik-route-health.ts"() {
|
|
11146
11203
|
"use strict";
|
|
11147
|
-
|
|
11148
|
-
|
|
11204
|
+
import_node_child_process22 = require("child_process");
|
|
11205
|
+
import_node_fs28 = __toESM(require("fs"));
|
|
11149
11206
|
import_node_path28 = __toESM(require("path"));
|
|
11150
11207
|
init_file_lock();
|
|
11151
11208
|
init_host_routes();
|
|
@@ -11191,12 +11248,12 @@ function resolveLinkedTarget(repoPath) {
|
|
|
11191
11248
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
11192
11249
|
};
|
|
11193
11250
|
}
|
|
11194
|
-
var
|
|
11251
|
+
var import_node_child_process23, import_node_fs29, import_node_path29;
|
|
11195
11252
|
var init_workspace_ensure = __esm({
|
|
11196
11253
|
"src/core/workspace-ensure.ts"() {
|
|
11197
11254
|
"use strict";
|
|
11198
|
-
|
|
11199
|
-
|
|
11255
|
+
import_node_child_process23 = require("child_process");
|
|
11256
|
+
import_node_fs29 = __toESM(require("fs"));
|
|
11200
11257
|
import_node_path29 = __toESM(require("path"));
|
|
11201
11258
|
init_devcontainer_profile();
|
|
11202
11259
|
init_devpod_environment();
|
|
@@ -11205,6 +11262,7 @@ var init_workspace_ensure = __esm({
|
|
|
11205
11262
|
init_file_lock();
|
|
11206
11263
|
init_host_routes();
|
|
11207
11264
|
init_http_route_probe();
|
|
11265
|
+
init_managed_host_preparation();
|
|
11208
11266
|
init_managed_post_start();
|
|
11209
11267
|
init_managed_runtime_state();
|
|
11210
11268
|
init_managed_runtime_status();
|
|
@@ -11626,7 +11684,7 @@ async function runOpenCommand(name) {
|
|
|
11626
11684
|
);
|
|
11627
11685
|
return;
|
|
11628
11686
|
}
|
|
11629
|
-
const result = (0,
|
|
11687
|
+
const result = (0, import_node_child_process24.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
11630
11688
|
if (result.status !== 0) {
|
|
11631
11689
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
11632
11690
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -11634,11 +11692,11 @@ async function runOpenCommand(name) {
|
|
|
11634
11692
|
process.stdout.write(`Opened ${url}
|
|
11635
11693
|
`);
|
|
11636
11694
|
}
|
|
11637
|
-
var
|
|
11695
|
+
var import_node_child_process24;
|
|
11638
11696
|
var init_open = __esm({
|
|
11639
11697
|
"src/commands/open.ts"() {
|
|
11640
11698
|
"use strict";
|
|
11641
|
-
|
|
11699
|
+
import_node_child_process24 = require("child_process");
|
|
11642
11700
|
init_docker();
|
|
11643
11701
|
init_host_routes();
|
|
11644
11702
|
init_repo_config();
|
|
@@ -11661,7 +11719,7 @@ async function runLogsCommand(options) {
|
|
|
11661
11719
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
11662
11720
|
if (options.follow) {
|
|
11663
11721
|
args.splice(1, 0, "-f");
|
|
11664
|
-
const child = (0,
|
|
11722
|
+
const child = (0, import_node_child_process25.spawn)("docker", args, { stdio: "inherit" });
|
|
11665
11723
|
const onSignal = () => {
|
|
11666
11724
|
child.kill("SIGTERM");
|
|
11667
11725
|
};
|
|
@@ -11675,17 +11733,17 @@ async function runLogsCommand(options) {
|
|
|
11675
11733
|
});
|
|
11676
11734
|
});
|
|
11677
11735
|
} else {
|
|
11678
|
-
const result = (0,
|
|
11736
|
+
const result = (0, import_node_child_process25.spawnSync)("docker", args, { stdio: "inherit" });
|
|
11679
11737
|
if (result.status !== 0) {
|
|
11680
11738
|
throw new Error("Failed to retrieve router logs.");
|
|
11681
11739
|
}
|
|
11682
11740
|
}
|
|
11683
11741
|
}
|
|
11684
|
-
var
|
|
11742
|
+
var import_node_child_process25;
|
|
11685
11743
|
var init_logs = __esm({
|
|
11686
11744
|
"src/commands/logs.ts"() {
|
|
11687
11745
|
"use strict";
|
|
11688
|
-
|
|
11746
|
+
import_node_child_process25 = require("child_process");
|
|
11689
11747
|
init_docker();
|
|
11690
11748
|
init_router();
|
|
11691
11749
|
}
|
|
@@ -11725,11 +11783,11 @@ function asRecord3(value) {
|
|
|
11725
11783
|
return value;
|
|
11726
11784
|
}
|
|
11727
11785
|
function readJson(filePath) {
|
|
11728
|
-
if (!
|
|
11786
|
+
if (!import_node_fs30.default.existsSync(filePath)) {
|
|
11729
11787
|
return void 0;
|
|
11730
11788
|
}
|
|
11731
11789
|
try {
|
|
11732
|
-
return JSON.parse(
|
|
11790
|
+
return JSON.parse(import_node_fs30.default.readFileSync(filePath, "utf-8"));
|
|
11733
11791
|
} catch {
|
|
11734
11792
|
return void 0;
|
|
11735
11793
|
}
|
|
@@ -11776,7 +11834,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
11776
11834
|
["bun.lock", "bun"]
|
|
11777
11835
|
];
|
|
11778
11836
|
for (const [fileName, name] of lockfiles) {
|
|
11779
|
-
if (
|
|
11837
|
+
if (import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))) {
|
|
11780
11838
|
return { name, source: fileName };
|
|
11781
11839
|
}
|
|
11782
11840
|
}
|
|
@@ -11792,8 +11850,8 @@ function inspectNode(repoPath, pkg) {
|
|
|
11792
11850
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
11793
11851
|
}
|
|
11794
11852
|
const nvmrc = import_node_path31.default.join(repoPath, ".nvmrc");
|
|
11795
|
-
if (
|
|
11796
|
-
const version =
|
|
11853
|
+
if (import_node_fs30.default.existsSync(nvmrc)) {
|
|
11854
|
+
const version = import_node_fs30.default.readFileSync(nvmrc, "utf-8").trim();
|
|
11797
11855
|
return { version, source: ".nvmrc" };
|
|
11798
11856
|
}
|
|
11799
11857
|
return void 0;
|
|
@@ -11872,7 +11930,7 @@ function composeFiles(repoPath) {
|
|
|
11872
11930
|
...configuredComposeFiles(repoPath)
|
|
11873
11931
|
];
|
|
11874
11932
|
return Array.from(new Set(candidates)).filter(
|
|
11875
|
-
(fileName) =>
|
|
11933
|
+
(fileName) => import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))
|
|
11876
11934
|
);
|
|
11877
11935
|
}
|
|
11878
11936
|
function stringArray2(value) {
|
|
@@ -11910,7 +11968,7 @@ function inspectServices(repoPath) {
|
|
|
11910
11968
|
const services = [];
|
|
11911
11969
|
for (const fileName of composeFiles(repoPath)) {
|
|
11912
11970
|
try {
|
|
11913
|
-
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"));
|
|
11914
11972
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
11915
11973
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
11916
11974
|
const service = asRecord3(value);
|
|
@@ -11945,8 +12003,8 @@ function inspectServices(repoPath) {
|
|
|
11945
12003
|
return services;
|
|
11946
12004
|
}
|
|
11947
12005
|
function inspectEnvFiles(repoPath) {
|
|
11948
|
-
const files =
|
|
11949
|
-
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");
|
|
11950
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();
|
|
11951
12009
|
return { path: fileName, names };
|
|
11952
12010
|
});
|
|
@@ -11961,17 +12019,17 @@ function inspectEnvFiles(repoPath) {
|
|
|
11961
12019
|
}
|
|
11962
12020
|
function inspectDevcontainer(repoPath) {
|
|
11963
12021
|
const dir = import_node_path31.default.join(repoPath, ".devcontainer");
|
|
11964
|
-
if (!
|
|
12022
|
+
if (!import_node_fs30.default.existsSync(dir)) {
|
|
11965
12023
|
return { exists: false, files: [] };
|
|
11966
12024
|
}
|
|
11967
12025
|
return {
|
|
11968
12026
|
exists: true,
|
|
11969
|
-
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}`)
|
|
11970
12028
|
};
|
|
11971
12029
|
}
|
|
11972
12030
|
function inspectDevrouter(repoPath) {
|
|
11973
12031
|
const configPath = getRepoConfigPath(repoPath);
|
|
11974
|
-
if (!
|
|
12032
|
+
if (!import_node_fs30.default.existsSync(configPath)) {
|
|
11975
12033
|
return {
|
|
11976
12034
|
exists: false,
|
|
11977
12035
|
configPath,
|
|
@@ -12015,15 +12073,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
12015
12073
|
["AGENTS.md", "agents"],
|
|
12016
12074
|
["CLAUDE.md", "claude"]
|
|
12017
12075
|
]) {
|
|
12018
|
-
if (
|
|
12076
|
+
if (import_node_fs30.default.existsSync(import_node_path31.default.join(repoPath, fileName))) {
|
|
12019
12077
|
results.push({ path: fileName, kind });
|
|
12020
12078
|
}
|
|
12021
12079
|
}
|
|
12022
12080
|
const skillsDir = import_node_path31.default.join(repoPath, ".agents", "skills");
|
|
12023
|
-
if (
|
|
12024
|
-
for (const name of
|
|
12081
|
+
if (import_node_fs30.default.existsSync(skillsDir)) {
|
|
12082
|
+
for (const name of import_node_fs30.default.readdirSync(skillsDir).sort()) {
|
|
12025
12083
|
const skillPath = import_node_path31.default.join(skillsDir, name, "SKILL.md");
|
|
12026
|
-
if (
|
|
12084
|
+
if (import_node_fs30.default.existsSync(skillPath)) {
|
|
12027
12085
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
12028
12086
|
}
|
|
12029
12087
|
}
|
|
@@ -12085,11 +12143,11 @@ function inspectRepo(options = {}) {
|
|
|
12085
12143
|
issues: buildIssues(reportWithoutIssues)
|
|
12086
12144
|
};
|
|
12087
12145
|
}
|
|
12088
|
-
var
|
|
12146
|
+
var import_node_fs30, import_node_path31, import_yaml6;
|
|
12089
12147
|
var init_repo_inspect = __esm({
|
|
12090
12148
|
"src/core/repo-inspect.ts"() {
|
|
12091
12149
|
"use strict";
|
|
12092
|
-
|
|
12150
|
+
import_node_fs30 = __toESM(require("fs"));
|
|
12093
12151
|
import_node_path31 = __toESM(require("path"));
|
|
12094
12152
|
import_yaml6 = __toESM(require("yaml"));
|
|
12095
12153
|
init_repo_config();
|
|
@@ -12195,7 +12253,7 @@ function requiredFileChecks(repoPath) {
|
|
|
12195
12253
|
".devcontainer/docker-compose.yml",
|
|
12196
12254
|
".devrouter.yml"
|
|
12197
12255
|
];
|
|
12198
|
-
const missing = required.filter((fileName) => !
|
|
12256
|
+
const missing = required.filter((fileName) => !import_node_fs31.default.existsSync(import_node_path32.default.join(repoPath, fileName)));
|
|
12199
12257
|
return {
|
|
12200
12258
|
id: "repo.devcontainer.verify-files",
|
|
12201
12259
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -12420,11 +12478,11 @@ async function verifyDevcontainer(options = {}) {
|
|
|
12420
12478
|
nextSteps: collectNextSteps3(checks)
|
|
12421
12479
|
};
|
|
12422
12480
|
}
|
|
12423
|
-
var
|
|
12481
|
+
var import_node_fs31, import_node_path32;
|
|
12424
12482
|
var init_devcontainer_verify = __esm({
|
|
12425
12483
|
"src/core/devcontainer-verify.ts"() {
|
|
12426
12484
|
"use strict";
|
|
12427
|
-
|
|
12485
|
+
import_node_fs31 = __toESM(require("fs"));
|
|
12428
12486
|
import_node_path32 = __toESM(require("path"));
|
|
12429
12487
|
init_capabilities();
|
|
12430
12488
|
init_doctor();
|
|
@@ -12768,7 +12826,7 @@ function plannedFiles(repoPath, version) {
|
|
|
12768
12826
|
}
|
|
12769
12827
|
function classifyFile(repoPath, file) {
|
|
12770
12828
|
const absolutePath = import_node_path33.default.join(repoPath, file.relativePath);
|
|
12771
|
-
if (!
|
|
12829
|
+
if (!import_node_fs32.default.existsSync(absolutePath)) {
|
|
12772
12830
|
return {
|
|
12773
12831
|
path: file.relativePath,
|
|
12774
12832
|
action: "create",
|
|
@@ -12776,7 +12834,7 @@ function classifyFile(repoPath, file) {
|
|
|
12776
12834
|
bytes: Buffer.byteLength(file.content)
|
|
12777
12835
|
};
|
|
12778
12836
|
}
|
|
12779
|
-
const current =
|
|
12837
|
+
const current = import_node_fs32.default.readFileSync(absolutePath, "utf-8");
|
|
12780
12838
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
12781
12839
|
return {
|
|
12782
12840
|
path: file.relativePath,
|
|
@@ -12834,10 +12892,10 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
12834
12892
|
}
|
|
12835
12893
|
function writeFile(repoPath, file) {
|
|
12836
12894
|
const absolutePath = import_node_path33.default.join(repoPath, file.relativePath);
|
|
12837
|
-
|
|
12838
|
-
|
|
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");
|
|
12839
12897
|
if (file.executable) {
|
|
12840
|
-
|
|
12898
|
+
import_node_fs32.default.chmodSync(absolutePath, 493);
|
|
12841
12899
|
}
|
|
12842
12900
|
}
|
|
12843
12901
|
function writeDevcontainer(options = {}) {
|
|
@@ -12875,11 +12933,11 @@ function writeDevcontainer(options = {}) {
|
|
|
12875
12933
|
nextSteps: postWriteNextSteps(repoPath)
|
|
12876
12934
|
};
|
|
12877
12935
|
}
|
|
12878
|
-
var
|
|
12936
|
+
var import_node_fs32, import_node_path33, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
12879
12937
|
var init_devcontainer_write = __esm({
|
|
12880
12938
|
"src/core/devcontainer-write.ts"() {
|
|
12881
12939
|
"use strict";
|
|
12882
|
-
|
|
12940
|
+
import_node_fs32 = __toESM(require("fs"));
|
|
12883
12941
|
import_node_path33 = __toESM(require("path"));
|
|
12884
12942
|
init_repo_config();
|
|
12885
12943
|
init_repo_inspect();
|
|
@@ -13293,7 +13351,7 @@ function loadContract(repoPath, contractPath) {
|
|
|
13293
13351
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
13294
13352
|
let metadata;
|
|
13295
13353
|
try {
|
|
13296
|
-
metadata =
|
|
13354
|
+
metadata = import_node_fs33.default.lstatSync(absolutePath);
|
|
13297
13355
|
} catch (error) {
|
|
13298
13356
|
fail(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
13299
13357
|
}
|
|
@@ -13303,10 +13361,10 @@ function loadContract(repoPath, contractPath) {
|
|
|
13303
13361
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
13304
13362
|
fail(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
13305
13363
|
}
|
|
13306
|
-
const realRepo =
|
|
13307
|
-
const realContract =
|
|
13364
|
+
const realRepo = import_node_fs33.default.realpathSync(repoPath);
|
|
13365
|
+
const realContract = import_node_fs33.default.realpathSync(absolutePath);
|
|
13308
13366
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
13309
|
-
const source =
|
|
13367
|
+
const source = import_node_fs33.default.readFileSync(absolutePath, "utf-8");
|
|
13310
13368
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
13311
13369
|
fail(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
13312
13370
|
}
|
|
@@ -13326,11 +13384,11 @@ function resolveProfilePlan(options) {
|
|
|
13326
13384
|
contractPath: loaded.contractPath
|
|
13327
13385
|
});
|
|
13328
13386
|
}
|
|
13329
|
-
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;
|
|
13330
13388
|
var init_profile_plan = __esm({
|
|
13331
13389
|
"src/core/profile-plan.ts"() {
|
|
13332
13390
|
"use strict";
|
|
13333
|
-
|
|
13391
|
+
import_node_fs33 = __toESM(require("fs"));
|
|
13334
13392
|
import_node_path34 = __toESM(require("path"));
|
|
13335
13393
|
import_yaml7 = require("yaml");
|
|
13336
13394
|
init_paths();
|
|
@@ -13776,10 +13834,10 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
13776
13834
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
13777
13835
|
}
|
|
13778
13836
|
const cachePath = import_node_path36.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
13779
|
-
|
|
13837
|
+
import_node_fs34.default.mkdirSync(cachePath, { recursive: true });
|
|
13780
13838
|
const overlayPath = import_node_path36.default.join(cachePath, "compose.devrouter.yml");
|
|
13781
13839
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
13782
|
-
|
|
13840
|
+
import_node_fs34.default.writeFileSync(overlayPath, import_yaml8.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
13783
13841
|
return {
|
|
13784
13842
|
overlayPath,
|
|
13785
13843
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -13793,7 +13851,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
13793
13851
|
fileArgs.push("-f", resolved);
|
|
13794
13852
|
}
|
|
13795
13853
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
13796
|
-
const result = (0,
|
|
13854
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13797
13855
|
encoding: "utf-8",
|
|
13798
13856
|
cwd: repoPath
|
|
13799
13857
|
});
|
|
@@ -13821,7 +13879,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
13821
13879
|
"--services",
|
|
13822
13880
|
...services
|
|
13823
13881
|
];
|
|
13824
|
-
const result = (0,
|
|
13882
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13825
13883
|
encoding: "utf-8",
|
|
13826
13884
|
cwd: repoPath
|
|
13827
13885
|
});
|
|
@@ -13847,7 +13905,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
13847
13905
|
fileArgs.push("-f", resolved);
|
|
13848
13906
|
}
|
|
13849
13907
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
13850
|
-
const result = (0,
|
|
13908
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13851
13909
|
encoding: "utf-8",
|
|
13852
13910
|
cwd: repoPath
|
|
13853
13911
|
});
|
|
@@ -13873,7 +13931,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
13873
13931
|
String(tail),
|
|
13874
13932
|
...services
|
|
13875
13933
|
];
|
|
13876
|
-
(0,
|
|
13934
|
+
(0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13877
13935
|
stdio: "inherit",
|
|
13878
13936
|
cwd: repoPath
|
|
13879
13937
|
});
|
|
@@ -13885,7 +13943,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
13885
13943
|
fileArgs.push("-f", resolved);
|
|
13886
13944
|
}
|
|
13887
13945
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
13888
|
-
const result = (0,
|
|
13946
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
13889
13947
|
encoding: "utf-8",
|
|
13890
13948
|
cwd: repoPath
|
|
13891
13949
|
});
|
|
@@ -13899,13 +13957,13 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
13899
13957
|
const port = Number(match[1]);
|
|
13900
13958
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
13901
13959
|
}
|
|
13902
|
-
var
|
|
13960
|
+
var import_node_child_process26, import_node_crypto11, import_node_fs34, import_node_path36, import_yaml8;
|
|
13903
13961
|
var init_docker_run = __esm({
|
|
13904
13962
|
"src/core/docker-run.ts"() {
|
|
13905
13963
|
"use strict";
|
|
13906
|
-
|
|
13964
|
+
import_node_child_process26 = require("child_process");
|
|
13907
13965
|
import_node_crypto11 = require("crypto");
|
|
13908
|
-
|
|
13966
|
+
import_node_fs34 = __toESM(require("fs"));
|
|
13909
13967
|
import_node_path36 = __toESM(require("path"));
|
|
13910
13968
|
import_yaml8 = __toESM(require("yaml"));
|
|
13911
13969
|
init_docker_error_guidance();
|
|
@@ -13996,7 +14054,7 @@ function isProcessRunning(pid) {
|
|
|
13996
14054
|
}
|
|
13997
14055
|
}
|
|
13998
14056
|
function readProcessTree(rootPid) {
|
|
13999
|
-
const result = (0,
|
|
14057
|
+
const result = (0, import_node_child_process27.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
14000
14058
|
if (result.status !== 0) {
|
|
14001
14059
|
return [rootPid];
|
|
14002
14060
|
}
|
|
@@ -14107,12 +14165,12 @@ function detectListeningPorts(pids) {
|
|
|
14107
14165
|
if (pids.length === 0) {
|
|
14108
14166
|
return [];
|
|
14109
14167
|
}
|
|
14110
|
-
const result = (0,
|
|
14168
|
+
const result = (0, import_node_child_process27.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
14111
14169
|
encoding: "utf-8"
|
|
14112
14170
|
});
|
|
14113
14171
|
if (result.error && result.error.code === "ENOENT") {
|
|
14114
14172
|
if (process.platform === "linux") {
|
|
14115
|
-
const ssResult = (0,
|
|
14173
|
+
const ssResult = (0, import_node_child_process27.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
14116
14174
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
14117
14175
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
14118
14176
|
}
|
|
@@ -14171,7 +14229,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
14171
14229
|
app.hostRun.command,
|
|
14172
14230
|
true
|
|
14173
14231
|
) : app.hostRun.command;
|
|
14174
|
-
const child = (0,
|
|
14232
|
+
const child = (0, import_node_child_process27.spawn)(spawnCommand, {
|
|
14175
14233
|
cwd: commandCwd,
|
|
14176
14234
|
stdio: "inherit",
|
|
14177
14235
|
shell: true,
|
|
@@ -14539,7 +14597,7 @@ async function execWithAppEnv(options) {
|
|
|
14539
14597
|
options.command[0],
|
|
14540
14598
|
true
|
|
14541
14599
|
);
|
|
14542
|
-
child = (0,
|
|
14600
|
+
child = (0, import_node_child_process27.spawn)(wrapped, {
|
|
14543
14601
|
cwd: deps.repoPath,
|
|
14544
14602
|
stdio: "inherit",
|
|
14545
14603
|
shell: true,
|
|
@@ -14553,7 +14611,7 @@ async function execWithAppEnv(options) {
|
|
|
14553
14611
|
false
|
|
14554
14612
|
);
|
|
14555
14613
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
14556
|
-
child = (0,
|
|
14614
|
+
child = (0, import_node_child_process27.spawn)(cmd, wrappedArgs, {
|
|
14557
14615
|
cwd: deps.repoPath,
|
|
14558
14616
|
stdio: "inherit",
|
|
14559
14617
|
shell: false,
|
|
@@ -14561,7 +14619,7 @@ async function execWithAppEnv(options) {
|
|
|
14561
14619
|
});
|
|
14562
14620
|
}
|
|
14563
14621
|
} else if (options.shell) {
|
|
14564
|
-
child = (0,
|
|
14622
|
+
child = (0, import_node_child_process27.spawn)(options.command[0], {
|
|
14565
14623
|
cwd: deps.repoPath,
|
|
14566
14624
|
stdio: "inherit",
|
|
14567
14625
|
shell: true,
|
|
@@ -14569,7 +14627,7 @@ async function execWithAppEnv(options) {
|
|
|
14569
14627
|
});
|
|
14570
14628
|
} else {
|
|
14571
14629
|
const [command, ...args] = options.command;
|
|
14572
|
-
child = (0,
|
|
14630
|
+
child = (0, import_node_child_process27.spawn)(command, args, {
|
|
14573
14631
|
cwd: deps.repoPath,
|
|
14574
14632
|
stdio: "inherit",
|
|
14575
14633
|
shell: false,
|
|
@@ -14590,11 +14648,11 @@ async function execWithAppEnv(options) {
|
|
|
14590
14648
|
deps.stopDeps();
|
|
14591
14649
|
}
|
|
14592
14650
|
}
|
|
14593
|
-
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;
|
|
14594
14652
|
var init_app_run = __esm({
|
|
14595
14653
|
"src/core/app-run.ts"() {
|
|
14596
14654
|
"use strict";
|
|
14597
|
-
|
|
14655
|
+
import_node_child_process27 = require("child_process");
|
|
14598
14656
|
import_node_net = __toESM(require("net"));
|
|
14599
14657
|
import_node_process = require("process");
|
|
14600
14658
|
import_promises = require("readline/promises");
|
|
@@ -14728,13 +14786,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14728
14786
|
const startedAt = Date.now();
|
|
14729
14787
|
let rootStat;
|
|
14730
14788
|
try {
|
|
14731
|
-
rootStat =
|
|
14789
|
+
rootStat = import_node_fs35.default.lstatSync(worktreePath);
|
|
14732
14790
|
} catch (error) {
|
|
14733
14791
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
14734
14792
|
}
|
|
14735
14793
|
let rootEntries;
|
|
14736
14794
|
try {
|
|
14737
|
-
rootEntries =
|
|
14795
|
+
rootEntries = import_node_fs35.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
14738
14796
|
} catch (error) {
|
|
14739
14797
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
14740
14798
|
}
|
|
@@ -14763,7 +14821,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14763
14821
|
const entryPath = import_node_path37.default.join(dirPath, entry.name);
|
|
14764
14822
|
let entryStat;
|
|
14765
14823
|
try {
|
|
14766
|
-
entryStat =
|
|
14824
|
+
entryStat = import_node_fs35.default.lstatSync(entryPath);
|
|
14767
14825
|
} catch (error) {
|
|
14768
14826
|
if (error?.code === "ENOENT") continue;
|
|
14769
14827
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -14773,7 +14831,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
14773
14831
|
if (!entryStat.isDirectory()) continue;
|
|
14774
14832
|
let childEntries;
|
|
14775
14833
|
try {
|
|
14776
|
-
childEntries =
|
|
14834
|
+
childEntries = import_node_fs35.default.readdirSync(entryPath, { withFileTypes: true });
|
|
14777
14835
|
} catch (error) {
|
|
14778
14836
|
unreadableReason = describeIncompleteWalk(error);
|
|
14779
14837
|
break;
|
|
@@ -14837,11 +14895,11 @@ function describeError(error, worktreePath) {
|
|
|
14837
14895
|
}
|
|
14838
14896
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
14839
14897
|
}
|
|
14840
|
-
var
|
|
14898
|
+
var import_node_fs35, import_node_path37, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
14841
14899
|
var init_workspace_consumption = __esm({
|
|
14842
14900
|
"src/core/workspace-consumption.ts"() {
|
|
14843
14901
|
"use strict";
|
|
14844
|
-
|
|
14902
|
+
import_node_fs35 = __toESM(require("fs"));
|
|
14845
14903
|
import_node_path37 = __toESM(require("path"));
|
|
14846
14904
|
init_devpod_environment();
|
|
14847
14905
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
@@ -14943,7 +15001,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
14943
15001
|
}
|
|
14944
15002
|
function readGitSnapshot(worktree, commandRunner) {
|
|
14945
15003
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
14946
|
-
if (worktree.prunable || !
|
|
15004
|
+
if (worktree.prunable || !import_node_fs36.default.existsSync(comparablePath)) {
|
|
14947
15005
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
14948
15006
|
}
|
|
14949
15007
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -15517,12 +15575,12 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
15517
15575
|
workspaces: rows
|
|
15518
15576
|
};
|
|
15519
15577
|
}
|
|
15520
|
-
var
|
|
15578
|
+
var import_node_child_process28, import_node_fs36, DEFAULT_INACTIVE_FOR, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
15521
15579
|
var init_workspace_cleanup = __esm({
|
|
15522
15580
|
"src/core/workspace-cleanup.ts"() {
|
|
15523
15581
|
"use strict";
|
|
15524
|
-
|
|
15525
|
-
|
|
15582
|
+
import_node_child_process28 = require("child_process");
|
|
15583
|
+
import_node_fs36 = __toESM(require("fs"));
|
|
15526
15584
|
init_devpod_workspaces();
|
|
15527
15585
|
init_host_routes();
|
|
15528
15586
|
init_repo_config();
|
|
@@ -15539,7 +15597,7 @@ var init_workspace_cleanup = __esm({
|
|
|
15539
15597
|
];
|
|
15540
15598
|
defaultCommandRunner = (command, args, input2) => {
|
|
15541
15599
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
15542
|
-
const result = (0,
|
|
15600
|
+
const result = (0, import_node_child_process28.spawnSync)(command, args, {
|
|
15543
15601
|
encoding: "utf-8",
|
|
15544
15602
|
env: environment,
|
|
15545
15603
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -15572,7 +15630,7 @@ function defaultWorktreePath(mainRepo, ws) {
|
|
|
15572
15630
|
return import_node_path38.default.join(mainRepo, "trees", ws);
|
|
15573
15631
|
}
|
|
15574
15632
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
15575
|
-
const ignored = (0,
|
|
15633
|
+
const ignored = (0, import_node_child_process29.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
15576
15634
|
encoding: "utf-8"
|
|
15577
15635
|
});
|
|
15578
15636
|
if (ignored.status !== 0) {
|
|
@@ -15694,13 +15752,13 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
15694
15752
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
15695
15753
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
15696
15754
|
}
|
|
15697
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
15755
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs37.default.existsSync(target.worktreePath)) return;
|
|
15698
15756
|
if (target.worktree.locked) {
|
|
15699
15757
|
throw new Error(
|
|
15700
15758
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
15701
15759
|
);
|
|
15702
15760
|
}
|
|
15703
|
-
const status = (0,
|
|
15761
|
+
const status = (0, import_node_child_process29.spawnSync)(
|
|
15704
15762
|
"git",
|
|
15705
15763
|
["-C", target.worktreePath, "status", "--porcelain", "--untracked-files=normal"],
|
|
15706
15764
|
{ encoding: "utf-8" }
|
|
@@ -15734,7 +15792,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15734
15792
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
15735
15793
|
);
|
|
15736
15794
|
const generatedPath = candidatePaths.find(
|
|
15737
|
-
(candidate) => !
|
|
15795
|
+
(candidate) => !import_node_fs37.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
15738
15796
|
);
|
|
15739
15797
|
const selectedPath = opts.path ? import_node_path38.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
15740
15798
|
if (!selectedPath) {
|
|
@@ -15745,7 +15803,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15745
15803
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
15746
15804
|
);
|
|
15747
15805
|
}
|
|
15748
|
-
if (
|
|
15806
|
+
if (import_node_fs37.default.existsSync(selectedPath)) {
|
|
15749
15807
|
const registered = worktrees.find(
|
|
15750
15808
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
15751
15809
|
);
|
|
@@ -15764,11 +15822,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
15764
15822
|
return selectedPath;
|
|
15765
15823
|
}
|
|
15766
15824
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
15767
|
-
const add = (0,
|
|
15825
|
+
const add = (0, import_node_child_process29.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
15768
15826
|
encoding: "utf-8"
|
|
15769
15827
|
});
|
|
15770
15828
|
if (add.status !== 0) {
|
|
15771
|
-
const addNew = (0,
|
|
15829
|
+
const addNew = (0, import_node_child_process29.spawnSync)(
|
|
15772
15830
|
"git",
|
|
15773
15831
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
15774
15832
|
{ encoding: "utf-8" }
|
|
@@ -15885,8 +15943,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
15885
15943
|
}
|
|
15886
15944
|
const result = await mutateWorkspaceRuntime("delete", resolved, worktrees, opts.quiet);
|
|
15887
15945
|
if (removeWorktree) {
|
|
15888
|
-
if (resolved.worktree && !resolved.worktree.prunable &&
|
|
15889
|
-
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], {
|
|
15890
15948
|
encoding: "utf-8"
|
|
15891
15949
|
});
|
|
15892
15950
|
if (rm.status !== 0) {
|
|
@@ -15904,7 +15962,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
15904
15962
|
}
|
|
15905
15963
|
return result;
|
|
15906
15964
|
};
|
|
15907
|
-
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();
|
|
15908
15966
|
}
|
|
15909
15967
|
async function workspaceStop(target, opts = {}) {
|
|
15910
15968
|
return runWorkspaceLifecycle("stop", target, opts);
|
|
@@ -15912,12 +15970,12 @@ async function workspaceStop(target, opts = {}) {
|
|
|
15912
15970
|
async function workspaceDown(target, opts = {}) {
|
|
15913
15971
|
return runWorkspaceLifecycle("down", target, opts);
|
|
15914
15972
|
}
|
|
15915
|
-
var
|
|
15973
|
+
var import_node_child_process29, import_node_fs37, import_node_path38, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
15916
15974
|
var init_workspace_lifecycle = __esm({
|
|
15917
15975
|
"src/core/workspace-lifecycle.ts"() {
|
|
15918
15976
|
"use strict";
|
|
15919
|
-
|
|
15920
|
-
|
|
15977
|
+
import_node_child_process29 = require("child_process");
|
|
15978
|
+
import_node_fs37 = __toESM(require("fs"));
|
|
15921
15979
|
import_node_path38 = __toESM(require("path"));
|
|
15922
15980
|
init_devpod_mutation();
|
|
15923
15981
|
init_devpod_workspaces();
|
|
@@ -16077,7 +16135,7 @@ var init_version = __esm({
|
|
|
16077
16135
|
|
|
16078
16136
|
// src/cli.ts
|
|
16079
16137
|
var import_commander = require("commander");
|
|
16080
|
-
var CLI_VERSION = true ? "0.0.
|
|
16138
|
+
var CLI_VERSION = true ? "0.0.58" : "0.0.0-dev";
|
|
16081
16139
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
16082
16140
|
function withErrorHandling(action2) {
|
|
16083
16141
|
return async (...args) => {
|