@devrouter/cli 0.6.3 → 0.6.5
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 +8579 -8128
- package/dist/devrouter.js +1220 -929
- package/package.json +1 -1
- package/upgrade-prompts/0.6.4.md +67 -0
- package/upgrade-prompts/0.6.5.md +45 -0
package/dist/devrouter.js
CHANGED
|
@@ -843,6 +843,52 @@ function runManagedStopDocker(args, endpoint, timeoutMs = MANAGED_STOP_DOCKER_TI
|
|
|
843
843
|
}
|
|
844
844
|
return result.stdout;
|
|
845
845
|
}
|
|
846
|
+
function inspectAppReplacementInventory(endpoint) {
|
|
847
|
+
const list2 = () => {
|
|
848
|
+
const ids3 = parseDockerLines(
|
|
849
|
+
runManagedStopDocker(["ps", "--all", "--quiet", "--no-trunc"], endpoint)
|
|
850
|
+
).sort();
|
|
851
|
+
if (ids3.length > 1024) throw new Error("App replacement daemon inventory exceeds its bound.");
|
|
852
|
+
ids3.forEach(assertFullContainerId);
|
|
853
|
+
assertUniqueContainerIds(ids3);
|
|
854
|
+
return ids3;
|
|
855
|
+
};
|
|
856
|
+
const ids2 = list2();
|
|
857
|
+
const template = '{"id":{{json .Id}},"name":{{json .Name}},"image":{{json .Image}},"namespaces":{"NetworkMode":{{json .HostConfig.NetworkMode}},"PidMode":{{json .HostConfig.PidMode}},"IpcMode":{{json .HostConfig.IpcMode}}},"mounts":{{json .Mounts}}}';
|
|
858
|
+
const containers2 = ids2.length ? parseDockerLines(
|
|
859
|
+
runManagedStopDocker(["inspect", "--format", template, ...ids2], endpoint)
|
|
860
|
+
).map((line) => {
|
|
861
|
+
const c = JSON.parse(line);
|
|
862
|
+
if (!isRecord(c)) throw new Error("Invalid replacement container inventory.");
|
|
863
|
+
assertFullContainerId(c.id);
|
|
864
|
+
if (typeof c.name !== "string" || !/^\/[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(c.name) || typeof c.image !== "string" || !/^sha256:[a-f0-9]{64}$/.test(c.image) || !isRecord(c.namespaces) || !["NetworkMode", "PidMode", "IpcMode"].every(
|
|
865
|
+
(key) => typeof c.namespaces[key] === "string"
|
|
866
|
+
) || !Array.isArray(c.mounts) || c.mounts.some(
|
|
867
|
+
(m) => !isRecord(m) || typeof m.Type !== "string" || typeof m.Source !== "string" || typeof m.Destination !== "string" || m.Type === "volume" && (typeof m.Name !== "string" || !m.Name)
|
|
868
|
+
))
|
|
869
|
+
throw new Error("Incomplete app replacement inventory.");
|
|
870
|
+
return c;
|
|
871
|
+
}) : [];
|
|
872
|
+
if (JSON.stringify(ids2) !== JSON.stringify(containers2.map((c) => c.id).sort()) || JSON.stringify(ids2) !== JSON.stringify(list2()) || new Set(containers2.map((c) => c.name)).size !== containers2.length)
|
|
873
|
+
throw new Error("App replacement daemon inventory changed during inspection.");
|
|
874
|
+
return containers2;
|
|
875
|
+
}
|
|
876
|
+
function assertNoAppNamespaceConsumers(containers2, primaryId) {
|
|
877
|
+
const primary = containers2.find((c) => c.id === primaryId);
|
|
878
|
+
if (!primary) throw new Error("App replacement lost the exact primary container.");
|
|
879
|
+
for (const c of containers2)
|
|
880
|
+
for (const mode of Object.values(c.namespaces)) {
|
|
881
|
+
if (!mode.startsWith("container:")) continue;
|
|
882
|
+
const reference = mode.slice("container:".length).replace(/^\//, "");
|
|
883
|
+
const matches = containers2.filter(
|
|
884
|
+
(candidate) => candidate.name.slice(1) === reference || /^[a-f0-9]+$/.test(reference) && candidate.id.startsWith(reference)
|
|
885
|
+
);
|
|
886
|
+
if (matches.length !== 1 || c.id === primaryId || matches[0].id === primaryId)
|
|
887
|
+
throw new Error(
|
|
888
|
+
"App replacement refuses unresolved or primary-dependent network, PID or IPC namespaces."
|
|
889
|
+
);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
846
892
|
function listManagedStopContainerIds(composeProject, endpoint) {
|
|
847
893
|
const stdout = runManagedStopDocker(
|
|
848
894
|
[
|
|
@@ -4898,7 +4944,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs8.default.read
|
|
|
4898
4944
|
const config = parseRepoConfigSource(raw, configPath);
|
|
4899
4945
|
const requiredVersion = config.devrouter?.version;
|
|
4900
4946
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4901
|
-
const cliVersion = true ? "0.6.
|
|
4947
|
+
const cliVersion = true ? "0.6.5" : "0.0.0-dev";
|
|
4902
4948
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4903
4949
|
hasWarnedVersionMismatch = true;
|
|
4904
4950
|
process.stderr.write(
|
|
@@ -7170,8 +7216,57 @@ var init_reliability_contract = __esm({
|
|
|
7170
7216
|
});
|
|
7171
7217
|
|
|
7172
7218
|
// src/core/reliability-operation-store.ts
|
|
7219
|
+
function appReplacementPath(identity2) {
|
|
7220
|
+
const directory = import_node_path16.default.join(DEVROUTER_HOME, "replacement-attempts");
|
|
7221
|
+
if (import_node_fs13.default.existsSync(directory)) {
|
|
7222
|
+
const stat = import_node_fs13.default.lstatSync(directory);
|
|
7223
|
+
if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
7224
|
+
throw new Error("App replacement directory must be private and not symlinked.");
|
|
7225
|
+
}
|
|
7226
|
+
return import_node_path16.default.join(directory, `${identityKey(identity2)}.json`);
|
|
7227
|
+
}
|
|
7228
|
+
function readAppReplacementAttempt(identity2) {
|
|
7229
|
+
const value = readBoundedPrivateJson(appReplacementPath(identity2), "App replacement attempt");
|
|
7230
|
+
if (value === void 0) return void 0;
|
|
7231
|
+
return validateAppReplacementAttempt(value, identity2);
|
|
7232
|
+
}
|
|
7233
|
+
function validateAppReplacementAttempt(value, identity2) {
|
|
7234
|
+
const attempt = value;
|
|
7235
|
+
keys(attempt, [
|
|
7236
|
+
"version",
|
|
7237
|
+
"identity",
|
|
7238
|
+
"operationId",
|
|
7239
|
+
"workerId",
|
|
7240
|
+
"fence",
|
|
7241
|
+
"stoppedFence",
|
|
7242
|
+
"oldPrimaryId",
|
|
7243
|
+
"preflightSha256",
|
|
7244
|
+
"stage",
|
|
7245
|
+
"newPrimaryId"
|
|
7246
|
+
]);
|
|
7247
|
+
exactKeys(
|
|
7248
|
+
attempt.identity,
|
|
7249
|
+
["repoPath", "workspace", "provider"],
|
|
7250
|
+
"Invalid replacement identity."
|
|
7251
|
+
);
|
|
7252
|
+
identityKey(attempt.identity);
|
|
7253
|
+
for (const fence of [attempt.fence, attempt.stoppedFence]) {
|
|
7254
|
+
exactKeys(
|
|
7255
|
+
fence,
|
|
7256
|
+
["environmentId", "intentRevision", "runtimeGeneration", "controllerEpoch"],
|
|
7257
|
+
"Invalid replacement fence."
|
|
7258
|
+
);
|
|
7259
|
+
if (!isReliabilityId(fence.environmentId) || ![fence.intentRevision, fence.runtimeGeneration, fence.controllerEpoch].every(
|
|
7260
|
+
isReliabilityCounter
|
|
7261
|
+
))
|
|
7262
|
+
throw new Error("Invalid replacement fence.");
|
|
7263
|
+
}
|
|
7264
|
+
if (attempt.version !== 1 || !(0, import_node_util3.isDeepStrictEqual)(attempt.identity, identity2) || !isReliabilityId(attempt.operationId) || !isReliabilityId(attempt.workerId) || !/^[a-f0-9]{64}$/.test(attempt.oldPrimaryId) || !/^[a-f0-9]{64}$/.test(attempt.preflightSha256) || !["claimed", "dispatched", "replaced", "ready"].includes(attempt.stage) || attempt.fence.environmentId !== attempt.stoppedFence.environmentId || attempt.fence.runtimeGeneration !== attempt.stoppedFence.runtimeGeneration || attempt.fence.controllerEpoch !== attempt.stoppedFence.controllerEpoch || attempt.fence.intentRevision !== attempt.stoppedFence.intentRevision + 1 || attempt.newPrimaryId !== void 0 && (!/^[a-f0-9]{64}$/.test(attempt.newPrimaryId) || attempt.newPrimaryId === attempt.oldPrimaryId) || ["claimed", "dispatched"].includes(attempt.stage) && attempt.newPrimaryId !== void 0 || ["replaced", "ready"].includes(attempt.stage) && !attempt.newPrimaryId)
|
|
7265
|
+
throw new Error("Invalid app replacement attempt.");
|
|
7266
|
+
return attempt;
|
|
7267
|
+
}
|
|
7173
7268
|
function installedCliVersion() {
|
|
7174
|
-
return true ? "0.6.
|
|
7269
|
+
return true ? "0.6.5" : "0.0.0-dev";
|
|
7175
7270
|
}
|
|
7176
7271
|
function compareCliVersions(left, right) {
|
|
7177
7272
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -7372,8 +7467,10 @@ function validate2(record6, identity2) {
|
|
|
7372
7467
|
}
|
|
7373
7468
|
}
|
|
7374
7469
|
if (record6.writtenByVersion !== void 0 && compareCliVersions(record6.writtenByVersion, installedCliVersion()) > 0) {
|
|
7375
|
-
throw new
|
|
7376
|
-
|
|
7470
|
+
throw new ReliabilityJournalError(
|
|
7471
|
+
"journal-writer-newer",
|
|
7472
|
+
journalEntryLocation(import_node_path16.default.basename(reliabilityOperationPath(identity2))),
|
|
7473
|
+
"Reliability record was written by a newer devrouter CLI; use a matching or newer CLI before retrying lifecycle commands. Preserve the journal."
|
|
7377
7474
|
);
|
|
7378
7475
|
}
|
|
7379
7476
|
keys(record6.identity, ["repoPath", "workspace", "provider"]);
|
|
@@ -11722,6 +11819,11 @@ async function prepareDevsyAgent(options = {}) {
|
|
|
11722
11819
|
return { ...preparedFromInspection(published), changed: true, transport };
|
|
11723
11820
|
});
|
|
11724
11821
|
}
|
|
11822
|
+
function requireReadyDevsyAgent(options = {}) {
|
|
11823
|
+
const inspection = inspectDevsyAgent(options);
|
|
11824
|
+
if (!isReadyInspection(inspection)) throw new DevsyAgentReadinessError(inspection);
|
|
11825
|
+
return preparedFromInspection(inspection);
|
|
11826
|
+
}
|
|
11725
11827
|
var import_node_child_process13, import_node_crypto13, import_node_fs21, import_node_path28, PINNED_DEVSY_AGENT_VERSION, SUPPORTED_DEVSY_MIN_VERSION, SUPPORTED_DEVSY_MAX_VERSION, SUPPORTED_DEVSY_RANGE, DEVSY_AGENT_SETUP_COMMAND, DEVSY_RELEASE_TAG_PREFIX, DEVSY_RELEASE_METADATA_BASE_URL, DEVSY_AGENT_ASSETS, DevsyAgentReadinessError, DEVSY_AGENT_CACHE_LOCK, DEVSY_AGENT_LOCK_WAIT_MS, DEVSY_AGENT_MANIFEST_FILE, DEVSY_AGENT_ASSET_NAMES, GITHUB_CLI_STDERR_TAIL_BYTES;
|
|
11726
11828
|
var init_devsy_agent = __esm({
|
|
11727
11829
|
"src/core/devsy-agent.ts"() {
|
|
@@ -11818,6 +11920,412 @@ var init_managed_compose_population = __esm({
|
|
|
11818
11920
|
}
|
|
11819
11921
|
});
|
|
11820
11922
|
|
|
11923
|
+
// src/core/managed-host-ports.ts
|
|
11924
|
+
function unavailableEntry(declaration, reason2) {
|
|
11925
|
+
return { ...declaration, status: "unavailable", reason: reason2 };
|
|
11926
|
+
}
|
|
11927
|
+
function livePublishedBindings(containerId, target) {
|
|
11928
|
+
const result = (0, import_node_child_process14.spawnSync)("docker", ["port", containerId, `${target}/tcp`], {
|
|
11929
|
+
encoding: "utf-8",
|
|
11930
|
+
timeout: PORT_LOOKUP_TIMEOUT_MS,
|
|
11931
|
+
maxBuffer: PORT_LOOKUP_MAX_BUFFER,
|
|
11932
|
+
...networkDockerOptions()
|
|
11933
|
+
});
|
|
11934
|
+
if (result.error || result.status === null) return void 0;
|
|
11935
|
+
if (result.status !== 0) return "";
|
|
11936
|
+
return typeof result.stdout === "string" ? result.stdout : void 0;
|
|
11937
|
+
}
|
|
11938
|
+
function parseLoopbackBinding(output2) {
|
|
11939
|
+
const lines = output2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
11940
|
+
if (lines.length === 0) return { reason: "not-published" };
|
|
11941
|
+
if (lines.length > 1) return { reason: "ambiguous" };
|
|
11942
|
+
const match = LOOPBACK_BINDING.exec(lines[0]);
|
|
11943
|
+
if (!match) return { reason: "not-published" };
|
|
11944
|
+
const port = Number(match[1]);
|
|
11945
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) return { reason: "not-published" };
|
|
11946
|
+
return { endpoint: { host: "127.0.0.1", port } };
|
|
11947
|
+
}
|
|
11948
|
+
function revalidateLiveOwner(containerId, input2, composeProject, composeFiles2, service) {
|
|
11949
|
+
try {
|
|
11950
|
+
const current = inspectWorkspaceContainers({ ids: [containerId] });
|
|
11951
|
+
if (current.length !== 1 || current[0].id !== containerId) return "unavailable";
|
|
11952
|
+
if (!hasExactComposeIdentity(current[0], {
|
|
11953
|
+
repoPath: input2.repoPath,
|
|
11954
|
+
service,
|
|
11955
|
+
composeProject,
|
|
11956
|
+
composeFiles: composeFiles2
|
|
11957
|
+
})) {
|
|
11958
|
+
return "unavailable";
|
|
11959
|
+
}
|
|
11960
|
+
return current[0].state.Running ? "available" : "not-running";
|
|
11961
|
+
} catch {
|
|
11962
|
+
return "unavailable";
|
|
11963
|
+
}
|
|
11964
|
+
}
|
|
11965
|
+
function resolveManagedHostPorts(input2) {
|
|
11966
|
+
const report = {};
|
|
11967
|
+
const selectedServices = new Set(input2.selectedServices);
|
|
11968
|
+
const selectedKeys = [];
|
|
11969
|
+
for (const [key, declaration] of Object.entries(input2.declarations)) {
|
|
11970
|
+
if (!selectedServices.has(declaration.service)) {
|
|
11971
|
+
report[key] = { ...declaration, status: "inactive" };
|
|
11972
|
+
continue;
|
|
11973
|
+
}
|
|
11974
|
+
selectedKeys.push(key);
|
|
11975
|
+
report[key] = { ...declaration, status: "unavailable", reason: "unavailable" };
|
|
11976
|
+
}
|
|
11977
|
+
if (selectedKeys.length === 0) return report;
|
|
11978
|
+
const composeProject = input2.composeProject;
|
|
11979
|
+
const composeFiles2 = input2.composeFiles;
|
|
11980
|
+
if (typeof composeProject !== "string" || composeProject.length === 0 || composeFiles2 === void 0 || composeFiles2.length === 0 || composeFiles2.some((file) => file.length === 0)) {
|
|
11981
|
+
return report;
|
|
11982
|
+
}
|
|
11983
|
+
if (selectedKeys.some((key) => {
|
|
11984
|
+
const target = input2.declarations[key].target;
|
|
11985
|
+
return !Number.isInteger(target) || target < 1 || target > 65535;
|
|
11986
|
+
})) {
|
|
11987
|
+
return report;
|
|
11988
|
+
}
|
|
11989
|
+
const liveContainers = input2.containers === void 0;
|
|
11990
|
+
let containers2 = input2.containers;
|
|
11991
|
+
if (containers2 === void 0) {
|
|
11992
|
+
try {
|
|
11993
|
+
containers2 = inspectWorkspaceContainers({ composeProject });
|
|
11994
|
+
} catch {
|
|
11995
|
+
return report;
|
|
11996
|
+
}
|
|
11997
|
+
}
|
|
11998
|
+
const publishedBindings = input2.publishedBindings ?? livePublishedBindings;
|
|
11999
|
+
for (const key of selectedKeys) {
|
|
12000
|
+
const declaration = input2.declarations[key];
|
|
12001
|
+
let owners;
|
|
12002
|
+
try {
|
|
12003
|
+
owners = containers2.filter(
|
|
12004
|
+
(container) => hasExactComposeIdentity(container, {
|
|
12005
|
+
repoPath: input2.repoPath,
|
|
12006
|
+
service: declaration.service,
|
|
12007
|
+
composeProject,
|
|
12008
|
+
composeFiles: composeFiles2
|
|
12009
|
+
})
|
|
12010
|
+
);
|
|
12011
|
+
} catch {
|
|
12012
|
+
report[key] = unavailableEntry(declaration, "unavailable");
|
|
12013
|
+
continue;
|
|
12014
|
+
}
|
|
12015
|
+
if (owners.length === 0) {
|
|
12016
|
+
report[key] = unavailableEntry(declaration, "not-found");
|
|
12017
|
+
continue;
|
|
12018
|
+
}
|
|
12019
|
+
if (owners.length > 1) {
|
|
12020
|
+
report[key] = unavailableEntry(declaration, "ambiguous");
|
|
12021
|
+
continue;
|
|
12022
|
+
}
|
|
12023
|
+
const owner = owners[0];
|
|
12024
|
+
if (!owner.state.Running) {
|
|
12025
|
+
report[key] = unavailableEntry(declaration, "not-running");
|
|
12026
|
+
continue;
|
|
12027
|
+
}
|
|
12028
|
+
let output2;
|
|
12029
|
+
try {
|
|
12030
|
+
output2 = publishedBindings(owner.id, declaration.target);
|
|
12031
|
+
} catch {
|
|
12032
|
+
output2 = void 0;
|
|
12033
|
+
}
|
|
12034
|
+
if (typeof output2 !== "string") {
|
|
12035
|
+
report[key] = unavailableEntry(declaration, "unavailable");
|
|
12036
|
+
continue;
|
|
12037
|
+
}
|
|
12038
|
+
const binding = parseLoopbackBinding(output2);
|
|
12039
|
+
if (!binding.endpoint) {
|
|
12040
|
+
report[key] = unavailableEntry(declaration, binding.reason ?? "unavailable");
|
|
12041
|
+
continue;
|
|
12042
|
+
}
|
|
12043
|
+
if (liveContainers) {
|
|
12044
|
+
const proof = revalidateLiveOwner(
|
|
12045
|
+
owner.id,
|
|
12046
|
+
input2,
|
|
12047
|
+
composeProject,
|
|
12048
|
+
composeFiles2,
|
|
12049
|
+
declaration.service
|
|
12050
|
+
);
|
|
12051
|
+
if (proof !== "available") {
|
|
12052
|
+
report[key] = unavailableEntry(declaration, proof);
|
|
12053
|
+
continue;
|
|
12054
|
+
}
|
|
12055
|
+
}
|
|
12056
|
+
report[key] = {
|
|
12057
|
+
...declaration,
|
|
12058
|
+
status: "available",
|
|
12059
|
+
endpoint: binding.endpoint
|
|
12060
|
+
};
|
|
12061
|
+
}
|
|
12062
|
+
return report;
|
|
12063
|
+
}
|
|
12064
|
+
function managedHostPortDeclarationsIdentity(declarations) {
|
|
12065
|
+
const keys2 = Object.keys(declarations).sort();
|
|
12066
|
+
if (keys2.length === 0) return void 0;
|
|
12067
|
+
const canonical = keys2.map((key) => [key, declarations[key].service, declarations[key].target]);
|
|
12068
|
+
return (0, import_node_crypto14.createHash)("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
12069
|
+
}
|
|
12070
|
+
function assertManagedHostPortsAvailable(report) {
|
|
12071
|
+
const unavailable = Object.entries(report).filter(([, entry]) => entry.status === "unavailable").map(([key]) => key).sort();
|
|
12072
|
+
if (unavailable.length > 0) {
|
|
12073
|
+
throw new Error(`Selected managed host ports are unavailable: ${unavailable.join(", ")}.`);
|
|
12074
|
+
}
|
|
12075
|
+
}
|
|
12076
|
+
var import_node_child_process14, import_node_crypto14, PORT_LOOKUP_TIMEOUT_MS, PORT_LOOKUP_MAX_BUFFER, LOOPBACK_BINDING;
|
|
12077
|
+
var init_managed_host_ports = __esm({
|
|
12078
|
+
"src/core/managed-host-ports.ts"() {
|
|
12079
|
+
"use strict";
|
|
12080
|
+
import_node_child_process14 = require("child_process");
|
|
12081
|
+
import_node_crypto14 = require("crypto");
|
|
12082
|
+
init_devpod_environment();
|
|
12083
|
+
init_network_effect_scope();
|
|
12084
|
+
PORT_LOOKUP_TIMEOUT_MS = 1e4;
|
|
12085
|
+
PORT_LOOKUP_MAX_BUFFER = 64 * 1024;
|
|
12086
|
+
LOOPBACK_BINDING = /^127\.0\.0\.1:(\d+)$/;
|
|
12087
|
+
}
|
|
12088
|
+
});
|
|
12089
|
+
|
|
12090
|
+
// src/core/managed-post-start.ts
|
|
12091
|
+
function readRegularFileBytes(filePath) {
|
|
12092
|
+
if (!import_node_fs23.default.existsSync(filePath) || !import_node_fs23.default.lstatSync(filePath).isFile()) return void 0;
|
|
12093
|
+
return import_node_fs23.default.readFileSync(filePath);
|
|
12094
|
+
}
|
|
12095
|
+
function readRegularFile(filePath) {
|
|
12096
|
+
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
12097
|
+
}
|
|
12098
|
+
function adapterFingerprint(adapter) {
|
|
12099
|
+
return (0, import_node_crypto15.createHash)("sha256").update(adapter).digest("hex");
|
|
12100
|
+
}
|
|
12101
|
+
function resolveManagedPostStartPlan(repoPath) {
|
|
12102
|
+
const adapterPath = import_node_path30.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
12103
|
+
const adapterBytes = readRegularFileBytes(adapterPath);
|
|
12104
|
+
const adapterText = adapterBytes?.toString("utf-8");
|
|
12105
|
+
const dockerfilePath = import_node_path30.default.join(repoPath, ".devcontainer", "Dockerfile");
|
|
12106
|
+
const devcontainerPath = import_node_path30.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
12107
|
+
const dockerfile = readRegularFile(dockerfilePath) ?? "";
|
|
12108
|
+
const devcontainer = readRegularFile(devcontainerPath) ?? "";
|
|
12109
|
+
const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
|
|
12110
|
+
(value) => value.includes("DEVROUTER_PROCESS_HELPER") || value.includes("devrouter-process")
|
|
12111
|
+
);
|
|
12112
|
+
if (adapterBytes === void 0) {
|
|
12113
|
+
if (devrouterPattern) {
|
|
12114
|
+
throw new Error(
|
|
12115
|
+
"Devrouter lifecycle wiring is incomplete: add the managed post-start adapter or remove the stale devrouter-process references."
|
|
12116
|
+
);
|
|
12117
|
+
}
|
|
12118
|
+
return { kind: "unmanaged" };
|
|
12119
|
+
}
|
|
12120
|
+
const adapter = adapterBytes.toString("utf-8");
|
|
12121
|
+
if (!adapter.includes(MANAGED_MARKER)) {
|
|
12122
|
+
if (devrouterPattern) {
|
|
12123
|
+
throw new Error(
|
|
12124
|
+
"Devrouter-looking post-start adapter is missing the 'devrouter:managed devcontainer' marker. Regenerate or migrate the devcontainer, then retry devrouter ensure."
|
|
12125
|
+
);
|
|
12126
|
+
}
|
|
12127
|
+
return { kind: "unmanaged" };
|
|
12128
|
+
}
|
|
12129
|
+
assertManagedDevcontainerLifecycle(repoPath);
|
|
12130
|
+
if (adapter.includes("DEVROUTER_PROCESS_HELPER")) {
|
|
12131
|
+
return {
|
|
12132
|
+
kind: "runtime",
|
|
12133
|
+
adapterPath: MANAGED_ADAPTER_PATH,
|
|
12134
|
+
adapterSha256: adapterFingerprint(adapterBytes),
|
|
12135
|
+
adapterContents: adapterBytes
|
|
12136
|
+
};
|
|
12137
|
+
}
|
|
12138
|
+
if (dockerfile.includes("devrouter-process") && devcontainer.includes("postStartCommand")) {
|
|
12139
|
+
return { kind: "legacy" };
|
|
12140
|
+
}
|
|
12141
|
+
throw new Error(
|
|
12142
|
+
"Managed post-start must use DEVROUTER_PROCESS_HELPER before removing the legacy image helper and postStartCommand. Regenerate or migrate the devcontainer, then retry devrouter ensure."
|
|
12143
|
+
);
|
|
12144
|
+
}
|
|
12145
|
+
function assertSafeProcessName(name) {
|
|
12146
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {
|
|
12147
|
+
throw new Error(`Managed process '${name}' is not a safe exact identifier.`);
|
|
12148
|
+
}
|
|
12149
|
+
}
|
|
12150
|
+
function runManagedProcessAction(options) {
|
|
12151
|
+
assertSafeProcessName(options.name);
|
|
12152
|
+
const result = (0, import_node_child_process15.spawnSync)(
|
|
12153
|
+
"docker",
|
|
12154
|
+
[
|
|
12155
|
+
"exec",
|
|
12156
|
+
"--workdir",
|
|
12157
|
+
options.container.workspacePath,
|
|
12158
|
+
"--env",
|
|
12159
|
+
`DEVROUTER_PROCESS_HELPER=${RUNTIME_HELPER_PATH}`,
|
|
12160
|
+
options.container.id,
|
|
12161
|
+
"bash",
|
|
12162
|
+
"-c",
|
|
12163
|
+
'exec "$DEVROUTER_PROCESS_HELPER" "$1" --name "$2"',
|
|
12164
|
+
"devrouter-process",
|
|
12165
|
+
options.action,
|
|
12166
|
+
options.name
|
|
12167
|
+
],
|
|
12168
|
+
{
|
|
12169
|
+
encoding: "utf-8",
|
|
12170
|
+
stdio: options.action === "status" ? ["ignore", "pipe", "pipe"] : ["ignore", 2, "inherit"],
|
|
12171
|
+
...networkDockerOptions()
|
|
12172
|
+
}
|
|
12173
|
+
);
|
|
12174
|
+
if (options.action === "stop") {
|
|
12175
|
+
if (result.status !== 0) {
|
|
12176
|
+
throw new Error(`Could not stop managed process '${options.name}'.`);
|
|
12177
|
+
}
|
|
12178
|
+
return "stopped";
|
|
12179
|
+
}
|
|
12180
|
+
try {
|
|
12181
|
+
const parsed = JSON.parse(result.stdout.trim());
|
|
12182
|
+
if (parsed.status === "running" || parsed.status === "stopped" || parsed.status === "foreign" || parsed.status === "drifted") {
|
|
12183
|
+
return parsed.status;
|
|
12184
|
+
}
|
|
12185
|
+
} catch {
|
|
12186
|
+
}
|
|
12187
|
+
return "drifted";
|
|
12188
|
+
}
|
|
12189
|
+
var import_node_child_process15, import_node_crypto15, import_node_fs23, import_node_path30, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH;
|
|
12190
|
+
var init_managed_post_start = __esm({
|
|
12191
|
+
"src/core/managed-post-start.ts"() {
|
|
12192
|
+
"use strict";
|
|
12193
|
+
import_node_child_process15 = require("child_process");
|
|
12194
|
+
import_node_crypto15 = require("crypto");
|
|
12195
|
+
import_node_fs23 = __toESM(require("fs"));
|
|
12196
|
+
import_node_path30 = __toESM(require("path"));
|
|
12197
|
+
init_devcontainer_config();
|
|
12198
|
+
init_managed_host_ports();
|
|
12199
|
+
init_network_effect_scope();
|
|
12200
|
+
MANAGED_MARKER = "devrouter:managed devcontainer";
|
|
12201
|
+
MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
|
|
12202
|
+
RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
|
|
12203
|
+
}
|
|
12204
|
+
});
|
|
12205
|
+
|
|
12206
|
+
// src/core/network-provider-inspect.ts
|
|
12207
|
+
function object3(value) {
|
|
12208
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
12209
|
+
throw new Error("Invalid provider evidence.");
|
|
12210
|
+
return value;
|
|
12211
|
+
}
|
|
12212
|
+
function qualifyNetworkProviderDefinition(value, provider) {
|
|
12213
|
+
const definition = object3(value);
|
|
12214
|
+
const agent = object3(definition.agent);
|
|
12215
|
+
const docker = object3(agent.docker);
|
|
12216
|
+
const env = object3(docker.env);
|
|
12217
|
+
const options = object3(definition.options);
|
|
12218
|
+
const host = object3(options.DOCKER_HOST);
|
|
12219
|
+
const dockerPath = object3(options.DOCKER_PATH);
|
|
12220
|
+
const exec = object3(definition.exec);
|
|
12221
|
+
const command = provider === "devsy" ? '"${DEVSY}" internal sh -c "${COMMAND}"' : '"${DEVPOD}" helper sh -c "${COMMAND}"';
|
|
12222
|
+
const actualCommand = Array.isArray(exec.command) ? exec.command : [exec.command];
|
|
12223
|
+
if (definition.name !== "docker" || ![true, "true"].includes(agent.local) || agent.driver !== void 0 && agent.driver !== "docker" && agent.driver !== "" || docker.path !== "${DOCKER_PATH}" || docker.builder !== "${DOCKER_BUILDER}" || ![false, "false"].includes(docker.install) || (provider === "devsy" ? docker.elevation !== "${DOCKER_ELEVATION}" : docker.elevation !== void 0 && docker.elevation !== "") || env.DOCKER_HOST !== "${DOCKER_HOST}" || Object.keys(env).some((key) => key !== "DOCKER_HOST") || host.global !== true || dockerPath.default !== "docker" || actualCommand.length !== 1 || typeof actualCommand[0] !== "string" || actualCommand[0].trim() !== command || Object.keys(exec).some((key) => key !== "command") || agent.path !== void 0 && agent.path !== "" || agent.downloadURL !== void 0 && agent.downloadURL !== "") {
|
|
12224
|
+
throw new Error("Docker provider definition is not qualified for network allocation.");
|
|
12225
|
+
}
|
|
12226
|
+
return (0, import_node_crypto16.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
|
|
12227
|
+
}
|
|
12228
|
+
function read(provider, args) {
|
|
12229
|
+
const result = (0, import_node_child_process16.spawnSync)(provider, args, {
|
|
12230
|
+
encoding: "utf8",
|
|
12231
|
+
timeout: 5e3,
|
|
12232
|
+
maxBuffer: 2 * 1024 * 1024
|
|
12233
|
+
});
|
|
12234
|
+
if (result.error || result.status !== 0)
|
|
12235
|
+
throw new Error("Network provider evidence is unavailable.");
|
|
12236
|
+
return result.stdout;
|
|
12237
|
+
}
|
|
12238
|
+
function inspectNetworkProviderBinding(input2) {
|
|
12239
|
+
try {
|
|
12240
|
+
const { provider, providerId, repoPath } = input2;
|
|
12241
|
+
const contexts = JSON.parse(
|
|
12242
|
+
read(provider, [
|
|
12243
|
+
"context",
|
|
12244
|
+
"list",
|
|
12245
|
+
...provider === "devsy" ? ["--result-format", "json"] : ["--output", "json"]
|
|
12246
|
+
])
|
|
12247
|
+
);
|
|
12248
|
+
if (!Array.isArray(contexts) || contexts.length > 128) throw new Error();
|
|
12249
|
+
const selected = contexts.map(object3).filter(
|
|
12250
|
+
(row) => input2.providerContext ? row.name === input2.providerContext : row.default === true
|
|
12251
|
+
);
|
|
12252
|
+
if (selected.length !== 1 || typeof selected[0].name !== "string") throw new Error();
|
|
12253
|
+
const providerContext = selected[0].name;
|
|
12254
|
+
if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(providerContext)) throw new Error();
|
|
12255
|
+
const contextArgs = ["--context", providerContext];
|
|
12256
|
+
const version = read(provider, provider === "devsy" ? ["--version"] : ["version"]);
|
|
12257
|
+
const parsedVersion = version.match(/\b(?:v)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\b/)?.[1];
|
|
12258
|
+
if (provider === "devsy" ? !isSupportedDevsyVersion(parsedVersion) : parsedVersion !== "0.6.15")
|
|
12259
|
+
throw new Error();
|
|
12260
|
+
const definitions = object3(
|
|
12261
|
+
JSON.parse(
|
|
12262
|
+
read(
|
|
12263
|
+
provider,
|
|
12264
|
+
provider === "devsy" ? ["provider", "list", "--result-format", "json", ...contextArgs] : ["provider", "list", "--output", "json", ...contextArgs]
|
|
12265
|
+
)
|
|
12266
|
+
)
|
|
12267
|
+
);
|
|
12268
|
+
const entry = object3(definitions.docker);
|
|
12269
|
+
const definitionSha256 = qualifyNetworkProviderDefinition(entry.config, provider);
|
|
12270
|
+
const rows2 = JSON.parse(
|
|
12271
|
+
read(
|
|
12272
|
+
provider,
|
|
12273
|
+
provider === "devsy" ? ["workspace", "list", "--result-format", "json", "--skip-pro", ...contextArgs] : ["list", "--output", "json", "--skip-pro", ...contextArgs]
|
|
12274
|
+
)
|
|
12275
|
+
);
|
|
12276
|
+
if (!Array.isArray(rows2) || rows2.length > 4096) throw new Error();
|
|
12277
|
+
const matching = rows2.map(object3).filter((row) => row.id === providerId || object3(row.source).localFolder === repoPath);
|
|
12278
|
+
if (matching.length > 1) throw new Error();
|
|
12279
|
+
const workspace = matching[0];
|
|
12280
|
+
if (workspace && (workspace.id !== providerId || object3(workspace.source).localFolder !== repoPath))
|
|
12281
|
+
throw new Error();
|
|
12282
|
+
const workspaceProvider = workspace ? object3(workspace.provider) : void 0;
|
|
12283
|
+
const state = object3(entry.state);
|
|
12284
|
+
const settings = object3(state.options ?? {});
|
|
12285
|
+
const stored = workspaceProvider ? object3(workspaceProvider.options ?? {}) : {};
|
|
12286
|
+
const option = (key, localOnly = false) => {
|
|
12287
|
+
const value = localOnly ? stored[key] : stored[key] ?? settings[key];
|
|
12288
|
+
if (value === void 0) return null;
|
|
12289
|
+
const text6 = object3(value).value;
|
|
12290
|
+
if (typeof text6 !== "string") throw new Error();
|
|
12291
|
+
return text6 || null;
|
|
12292
|
+
};
|
|
12293
|
+
if (workspaceProvider && workspaceProvider.name !== "docker") throw new Error();
|
|
12294
|
+
if (option("DOCKER_ELEVATION") && option("DOCKER_ELEVATION") !== "none") throw new Error();
|
|
12295
|
+
const endpoint = input2.endpoint ?? option("DOCKER_HOST");
|
|
12296
|
+
if (!endpoint || !input2.endpoint && (process.env.DOCKER_CONTEXT || option("DOCKER_CONTEXT") || (option("DOCKER_PATH") ?? "docker") !== "docker" || !workspace && entry.default !== true))
|
|
12297
|
+
throw new Error();
|
|
12298
|
+
return {
|
|
12299
|
+
provider,
|
|
12300
|
+
providerContext,
|
|
12301
|
+
providerId,
|
|
12302
|
+
endpoint,
|
|
12303
|
+
daemonId: inspectManagedStopDaemon(endpoint),
|
|
12304
|
+
versionQualified: true,
|
|
12305
|
+
definitionSha256,
|
|
12306
|
+
providerName: "docker",
|
|
12307
|
+
dockerPath: option("DOCKER_PATH") ?? "docker",
|
|
12308
|
+
persistedEndpoint: workspace ? option("DOCKER_HOST", true) : null,
|
|
12309
|
+
persistedContext: option("DOCKER_CONTEXT"),
|
|
12310
|
+
registration: workspace ? "owned" : "absent"
|
|
12311
|
+
};
|
|
12312
|
+
} catch {
|
|
12313
|
+
throw new Error(
|
|
12314
|
+
"Network provider destination could not be qualified; no allocation is permitted."
|
|
12315
|
+
);
|
|
12316
|
+
}
|
|
12317
|
+
}
|
|
12318
|
+
var import_node_child_process16, import_node_crypto16;
|
|
12319
|
+
var init_network_provider_inspect = __esm({
|
|
12320
|
+
"src/core/network-provider-inspect.ts"() {
|
|
12321
|
+
"use strict";
|
|
12322
|
+
import_node_child_process16 = require("child_process");
|
|
12323
|
+
import_node_crypto16 = require("crypto");
|
|
12324
|
+
init_devpod_environment();
|
|
12325
|
+
init_devsy_agent();
|
|
12326
|
+
}
|
|
12327
|
+
});
|
|
12328
|
+
|
|
11821
12329
|
// src/core/reliability-context.ts
|
|
11822
12330
|
function claimLifecycleEffect() {
|
|
11823
12331
|
claim?.();
|
|
@@ -11838,7 +12346,7 @@ function commandError(command, repoPath, stderr) {
|
|
|
11838
12346
|
);
|
|
11839
12347
|
}
|
|
11840
12348
|
function resolveGitCommonDir(repoPath) {
|
|
11841
|
-
const result = (0,
|
|
12349
|
+
const result = (0, import_node_child_process17.spawnSync)("git", ["-C", repoPath, "rev-parse", "--git-common-dir"], {
|
|
11842
12350
|
encoding: "utf-8",
|
|
11843
12351
|
env: READ_ONLY_GIT_ENV
|
|
11844
12352
|
});
|
|
@@ -11846,10 +12354,10 @@ function resolveGitCommonDir(repoPath) {
|
|
|
11846
12354
|
if (result.status !== 0 || !output2) {
|
|
11847
12355
|
throw commandError("Could not resolve the Git common directory", repoPath, result.stderr);
|
|
11848
12356
|
}
|
|
11849
|
-
return comparableWorkspacePath(
|
|
12357
|
+
return comparableWorkspacePath(import_node_path31.default.isAbsolute(output2) ? output2 : import_node_path31.default.resolve(repoPath, output2));
|
|
11850
12358
|
}
|
|
11851
12359
|
function resolveGitTopLevel(repoPath) {
|
|
11852
|
-
const result = (0,
|
|
12360
|
+
const result = (0, import_node_child_process17.spawnSync)("git", ["-C", repoPath, "rev-parse", "--show-toplevel"], {
|
|
11853
12361
|
encoding: "utf-8",
|
|
11854
12362
|
env: READ_ONLY_GIT_ENV
|
|
11855
12363
|
});
|
|
@@ -11860,7 +12368,7 @@ function resolveGitTopLevel(repoPath) {
|
|
|
11860
12368
|
return comparableWorkspacePath(output2);
|
|
11861
12369
|
}
|
|
11862
12370
|
function listGitWorktrees(repoPath) {
|
|
11863
|
-
const result = (0,
|
|
12371
|
+
const result = (0, import_node_child_process17.spawnSync)("git", ["-C", repoPath, "worktree", "list", "--porcelain"], {
|
|
11864
12372
|
encoding: "utf-8",
|
|
11865
12373
|
env: READ_ONLY_GIT_ENV
|
|
11866
12374
|
});
|
|
@@ -11897,7 +12405,7 @@ function listGitWorktrees(repoPath) {
|
|
|
11897
12405
|
return worktrees;
|
|
11898
12406
|
}
|
|
11899
12407
|
function ownershipDirectory(repoPath) {
|
|
11900
|
-
return
|
|
12408
|
+
return import_node_path31.default.join(resolveGitCommonDir(repoPath), OWNERSHIP_DIR);
|
|
11901
12409
|
}
|
|
11902
12410
|
function validateWorkspace(value, label2) {
|
|
11903
12411
|
if (typeof value !== "string" || wsFromBranch(value) !== value) {
|
|
@@ -11925,7 +12433,7 @@ function validateRecord(value, expectedWorkspace) {
|
|
|
11925
12433
|
`workspace ownership file '${expectedWorkspace}' contains identity '${workspace}'`
|
|
11926
12434
|
);
|
|
11927
12435
|
}
|
|
11928
|
-
if (typeof candidate.worktreePath !== "string" || !
|
|
12436
|
+
if (typeof candidate.worktreePath !== "string" || !import_node_path31.default.isAbsolute(candidate.worktreePath)) {
|
|
11929
12437
|
throw new Error("invalid workspace ownership worktreePath");
|
|
11930
12438
|
}
|
|
11931
12439
|
if (candidate.branch !== null && typeof candidate.branch !== "string") {
|
|
@@ -11943,7 +12451,7 @@ function validateRecord(value, expectedWorkspace) {
|
|
|
11943
12451
|
};
|
|
11944
12452
|
}
|
|
11945
12453
|
function recordPath(repoPath, workspace) {
|
|
11946
|
-
return
|
|
12454
|
+
return import_node_path31.default.join(
|
|
11947
12455
|
ownershipDirectory(repoPath),
|
|
11948
12456
|
`${validateWorkspace(workspace, "workspace")}.json`
|
|
11949
12457
|
);
|
|
@@ -11951,7 +12459,7 @@ function recordPath(repoPath, workspace) {
|
|
|
11951
12459
|
function readRecordFile(filePath, expectedWorkspace) {
|
|
11952
12460
|
let parsed;
|
|
11953
12461
|
try {
|
|
11954
|
-
parsed = JSON.parse(
|
|
12462
|
+
parsed = JSON.parse(import_node_fs24.default.readFileSync(filePath, "utf-8"));
|
|
11955
12463
|
} catch (error) {
|
|
11956
12464
|
if (error instanceof SyntaxError) {
|
|
11957
12465
|
throw new Error(`invalid workspace ownership JSON at '${filePath}'`);
|
|
@@ -11976,7 +12484,7 @@ function listWorkspaceOwnership(repoPath) {
|
|
|
11976
12484
|
function listWorkspaceOwnershipInDirectory(directory) {
|
|
11977
12485
|
let entries;
|
|
11978
12486
|
try {
|
|
11979
|
-
entries =
|
|
12487
|
+
entries = import_node_fs24.default.readdirSync(directory, { withFileTypes: true });
|
|
11980
12488
|
} catch (error) {
|
|
11981
12489
|
if (error.code === "ENOENT") return [];
|
|
11982
12490
|
throw error;
|
|
@@ -11984,14 +12492,14 @@ function listWorkspaceOwnershipInDirectory(directory) {
|
|
|
11984
12492
|
return entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).sort((left, right) => left.name.localeCompare(right.name)).map((entry) => {
|
|
11985
12493
|
const workspace = entry.name.slice(0, -".json".length);
|
|
11986
12494
|
validateWorkspace(workspace, "filename");
|
|
11987
|
-
return readRecordFile(
|
|
12495
|
+
return readRecordFile(import_node_path31.default.join(directory, entry.name), workspace);
|
|
11988
12496
|
});
|
|
11989
12497
|
}
|
|
11990
12498
|
function writeWorkspaceOwnershipInDirectory(directory, input2) {
|
|
11991
12499
|
const workspace = validateWorkspace(input2.workspace, "workspace");
|
|
11992
12500
|
const devpodId = validateWorkspace(input2.devpodId, "devpodId");
|
|
11993
12501
|
const worktreePath = comparableWorkspacePath(input2.worktreePath);
|
|
11994
|
-
const filePath =
|
|
12502
|
+
const filePath = import_node_path31.default.join(directory, `${workspace}.json`);
|
|
11995
12503
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
11996
12504
|
const records = listWorkspaceOwnershipInDirectory(directory);
|
|
11997
12505
|
const existing = records.find((record7) => record7.workspace === workspace);
|
|
@@ -12027,9 +12535,9 @@ function writeWorkspaceOwnershipInDirectory(directory, input2) {
|
|
|
12027
12535
|
return record6;
|
|
12028
12536
|
}
|
|
12029
12537
|
function removeWorkspaceOwnershipInDirectory(directory, workspace) {
|
|
12030
|
-
const filePath =
|
|
12538
|
+
const filePath = import_node_path31.default.join(directory, `${validateWorkspace(workspace, "workspace")}.json`);
|
|
12031
12539
|
try {
|
|
12032
|
-
|
|
12540
|
+
import_node_fs24.default.rmSync(filePath);
|
|
12033
12541
|
return true;
|
|
12034
12542
|
} catch (error) {
|
|
12035
12543
|
if (error.code === "ENOENT") return false;
|
|
@@ -12040,7 +12548,7 @@ function sameOwnershipRecord(left, right) {
|
|
|
12040
12548
|
return left.version === right.version && left.workspace === right.workspace && sameWorkspacePath(left.worktreePath, right.worktreePath) && left.branch === right.branch && left.devpodId === right.devpodId && left.createdAt === right.createdAt && left.updatedAt === right.updatedAt;
|
|
12041
12549
|
}
|
|
12042
12550
|
function removeWorkspaceOwnershipIfMatchesInDirectory(directory, expected) {
|
|
12043
|
-
const filePath =
|
|
12551
|
+
const filePath = import_node_path31.default.join(
|
|
12044
12552
|
directory,
|
|
12045
12553
|
`${validateWorkspace(expected.workspace, "workspace")}.json`
|
|
12046
12554
|
);
|
|
@@ -12052,14 +12560,14 @@ function removeWorkspaceOwnershipIfMatchesInDirectory(directory, expected) {
|
|
|
12052
12560
|
throw error;
|
|
12053
12561
|
}
|
|
12054
12562
|
if (!sameOwnershipRecord(current, expected)) return "changed";
|
|
12055
|
-
|
|
12563
|
+
import_node_fs24.default.rmSync(filePath);
|
|
12056
12564
|
return "removed";
|
|
12057
12565
|
}
|
|
12058
12566
|
function withWorkspaceOwnershipTransaction(repoPath, operation, options = {}) {
|
|
12059
12567
|
const directory = ownershipDirectory(repoPath);
|
|
12060
|
-
|
|
12568
|
+
import_node_fs24.default.mkdirSync(directory, { recursive: true });
|
|
12061
12569
|
return withFileLockSync(
|
|
12062
|
-
|
|
12570
|
+
import_node_path31.default.join(directory, ".lock"),
|
|
12063
12571
|
{
|
|
12064
12572
|
activity: "workspace ownership transaction",
|
|
12065
12573
|
target: `'${repoPath}'`,
|
|
@@ -12092,7 +12600,7 @@ function persistedWorkspaceOwners(repoPath, worktreePath) {
|
|
|
12092
12600
|
try {
|
|
12093
12601
|
workspace = readPersistedWorkspace(worktree.path);
|
|
12094
12602
|
} catch (error) {
|
|
12095
|
-
if (!
|
|
12603
|
+
if (!import_node_fs24.default.existsSync(worktree.path)) continue;
|
|
12096
12604
|
throw error;
|
|
12097
12605
|
}
|
|
12098
12606
|
if (!workspace) continue;
|
|
@@ -12255,7 +12763,7 @@ function inspectWorkspaceOwnership(record6, worktrees, devpods) {
|
|
|
12255
12763
|
if (worktree?.locked) {
|
|
12256
12764
|
return { ownerStatus: "locked", devpodStatus, worktree };
|
|
12257
12765
|
}
|
|
12258
|
-
if ((!worktree || worktree.prunable) &&
|
|
12766
|
+
if ((!worktree || worktree.prunable) && import_node_fs24.default.existsSync(record6.worktreePath)) {
|
|
12259
12767
|
return { ownerStatus: "conflict", devpodStatus, worktree };
|
|
12260
12768
|
}
|
|
12261
12769
|
if (!worktree || worktree.prunable) {
|
|
@@ -12279,20 +12787,20 @@ function listMissingWorkspaceOwnership(repoPath) {
|
|
|
12279
12787
|
(record6) => inspectWorkspaceOwnership(record6, worktrees, void 0).ownerStatus === "missing"
|
|
12280
12788
|
);
|
|
12281
12789
|
}
|
|
12282
|
-
var
|
|
12790
|
+
var import_node_child_process17, import_node_fs24, import_node_path31, READ_ONLY_GIT_ENV, OWNERSHIP_VERSION, OWNERSHIP_DIR;
|
|
12283
12791
|
var init_workspace_ownership = __esm({
|
|
12284
12792
|
"src/core/workspace-ownership.ts"() {
|
|
12285
12793
|
"use strict";
|
|
12286
|
-
|
|
12287
|
-
|
|
12288
|
-
|
|
12794
|
+
import_node_child_process17 = require("child_process");
|
|
12795
|
+
import_node_fs24 = __toESM(require("fs"));
|
|
12796
|
+
import_node_path31 = __toESM(require("path"));
|
|
12289
12797
|
init_atomic_file();
|
|
12290
12798
|
init_devpod_workspaces();
|
|
12291
12799
|
init_file_lock();
|
|
12292
12800
|
init_workspace();
|
|
12293
12801
|
READ_ONLY_GIT_ENV = { ...process.env, GIT_OPTIONAL_LOCKS: "0" };
|
|
12294
12802
|
OWNERSHIP_VERSION = 1;
|
|
12295
|
-
OWNERSHIP_DIR =
|
|
12803
|
+
OWNERSHIP_DIR = import_node_path31.default.join("devrouter", "workspaces");
|
|
12296
12804
|
}
|
|
12297
12805
|
});
|
|
12298
12806
|
|
|
@@ -12395,6 +12903,148 @@ function proveRetainedManagedStop(state) {
|
|
|
12395
12903
|
}
|
|
12396
12904
|
return result;
|
|
12397
12905
|
}
|
|
12906
|
+
function replacementSourceDigest(state, plan) {
|
|
12907
|
+
const git2 = (args) => {
|
|
12908
|
+
const result = (0, import_node_child_process18.spawnSync)("git", ["-C", state.repoPath, ...args], {
|
|
12909
|
+
encoding: "utf8",
|
|
12910
|
+
timeout: 5e3,
|
|
12911
|
+
maxBuffer: 1024 * 1024
|
|
12912
|
+
});
|
|
12913
|
+
if (result.status !== 0 || result.error)
|
|
12914
|
+
throw new Error("Replacement cannot freeze the source checkout.");
|
|
12915
|
+
return result.stdout;
|
|
12916
|
+
};
|
|
12917
|
+
if (git2(["status", "--porcelain", "--untracked-files=no"]).trim() || git2([
|
|
12918
|
+
"ls-files",
|
|
12919
|
+
"--others",
|
|
12920
|
+
"--exclude-standard",
|
|
12921
|
+
"--",
|
|
12922
|
+
".devcontainer",
|
|
12923
|
+
".devrouter.yml"
|
|
12924
|
+
]).trim())
|
|
12925
|
+
throw new Error("Replacement requires committed, unchanged managed source and hooks.");
|
|
12926
|
+
const adapter = resolveManagedPostStartPlan(state.repoPath);
|
|
12927
|
+
if (adapter.kind !== "runtime")
|
|
12928
|
+
throw new Error("Replacement requires a preserving managed adapter.");
|
|
12929
|
+
const files = [
|
|
12930
|
+
import_node_path32.default.join(state.repoPath, ".devrouter.yml"),
|
|
12931
|
+
plan.sourcePath,
|
|
12932
|
+
...plan.composeFiles
|
|
12933
|
+
];
|
|
12934
|
+
return (0, import_node_crypto17.createHash)("sha256").update(
|
|
12935
|
+
JSON.stringify([
|
|
12936
|
+
git2(["rev-parse", "HEAD"]).trim(),
|
|
12937
|
+
adapter.adapterSha256,
|
|
12938
|
+
...files.map((file) => [
|
|
12939
|
+
file,
|
|
12940
|
+
(0, import_node_crypto17.createHash)("sha256").update(import_node_fs25.default.readFileSync(file)).digest("hex")
|
|
12941
|
+
])
|
|
12942
|
+
])
|
|
12943
|
+
).digest("hex");
|
|
12944
|
+
}
|
|
12945
|
+
function captureManagedAppReplacementProof(state) {
|
|
12946
|
+
if (state.status !== "ready" || requireReadyDevsyAgent().version !== "1.24.0")
|
|
12947
|
+
throw new Error("App replacement requires a successful retained generation and Devsy 1.24.0.");
|
|
12948
|
+
const baseline = validateManagedStopBaseline(state.stopBaseline, state);
|
|
12949
|
+
if (baseline.sourceContainer)
|
|
12950
|
+
throw new Error("Replacement refuses a container-sourced provider.");
|
|
12951
|
+
const runtime = loadRuntimeConfig(state.repoPath, state.workspace ?? "", state.profile);
|
|
12952
|
+
if (!runtime.config.managedRuntime || runtime.config.managedRuntime.network)
|
|
12953
|
+
throw new Error("Replacement requires manual managed Compose without network allocation.");
|
|
12954
|
+
const plan = inspectManagedDevcontainerConfig({
|
|
12955
|
+
repoPath: state.repoPath,
|
|
12956
|
+
config: runtime.config,
|
|
12957
|
+
profile: runtime.resolvedProfile,
|
|
12958
|
+
linked: isLinkedWorktree(state.repoPath)
|
|
12959
|
+
});
|
|
12960
|
+
if (state.sourceConfigSha256 !== plan.sourceConfigSha256 || state.effectiveConfigSha256 !== plan.effectiveConfigSha256 || inspectManagedDevcontainerGeneratedConfig(plan).status !== "valid")
|
|
12961
|
+
throw new Error("Replacement refuses changed or unavailable managed configuration.");
|
|
12962
|
+
const containers2 = proveRetainedManagedStop(state);
|
|
12963
|
+
if (!baseline.containers.some((c) => c.service !== baseline.primaryService))
|
|
12964
|
+
throw new Error(
|
|
12965
|
+
"App replacement requires a retained dependency to preserve released-client recovery proof."
|
|
12966
|
+
);
|
|
12967
|
+
if (containers2.some((c) => c.state.Running || !["created", "exited"].includes(c.state.Status)))
|
|
12968
|
+
throw new Error("App replacement requires every retained container stopped.");
|
|
12969
|
+
const workspace = state.workspace ? { token: state.workspace, gitCommonDir: resolveGitCommonDir(state.repoPath) } : void 0;
|
|
12970
|
+
assertManagedContainerConfigUnchanged({ plan, containers: containers2, workspace });
|
|
12971
|
+
const source = replacementSourceDigest(state, plan);
|
|
12972
|
+
const evidence = inspectNetworkProviderBinding({
|
|
12973
|
+
provider: "devsy",
|
|
12974
|
+
providerId: state.devpodId,
|
|
12975
|
+
repoPath: state.repoPath,
|
|
12976
|
+
endpoint: baseline.endpoint,
|
|
12977
|
+
providerContext: baseline.context
|
|
12978
|
+
});
|
|
12979
|
+
if (!evidence.versionQualified || evidence.registration !== "owned" || evidence.providerName !== "docker" || evidence.dockerPath !== "docker" || evidence.persistedContext !== null || evidence.persistedEndpoint !== null && evidence.persistedEndpoint !== baseline.endpoint || evidence.daemonId !== baseline.daemonId)
|
|
12980
|
+
throw new Error("Replacement provider destination is unqualified or changed.");
|
|
12981
|
+
const inventory = inspectAppReplacementInventory(baseline.endpoint);
|
|
12982
|
+
const primaryId = baseline.containers.find((c) => c.service === baseline.primaryService)?.id;
|
|
12983
|
+
if (!primaryId) throw new Error("Replacement has no exact retained primary.");
|
|
12984
|
+
assertNoAppNamespaceConsumers(inventory, primaryId);
|
|
12985
|
+
const primary = inventory.find((c) => c.id === primaryId);
|
|
12986
|
+
const env = managedComposeEnvironment(workspace);
|
|
12987
|
+
delete env.DOCKER_CONTEXT;
|
|
12988
|
+
delete env.DOCKER_HOST;
|
|
12989
|
+
const result = (0, import_node_child_process18.spawnSync)(
|
|
12990
|
+
"docker",
|
|
12991
|
+
[
|
|
12992
|
+
"--host",
|
|
12993
|
+
baseline.endpoint,
|
|
12994
|
+
"compose",
|
|
12995
|
+
"--project-name",
|
|
12996
|
+
baseline.project,
|
|
12997
|
+
"--project-directory",
|
|
12998
|
+
plan.composeDirectory,
|
|
12999
|
+
...baseline.composeFiles.flatMap((f) => ["-f", f]),
|
|
13000
|
+
"config",
|
|
13001
|
+
"--format",
|
|
13002
|
+
"json",
|
|
13003
|
+
"--no-env-resolution"
|
|
13004
|
+
],
|
|
13005
|
+
{
|
|
13006
|
+
cwd: plan.composeDirectory,
|
|
13007
|
+
env,
|
|
13008
|
+
encoding: "utf8",
|
|
13009
|
+
timeout: 15e3,
|
|
13010
|
+
maxBuffer: 4 * 1024 * 1024
|
|
13011
|
+
}
|
|
13012
|
+
);
|
|
13013
|
+
if (result.status !== 0 || result.error)
|
|
13014
|
+
throw new Error("Replacement Compose evidence is unavailable.");
|
|
13015
|
+
const model = JSON.parse(result.stdout);
|
|
13016
|
+
const service = model?.services?.[plan.primaryService];
|
|
13017
|
+
if (!service || !Array.isArray(service.volumes))
|
|
13018
|
+
throw new Error("Replacement requires declared persistent mounts.");
|
|
13019
|
+
for (const mount of primary.mounts) {
|
|
13020
|
+
if (!["bind", "volume"].includes(mount.Type))
|
|
13021
|
+
throw new Error("Replacement refuses unattributed primary mounts.");
|
|
13022
|
+
if (mount.Type === "volume" && !service.volumes.some(
|
|
13023
|
+
(v) => v.type === "volume" && v.source && v.target === mount.Destination && model.volumes?.[v.source]?.name === mount.Name
|
|
13024
|
+
))
|
|
13025
|
+
throw new Error("Replacement refuses anonymous or undeclared primary volumes.");
|
|
13026
|
+
}
|
|
13027
|
+
const binding = {
|
|
13028
|
+
provider: "devsy",
|
|
13029
|
+
providerId: state.devpodId,
|
|
13030
|
+
endpoint: baseline.endpoint,
|
|
13031
|
+
daemonId: baseline.daemonId,
|
|
13032
|
+
definitionSha256: evidence.definitionSha256,
|
|
13033
|
+
providerContext: baseline.context
|
|
13034
|
+
};
|
|
13035
|
+
const digest5 = (0, import_node_crypto17.createHash)("sha256").update(
|
|
13036
|
+
JSON.stringify({
|
|
13037
|
+
state,
|
|
13038
|
+
plan,
|
|
13039
|
+
source,
|
|
13040
|
+
binding,
|
|
13041
|
+
primary,
|
|
13042
|
+
population: containers2,
|
|
13043
|
+
modelSha256: (0, import_node_crypto17.createHash)("sha256").update(result.stdout).digest("hex")
|
|
13044
|
+
})
|
|
13045
|
+
).digest("hex");
|
|
13046
|
+
return { state, plan, primary, binding, sourceSha256: source, digest: digest5 };
|
|
13047
|
+
}
|
|
12398
13048
|
function absentRegistrationIdentity(state) {
|
|
12399
13049
|
resetWorkspaceRuntimeCaches();
|
|
12400
13050
|
if (resolveWorkspaceRuntimeOrDefault(state.repoPath) !== "devsy")
|
|
@@ -12592,22 +13242,29 @@ function managedStopRouteReferences(state) {
|
|
|
12592
13242
|
(name) => ["http", "tcp"].map((protocol) => ({ repoPath: state.repoPath, name, protocol }))
|
|
12593
13243
|
);
|
|
12594
13244
|
}
|
|
12595
|
-
var import_node_os4,
|
|
13245
|
+
var import_node_child_process18, import_node_crypto17, import_node_fs25, import_node_os4, import_node_path32, import_node_util9;
|
|
12596
13246
|
var init_managed_stop_recovery = __esm({
|
|
12597
13247
|
"src/core/managed-stop-recovery.ts"() {
|
|
12598
13248
|
"use strict";
|
|
13249
|
+
import_node_child_process18 = require("child_process");
|
|
13250
|
+
import_node_crypto17 = require("crypto");
|
|
13251
|
+
import_node_fs25 = __toESM(require("fs"));
|
|
12599
13252
|
import_node_os4 = __toESM(require("os"));
|
|
12600
|
-
|
|
13253
|
+
import_node_path32 = __toESM(require("path"));
|
|
12601
13254
|
import_node_util9 = require("util");
|
|
12602
13255
|
init_devcontainer_profile();
|
|
12603
13256
|
init_devpod_environment();
|
|
12604
13257
|
init_devpod_registry();
|
|
13258
|
+
init_devsy_agent();
|
|
12605
13259
|
init_devsy_exec_proof();
|
|
12606
13260
|
init_devsy_workspaces();
|
|
12607
13261
|
init_managed_compose_population();
|
|
13262
|
+
init_managed_post_start();
|
|
12608
13263
|
init_managed_runtime_state();
|
|
12609
13264
|
init_managed_stop_baseline();
|
|
13265
|
+
init_network_provider_inspect();
|
|
12610
13266
|
init_reliability_context();
|
|
13267
|
+
init_repo_config();
|
|
12611
13268
|
init_workspace();
|
|
12612
13269
|
init_workspace_ownership();
|
|
12613
13270
|
init_workspace_runtime();
|
|
@@ -12625,7 +13282,7 @@ async function getDockerodeConstructor() {
|
|
|
12625
13282
|
return dockerodeConstructorPromise;
|
|
12626
13283
|
}
|
|
12627
13284
|
function runDockerContextCommand(args) {
|
|
12628
|
-
const result = (0,
|
|
13285
|
+
const result = (0, import_node_child_process19.spawnSync)("docker", ["context", ...args], {
|
|
12629
13286
|
encoding: "utf-8"
|
|
12630
13287
|
});
|
|
12631
13288
|
if (result.status !== 0) {
|
|
@@ -12638,7 +13295,7 @@ function getCurrentDockerContext() {
|
|
|
12638
13295
|
return runDockerContextCommand(["show"]);
|
|
12639
13296
|
}
|
|
12640
13297
|
function getDockerHostFromContext(context) {
|
|
12641
|
-
const result = (0,
|
|
13298
|
+
const result = (0, import_node_child_process19.spawnSync)(
|
|
12642
13299
|
"docker",
|
|
12643
13300
|
["context", "inspect", context, "--format", "{{ .Endpoints.docker.Host }}"],
|
|
12644
13301
|
{ encoding: "utf-8" }
|
|
@@ -12705,11 +13362,11 @@ async function networkExists(name) {
|
|
|
12705
13362
|
return false;
|
|
12706
13363
|
}
|
|
12707
13364
|
}
|
|
12708
|
-
var
|
|
13365
|
+
var import_node_child_process19, dockerodeConstructorPromise;
|
|
12709
13366
|
var init_docker = __esm({
|
|
12710
13367
|
"src/core/docker.ts"() {
|
|
12711
13368
|
"use strict";
|
|
12712
|
-
|
|
13369
|
+
import_node_child_process19 = require("child_process");
|
|
12713
13370
|
init_network_effect_scope();
|
|
12714
13371
|
dockerodeConstructorPromise = null;
|
|
12715
13372
|
}
|
|
@@ -12717,7 +13374,7 @@ var init_docker = __esm({
|
|
|
12717
13374
|
|
|
12718
13375
|
// src/core/tls.ts
|
|
12719
13376
|
function runOrThrow(command, args) {
|
|
12720
|
-
const result = (0,
|
|
13377
|
+
const result = (0, import_node_child_process20.spawnSync)(command, args, {
|
|
12721
13378
|
encoding: "utf-8"
|
|
12722
13379
|
});
|
|
12723
13380
|
if (result.status !== 0) {
|
|
@@ -12727,7 +13384,7 @@ function runOrThrow(command, args) {
|
|
|
12727
13384
|
return result.stdout.trim();
|
|
12728
13385
|
}
|
|
12729
13386
|
function commandExists(command) {
|
|
12730
|
-
const result = (0,
|
|
13387
|
+
const result = (0, import_node_child_process20.spawnSync)("sh", ["-c", `command -v ${command}`], { encoding: "utf-8" });
|
|
12731
13388
|
return result.status === 0;
|
|
12732
13389
|
}
|
|
12733
13390
|
function ensureMkcert() {
|
|
@@ -12745,8 +13402,8 @@ function tlsSetupCommand(repoPath) {
|
|
|
12745
13402
|
}
|
|
12746
13403
|
function getMkcertRootCAPath(options = {}) {
|
|
12747
13404
|
ensureMkcert();
|
|
12748
|
-
const rootCAPath =
|
|
12749
|
-
if (!
|
|
13405
|
+
const rootCAPath = import_node_path33.default.join(runOrThrow("mkcert", ["-CAROOT"]), "rootCA.pem");
|
|
13406
|
+
if (!import_node_fs26.default.existsSync(rootCAPath)) {
|
|
12750
13407
|
throw new Error(
|
|
12751
13408
|
`mkcert root CA was not found at '${rootCAPath}'. Run: ${tlsSetupCommand(options.repoPath)}`
|
|
12752
13409
|
);
|
|
@@ -12779,7 +13436,7 @@ function parseDnsHostsFromSubjectAltName(subjectAltName) {
|
|
|
12779
13436
|
return normalizeUniqueHosts(names);
|
|
12780
13437
|
}
|
|
12781
13438
|
function parseCertificateDnsHosts(pem) {
|
|
12782
|
-
const certificate = new
|
|
13439
|
+
const certificate = new import_node_crypto18.X509Certificate(pem);
|
|
12783
13440
|
const subjectAltName = certificate.subjectAltName ?? "";
|
|
12784
13441
|
if (subjectAltName.length === 0) {
|
|
12785
13442
|
return [];
|
|
@@ -12847,11 +13504,11 @@ function compactTLSCertificateHosts(hosts) {
|
|
|
12847
13504
|
);
|
|
12848
13505
|
}
|
|
12849
13506
|
function readCurrentCertificateHosts(options = {}) {
|
|
12850
|
-
if (!
|
|
13507
|
+
if (!import_node_fs26.default.existsSync(CERT_FILE)) {
|
|
12851
13508
|
return [];
|
|
12852
13509
|
}
|
|
12853
13510
|
try {
|
|
12854
|
-
const pem =
|
|
13511
|
+
const pem = import_node_fs26.default.readFileSync(CERT_FILE, "utf-8");
|
|
12855
13512
|
return parseCertificateDnsHosts(pem);
|
|
12856
13513
|
} catch (error) {
|
|
12857
13514
|
if (options.replaceMalformed) {
|
|
@@ -12979,20 +13636,20 @@ Run: ${tlsSetupCommand(options.repoPath)}`
|
|
|
12979
13636
|
);
|
|
12980
13637
|
}
|
|
12981
13638
|
}
|
|
12982
|
-
var
|
|
13639
|
+
var import_node_child_process20, import_node_crypto18, import_node_fs26, import_node_path33, DEFAULT_TLS_CERT_HOSTS, TLS_CERTIFICATE_LOCK_FILE, TLS_CERTIFICATE_LOCK_WAIT_MS, TLS_CERTIFICATE_WRITE_ATTEMPTS;
|
|
12983
13640
|
var init_tls = __esm({
|
|
12984
13641
|
"src/core/tls.ts"() {
|
|
12985
13642
|
"use strict";
|
|
12986
|
-
|
|
12987
|
-
|
|
12988
|
-
|
|
12989
|
-
|
|
13643
|
+
import_node_child_process20 = require("child_process");
|
|
13644
|
+
import_node_crypto18 = require("crypto");
|
|
13645
|
+
import_node_fs26 = __toESM(require("fs"));
|
|
13646
|
+
import_node_path33 = __toESM(require("path"));
|
|
12990
13647
|
init_docker();
|
|
12991
13648
|
init_file_lock();
|
|
12992
13649
|
init_host_routes();
|
|
12993
13650
|
init_router();
|
|
12994
13651
|
DEFAULT_TLS_CERT_HOSTS = ["localhost", "*.localhost"];
|
|
12995
|
-
TLS_CERTIFICATE_LOCK_FILE =
|
|
13652
|
+
TLS_CERTIFICATE_LOCK_FILE = import_node_path33.default.join(DEVROUTER_HOME, "tls-certificate.lock");
|
|
12996
13653
|
TLS_CERTIFICATE_LOCK_WAIT_MS = 6e4;
|
|
12997
13654
|
TLS_CERTIFICATE_WRITE_ATTEMPTS = 2;
|
|
12998
13655
|
}
|
|
@@ -13078,7 +13735,7 @@ function sleep(ms) {
|
|
|
13078
13735
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
13079
13736
|
}
|
|
13080
13737
|
function inspectRouterApi(protocol) {
|
|
13081
|
-
const result = (0,
|
|
13738
|
+
const result = (0, import_node_child_process21.spawnSync)(
|
|
13082
13739
|
"curl",
|
|
13083
13740
|
[
|
|
13084
13741
|
"--silent",
|
|
@@ -13185,7 +13842,7 @@ async function ensureTraefikRouteExpectation(routes, expectation, options) {
|
|
|
13185
13842
|
throw new Error(
|
|
13186
13843
|
"Traefik routes did not reload; shared router restart is disabled for this operation."
|
|
13187
13844
|
);
|
|
13188
|
-
|
|
13845
|
+
import_node_fs27.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
13189
13846
|
return withFileLock(
|
|
13190
13847
|
ROUTER_RELOAD_LOCK_FILE,
|
|
13191
13848
|
{
|
|
@@ -13220,19 +13877,19 @@ function assertTraefikRoutesRemoved(routes) {
|
|
|
13220
13877
|
const result = inspectExpectedRoutes(routes, "removed");
|
|
13221
13878
|
if (!result.ok) throw new Error(`Workspace route cessation is not proven: ${result.details}`);
|
|
13222
13879
|
}
|
|
13223
|
-
var
|
|
13880
|
+
var import_node_child_process21, import_node_fs27, import_node_path34, 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;
|
|
13224
13881
|
var init_traefik_route_health = __esm({
|
|
13225
13882
|
"src/core/traefik-route-health.ts"() {
|
|
13226
13883
|
"use strict";
|
|
13227
|
-
|
|
13228
|
-
|
|
13229
|
-
|
|
13884
|
+
import_node_child_process21 = require("child_process");
|
|
13885
|
+
import_node_fs27 = __toESM(require("fs"));
|
|
13886
|
+
import_node_path34 = __toESM(require("path"));
|
|
13230
13887
|
init_file_lock();
|
|
13231
13888
|
init_host_routes();
|
|
13232
13889
|
init_reliability_context();
|
|
13233
13890
|
init_router();
|
|
13234
13891
|
ROUTER_API_BASE = "http://127.0.0.1:8080/api";
|
|
13235
|
-
ROUTER_RELOAD_LOCK_FILE =
|
|
13892
|
+
ROUTER_RELOAD_LOCK_FILE = import_node_path34.default.join(DEVROUTER_HOME, "router-reload.lock");
|
|
13236
13893
|
ROUTER_API_REQUEST_TIMEOUT_SECONDS = "2";
|
|
13237
13894
|
DEFAULT_INITIAL_TIMEOUT_MS = 3e3;
|
|
13238
13895
|
DEFAULT_RECOVERY_TIMEOUT_MS = 1e4;
|
|
@@ -13257,7 +13914,7 @@ function proveInitialManagedDevsyAbsence(repoPath, expectedId) {
|
|
|
13257
13914
|
if (!isLinkedWorktree(repoPath)) return void 0;
|
|
13258
13915
|
const workspace = resolveWorktreeWorkspace(repoPath);
|
|
13259
13916
|
if (!workspace || readManagedRuntimeState(repoPath, workspace)) return void 0;
|
|
13260
|
-
if (!
|
|
13917
|
+
if (!import_node_fs28.default.existsSync(import_node_path35.default.join(repoPath, ".devrouter.yml"))) return void 0;
|
|
13261
13918
|
const runtime = loadRuntimeConfig(repoPath, workspace);
|
|
13262
13919
|
if (!runtime.config.managedRuntime) return void 0;
|
|
13263
13920
|
const routes = proxyAppsFromConfig(runtime.config).flatMap(
|
|
@@ -13317,7 +13974,7 @@ function proveInitialManagedDevsyAbsence(repoPath, expectedId) {
|
|
|
13317
13974
|
};
|
|
13318
13975
|
}
|
|
13319
13976
|
function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
13320
|
-
if (!
|
|
13977
|
+
if (!import_node_fs28.default.existsSync(import_node_path35.default.join(repoPath, ".devrouter.yml"))) return false;
|
|
13321
13978
|
if (!loadRepoConfig(repoPath).managedRuntime) return false;
|
|
13322
13979
|
const linked = isLinkedWorktree(repoPath);
|
|
13323
13980
|
const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
|
|
@@ -13374,8 +14031,8 @@ function stopInitialManagedDevsyWorkspace(repoPath, devsyId) {
|
|
|
13374
14031
|
profile: runtime.resolvedProfile,
|
|
13375
14032
|
linked
|
|
13376
14033
|
});
|
|
13377
|
-
const providerRoot =
|
|
13378
|
-
const featureDirectory =
|
|
14034
|
+
const providerRoot = import_node_path35.default.resolve(process.env.DEVSY_HOME || import_node_path35.default.join(import_node_os5.default.homedir(), ".devsy"));
|
|
14035
|
+
const featureDirectory = import_node_path35.default.join(
|
|
13379
14036
|
providerRoot,
|
|
13380
14037
|
"contexts",
|
|
13381
14038
|
owner.context,
|
|
@@ -13497,7 +14154,7 @@ function restoreRecordedManagedDevcontainerConfig(repoPath) {
|
|
|
13497
14154
|
}
|
|
13498
14155
|
function recordedManagedDevcontainerRestorePlan(repoPath) {
|
|
13499
14156
|
try {
|
|
13500
|
-
if (!
|
|
14157
|
+
if (!import_node_fs28.default.existsSync(import_node_path35.default.join(repoPath, ".devrouter.yml"))) return void 0;
|
|
13501
14158
|
const linked = isLinkedWorktree(repoPath);
|
|
13502
14159
|
const workspace = linked ? resolveWorktreeWorkspace(repoPath) : void 0;
|
|
13503
14160
|
const state = readManagedRuntimeState(repoPath, workspace);
|
|
@@ -13588,7 +14245,7 @@ function stopRetainedManagedDevsyWorkspace(options) {
|
|
|
13588
14245
|
const owned = inspectWorkspaceContainers().filter(
|
|
13589
14246
|
(container) => sameWorkspacePath(
|
|
13590
14247
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
13591
|
-
|
|
14248
|
+
import_node_path35.default.join(repoPath, ".devcontainer")
|
|
13592
14249
|
)
|
|
13593
14250
|
);
|
|
13594
14251
|
if (owned.length !== 0) {
|
|
@@ -13617,8 +14274,8 @@ function stopRetainedManagedDevsyWorkspace(options) {
|
|
|
13617
14274
|
if (!context || !/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(context) || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/.test(devsyId)) {
|
|
13618
14275
|
throw new Error("Managed stop requires a valid exact Devsy context and workspace ID.");
|
|
13619
14276
|
}
|
|
13620
|
-
const devsyRoot =
|
|
13621
|
-
const featureDirectory =
|
|
14277
|
+
const devsyRoot = import_node_path35.default.resolve(process.env.DEVSY_HOME || import_node_path35.default.join(import_node_os5.default.homedir(), ".devsy"));
|
|
14278
|
+
const featureDirectory = import_node_path35.default.join(
|
|
13622
14279
|
devsyRoot,
|
|
13623
14280
|
"contexts",
|
|
13624
14281
|
context,
|
|
@@ -13722,13 +14379,13 @@ function stopRetainedManagedDevsyWorkspace(options) {
|
|
|
13722
14379
|
if (providerFailed) throw providerError;
|
|
13723
14380
|
return true;
|
|
13724
14381
|
}
|
|
13725
|
-
var
|
|
14382
|
+
var import_node_fs28, import_node_os5, import_node_path35, import_node_util10;
|
|
13726
14383
|
var init_managed_devsy_stop = __esm({
|
|
13727
14384
|
"src/core/managed-devsy-stop.ts"() {
|
|
13728
14385
|
"use strict";
|
|
13729
|
-
|
|
14386
|
+
import_node_fs28 = __toESM(require("fs"));
|
|
13730
14387
|
import_node_os5 = __toESM(require("os"));
|
|
13731
|
-
|
|
14388
|
+
import_node_path35 = __toESM(require("path"));
|
|
13732
14389
|
import_node_util10 = require("util");
|
|
13733
14390
|
init_devcontainer_profile();
|
|
13734
14391
|
init_devpod_environment();
|
|
@@ -14290,7 +14947,7 @@ function hasControlCharacter2(value) {
|
|
|
14290
14947
|
function readPolicyFile(filePath) {
|
|
14291
14948
|
let initialStats;
|
|
14292
14949
|
try {
|
|
14293
|
-
initialStats =
|
|
14950
|
+
initialStats = import_node_fs29.default.lstatSync(filePath);
|
|
14294
14951
|
} catch (error) {
|
|
14295
14952
|
if (isErrno(error, "ENOENT")) return { status: "absent" };
|
|
14296
14953
|
return { status: "invalid", error: "network policy could not be read" };
|
|
@@ -14303,16 +14960,16 @@ function readPolicyFile(filePath) {
|
|
|
14303
14960
|
}
|
|
14304
14961
|
let fileDescriptor;
|
|
14305
14962
|
try {
|
|
14306
|
-
fileDescriptor =
|
|
14963
|
+
fileDescriptor = import_node_fs29.default.openSync(
|
|
14307
14964
|
filePath,
|
|
14308
|
-
|
|
14965
|
+
import_node_fs29.default.constants.O_RDONLY | import_node_fs29.default.constants.O_NONBLOCK | (import_node_fs29.default.constants.O_NOFOLLOW ?? 0)
|
|
14309
14966
|
);
|
|
14310
14967
|
} catch (error) {
|
|
14311
14968
|
if (isErrno(error, "ENOENT")) return { status: "absent" };
|
|
14312
14969
|
return { status: "invalid", error: "network policy could not be read" };
|
|
14313
14970
|
}
|
|
14314
14971
|
try {
|
|
14315
|
-
const openedStats =
|
|
14972
|
+
const openedStats = import_node_fs29.default.fstatSync(fileDescriptor);
|
|
14316
14973
|
if (!openedStats.isFile()) {
|
|
14317
14974
|
return { status: "invalid", error: "network policy must be a regular file" };
|
|
14318
14975
|
}
|
|
@@ -14325,12 +14982,12 @@ function readPolicyFile(filePath) {
|
|
|
14325
14982
|
const buffer = Buffer.alloc(openedStats.size);
|
|
14326
14983
|
let offset = 0;
|
|
14327
14984
|
while (offset < buffer.length) {
|
|
14328
|
-
const bytesRead =
|
|
14985
|
+
const bytesRead = import_node_fs29.default.readSync(fileDescriptor, buffer, offset, buffer.length - offset, null);
|
|
14329
14986
|
if (bytesRead === 0)
|
|
14330
14987
|
return { status: "invalid", error: "network policy changed during read" };
|
|
14331
14988
|
offset += bytesRead;
|
|
14332
14989
|
}
|
|
14333
|
-
const finalStats =
|
|
14990
|
+
const finalStats = import_node_fs29.default.fstatSync(fileDescriptor);
|
|
14334
14991
|
if (!finalStats.isFile() || finalStats.size !== openedStats.size) {
|
|
14335
14992
|
return { status: "invalid", error: "network policy changed during read" };
|
|
14336
14993
|
}
|
|
@@ -14339,7 +14996,7 @@ function readPolicyFile(filePath) {
|
|
|
14339
14996
|
return { status: "invalid", error: "network policy could not be read" };
|
|
14340
14997
|
} finally {
|
|
14341
14998
|
try {
|
|
14342
|
-
|
|
14999
|
+
import_node_fs29.default.closeSync(fileDescriptor);
|
|
14343
15000
|
} catch {
|
|
14344
15001
|
}
|
|
14345
15002
|
}
|
|
@@ -14356,16 +15013,16 @@ function assertDisjoint(cidrs, message) {
|
|
|
14356
15013
|
function isErrno(error, code) {
|
|
14357
15014
|
return typeof error === "object" && error !== null && "code" in error && error.code === code;
|
|
14358
15015
|
}
|
|
14359
|
-
var
|
|
15016
|
+
var import_node_fs29, import_node_path36, NETWORK_POLICY_VERSION, NETWORK_POLICY_FILE, DEFAULT_NETWORK_POLICY_ENDPOINT_RESERVE, NETWORK_POLICY_PREFIX_LENGTHS, MAX_NETWORK_POLICY_FILE_BYTES, MAX_NETWORK_POLICY_ARRAY_ENTRIES, MAX_NETWORK_POLICY_DAEMON_ID_LENGTH, NetworkPolicyValidationError, NETWORK_POLICY_KEYS, PRIVATE_IPV4_RANGES;
|
|
14360
15017
|
var init_network_policy = __esm({
|
|
14361
15018
|
"src/core/network-policy.ts"() {
|
|
14362
15019
|
"use strict";
|
|
14363
|
-
|
|
14364
|
-
|
|
15020
|
+
import_node_fs29 = __toESM(require("fs"));
|
|
15021
|
+
import_node_path36 = __toESM(require("path"));
|
|
14365
15022
|
init_network_capacity();
|
|
14366
15023
|
init_router();
|
|
14367
15024
|
NETWORK_POLICY_VERSION = 1;
|
|
14368
|
-
NETWORK_POLICY_FILE =
|
|
15025
|
+
NETWORK_POLICY_FILE = import_node_path36.default.join(DEVROUTER_HOME, "network-policy.json");
|
|
14369
15026
|
DEFAULT_NETWORK_POLICY_ENDPOINT_RESERVE = 8;
|
|
14370
15027
|
NETWORK_POLICY_PREFIX_LENGTHS = [24, 25, 26];
|
|
14371
15028
|
MAX_NETWORK_POLICY_FILE_BYTES = 64 * 1024;
|
|
@@ -14466,27 +15123,27 @@ function assertExactKeys(value, keys2) {
|
|
|
14466
15123
|
function readDocument(store) {
|
|
14467
15124
|
let descriptor;
|
|
14468
15125
|
try {
|
|
14469
|
-
descriptor =
|
|
15126
|
+
descriptor = import_node_fs30.default.openSync(
|
|
14470
15127
|
store.filePath,
|
|
14471
|
-
|
|
15128
|
+
import_node_fs30.default.constants.O_RDONLY | import_node_fs30.default.constants.O_NONBLOCK | (import_node_fs30.default.constants.O_NOFOLLOW ?? 0)
|
|
14472
15129
|
);
|
|
14473
15130
|
} catch (error) {
|
|
14474
15131
|
if (isErrno2(error, "ENOENT")) return void 0;
|
|
14475
15132
|
throw claimError("invalid-state", "network claim state could not be read");
|
|
14476
15133
|
}
|
|
14477
15134
|
try {
|
|
14478
|
-
const stat =
|
|
15135
|
+
const stat = import_node_fs30.default.fstatSync(descriptor);
|
|
14479
15136
|
if (!stat.isFile() || stat.size > NETWORK_CLAIMS_MAX_FILE_BYTES || (stat.mode & 63) !== 0) {
|
|
14480
15137
|
throw claimError("invalid-state", "network claim state is not a bounded private file");
|
|
14481
15138
|
}
|
|
14482
15139
|
const buffer = Buffer.alloc(NETWORK_CLAIMS_MAX_FILE_BYTES + 1);
|
|
14483
15140
|
let count = 0;
|
|
14484
15141
|
while (count < buffer.length) {
|
|
14485
|
-
const bytesRead =
|
|
15142
|
+
const bytesRead = import_node_fs30.default.readSync(descriptor, buffer, count, buffer.length - count, null);
|
|
14486
15143
|
if (bytesRead === 0) break;
|
|
14487
15144
|
count += bytesRead;
|
|
14488
15145
|
}
|
|
14489
|
-
const finalStat =
|
|
15146
|
+
const finalStat = import_node_fs30.default.fstatSync(descriptor);
|
|
14490
15147
|
if (count > NETWORK_CLAIMS_MAX_FILE_BYTES || finalStat.size !== stat.size) {
|
|
14491
15148
|
throw claimError("invalid-state", "network claim state changed during read");
|
|
14492
15149
|
}
|
|
@@ -14498,7 +15155,7 @@ function readDocument(store) {
|
|
|
14498
15155
|
}
|
|
14499
15156
|
return validateDocument(parsed, store.daemonId);
|
|
14500
15157
|
} finally {
|
|
14501
|
-
|
|
15158
|
+
import_node_fs30.default.closeSync(descriptor);
|
|
14502
15159
|
}
|
|
14503
15160
|
}
|
|
14504
15161
|
function validateDocument(value, daemonId) {
|
|
@@ -14565,21 +15222,21 @@ function createStore(daemonId, options) {
|
|
|
14565
15222
|
return {
|
|
14566
15223
|
root,
|
|
14567
15224
|
daemonId,
|
|
14568
|
-
filePath:
|
|
14569
|
-
lockPath:
|
|
15225
|
+
filePath: import_node_path37.default.join(root, `${key}.json`),
|
|
15226
|
+
lockPath: import_node_path37.default.join(root, `${key}.lock`),
|
|
14570
15227
|
writeAtomic: options.writeAtomic ?? writeFileAtomically
|
|
14571
15228
|
};
|
|
14572
15229
|
}
|
|
14573
15230
|
function validateRoot(root) {
|
|
14574
|
-
if (typeof root !== "string" || !
|
|
15231
|
+
if (typeof root !== "string" || !import_node_path37.default.isAbsolute(root) || root.includes("\0")) {
|
|
14575
15232
|
throw claimError("invalid-input", "network claim root is invalid");
|
|
14576
15233
|
}
|
|
14577
|
-
const resolved2 =
|
|
15234
|
+
const resolved2 = import_node_path37.default.resolve(root);
|
|
14578
15235
|
if (resolved2 !== root) throw claimError("invalid-input", "network claim root is invalid");
|
|
14579
15236
|
return resolved2;
|
|
14580
15237
|
}
|
|
14581
15238
|
function hashKey(value) {
|
|
14582
|
-
return (0,
|
|
15239
|
+
return (0, import_node_crypto19.createHash)("sha256").update(value).digest("hex");
|
|
14583
15240
|
}
|
|
14584
15241
|
function cloneFence(fence) {
|
|
14585
15242
|
return { ...fence };
|
|
@@ -14602,20 +15259,20 @@ function isErrno2(error, code) {
|
|
|
14602
15259
|
function claimError(code, message) {
|
|
14603
15260
|
return new NetworkClaimError(code, message);
|
|
14604
15261
|
}
|
|
14605
|
-
var
|
|
15262
|
+
var import_node_crypto19, import_node_fs30, import_node_path37, NETWORK_CLAIMS_VERSION, NETWORK_CLAIMS_ROOT, NETWORK_CLAIMS_MAX_RECORDS, NETWORK_CLAIMS_MAX_FILE_BYTES, NetworkClaimError, CLAIM_CORE_KEYS, CLAIM_KEYS, FENCE_KEYS, DOCUMENT_KEYS, MAX_CLAIM_TEXT, MAX_ENDPOINT_TEXT;
|
|
14606
15263
|
var init_network_claims = __esm({
|
|
14607
15264
|
"src/core/network-claims.ts"() {
|
|
14608
15265
|
"use strict";
|
|
14609
|
-
|
|
14610
|
-
|
|
14611
|
-
|
|
15266
|
+
import_node_crypto19 = require("crypto");
|
|
15267
|
+
import_node_fs30 = __toESM(require("fs"));
|
|
15268
|
+
import_node_path37 = __toESM(require("path"));
|
|
14612
15269
|
init_atomic_file();
|
|
14613
15270
|
init_file_lock();
|
|
14614
15271
|
init_network_capacity();
|
|
14615
15272
|
init_network_policy();
|
|
14616
15273
|
init_router();
|
|
14617
15274
|
NETWORK_CLAIMS_VERSION = 1;
|
|
14618
|
-
NETWORK_CLAIMS_ROOT =
|
|
15275
|
+
NETWORK_CLAIMS_ROOT = import_node_path37.default.join(DEVROUTER_HOME, "networks");
|
|
14619
15276
|
NETWORK_CLAIMS_MAX_RECORDS = 256;
|
|
14620
15277
|
NETWORK_CLAIMS_MAX_FILE_BYTES = 512 * 1024;
|
|
14621
15278
|
NetworkClaimError = class extends Error {
|
|
@@ -14657,14 +15314,14 @@ var init_network_claims = __esm({
|
|
|
14657
15314
|
|
|
14658
15315
|
// src/core/network-claim-lookup.ts
|
|
14659
15316
|
function networkOwnerKey(repoPath) {
|
|
14660
|
-
if (!
|
|
15317
|
+
if (!import_node_path38.default.isAbsolute(repoPath) || import_node_path38.default.resolve(repoPath) !== repoPath)
|
|
14661
15318
|
throw new Error("Invalid network owner path.");
|
|
14662
|
-
return (0,
|
|
15319
|
+
return (0, import_node_crypto20.createHash)("sha256").update(repoPath).digest("hex");
|
|
14663
15320
|
}
|
|
14664
15321
|
function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
14665
15322
|
let names;
|
|
14666
15323
|
try {
|
|
14667
|
-
names =
|
|
15324
|
+
names = import_node_fs31.default.readdirSync(root);
|
|
14668
15325
|
} catch (error) {
|
|
14669
15326
|
if (error.code === "ENOENT") return void 0;
|
|
14670
15327
|
throw new Error("Network claims cannot be inspected; repair is required.");
|
|
@@ -14673,21 +15330,21 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
14673
15330
|
if (files.length > 128) throw new Error("Network daemon inventory exceeds its bound.");
|
|
14674
15331
|
let found;
|
|
14675
15332
|
for (const file of files) {
|
|
14676
|
-
const full =
|
|
14677
|
-
const stat =
|
|
15333
|
+
const full = import_node_path38.default.join(root, file);
|
|
15334
|
+
const stat = import_node_fs31.default.lstatSync(full);
|
|
14678
15335
|
if (!stat.isFile() || stat.size > NETWORK_CLAIMS_MAX_FILE_BYTES)
|
|
14679
15336
|
throw new Error("Invalid retained network claim file.");
|
|
14680
15337
|
let value;
|
|
14681
|
-
const descriptor =
|
|
15338
|
+
const descriptor = import_node_fs31.default.openSync(
|
|
14682
15339
|
full,
|
|
14683
|
-
|
|
15340
|
+
import_node_fs31.default.constants.O_RDONLY | import_node_fs31.default.constants.O_NONBLOCK | import_node_fs31.default.constants.O_NOFOLLOW
|
|
14684
15341
|
);
|
|
14685
15342
|
try {
|
|
14686
|
-
if (!
|
|
15343
|
+
if (!import_node_fs31.default.fstatSync(descriptor).isFile()) throw new Error();
|
|
14687
15344
|
const bytes2 = Buffer.alloc(NETWORK_CLAIMS_MAX_FILE_BYTES + 1);
|
|
14688
15345
|
let size = 0;
|
|
14689
15346
|
while (size < bytes2.length) {
|
|
14690
|
-
const count =
|
|
15347
|
+
const count = import_node_fs31.default.readSync(descriptor, bytes2, size, bytes2.length - size, null);
|
|
14691
15348
|
if (!count) break;
|
|
14692
15349
|
size += count;
|
|
14693
15350
|
}
|
|
@@ -14697,9 +15354,9 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
14697
15354
|
} catch {
|
|
14698
15355
|
throw new Error("Retained network claim could not be read safely.");
|
|
14699
15356
|
} finally {
|
|
14700
|
-
|
|
15357
|
+
import_node_fs31.default.closeSync(descriptor);
|
|
14701
15358
|
}
|
|
14702
|
-
if (typeof value.daemonId !== "string" || `${(0,
|
|
15359
|
+
if (typeof value.daemonId !== "string" || `${(0, import_node_crypto20.createHash)("sha256").update(value.daemonId).digest("hex")}.json` !== file)
|
|
14703
15360
|
throw new Error("Retained network daemon identity is invalid.");
|
|
14704
15361
|
const claim2 = readNetworkClaim({
|
|
14705
15362
|
daemonId: value.daemonId,
|
|
@@ -14713,140 +15370,17 @@ function findOwnedNetworkClaim(repoPath, root = NETWORK_CLAIMS_ROOT) {
|
|
|
14713
15370
|
}
|
|
14714
15371
|
return found;
|
|
14715
15372
|
}
|
|
14716
|
-
var
|
|
15373
|
+
var import_node_crypto20, import_node_fs31, import_node_path38;
|
|
14717
15374
|
var init_network_claim_lookup = __esm({
|
|
14718
15375
|
"src/core/network-claim-lookup.ts"() {
|
|
14719
15376
|
"use strict";
|
|
14720
|
-
|
|
14721
|
-
|
|
14722
|
-
|
|
15377
|
+
import_node_crypto20 = require("crypto");
|
|
15378
|
+
import_node_fs31 = __toESM(require("fs"));
|
|
15379
|
+
import_node_path38 = __toESM(require("path"));
|
|
14723
15380
|
init_network_claims();
|
|
14724
15381
|
}
|
|
14725
15382
|
});
|
|
14726
15383
|
|
|
14727
|
-
// src/core/network-provider-inspect.ts
|
|
14728
|
-
function object3(value) {
|
|
14729
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
14730
|
-
throw new Error("Invalid provider evidence.");
|
|
14731
|
-
return value;
|
|
14732
|
-
}
|
|
14733
|
-
function qualifyNetworkProviderDefinition(value, provider) {
|
|
14734
|
-
const definition = object3(value);
|
|
14735
|
-
const agent = object3(definition.agent);
|
|
14736
|
-
const docker = object3(agent.docker);
|
|
14737
|
-
const env = object3(docker.env);
|
|
14738
|
-
const options = object3(definition.options);
|
|
14739
|
-
const host = object3(options.DOCKER_HOST);
|
|
14740
|
-
const dockerPath = object3(options.DOCKER_PATH);
|
|
14741
|
-
const exec = object3(definition.exec);
|
|
14742
|
-
const command = provider === "devsy" ? '"${DEVSY}" internal sh -c "${COMMAND}"' : '"${DEVPOD}" helper sh -c "${COMMAND}"';
|
|
14743
|
-
const actualCommand = Array.isArray(exec.command) ? exec.command : [exec.command];
|
|
14744
|
-
if (definition.name !== "docker" || ![true, "true"].includes(agent.local) || agent.driver !== void 0 && agent.driver !== "docker" && agent.driver !== "" || docker.path !== "${DOCKER_PATH}" || docker.builder !== "${DOCKER_BUILDER}" || ![false, "false"].includes(docker.install) || (provider === "devsy" ? docker.elevation !== "${DOCKER_ELEVATION}" : docker.elevation !== void 0 && docker.elevation !== "") || env.DOCKER_HOST !== "${DOCKER_HOST}" || Object.keys(env).some((key) => key !== "DOCKER_HOST") || host.global !== true || dockerPath.default !== "docker" || actualCommand.length !== 1 || typeof actualCommand[0] !== "string" || actualCommand[0].trim() !== command || Object.keys(exec).some((key) => key !== "command") || agent.path !== void 0 && agent.path !== "" || agent.downloadURL !== void 0 && agent.downloadURL !== "") {
|
|
14745
|
-
throw new Error("Docker provider definition is not qualified for network allocation.");
|
|
14746
|
-
}
|
|
14747
|
-
return (0, import_node_crypto17.createHash)("sha256").update(JSON.stringify({ name: definition.name, agent, options, exec })).digest("hex");
|
|
14748
|
-
}
|
|
14749
|
-
function read(provider, args) {
|
|
14750
|
-
const result = (0, import_node_child_process18.spawnSync)(provider, args, {
|
|
14751
|
-
encoding: "utf8",
|
|
14752
|
-
timeout: 5e3,
|
|
14753
|
-
maxBuffer: 2 * 1024 * 1024
|
|
14754
|
-
});
|
|
14755
|
-
if (result.error || result.status !== 0)
|
|
14756
|
-
throw new Error("Network provider evidence is unavailable.");
|
|
14757
|
-
return result.stdout;
|
|
14758
|
-
}
|
|
14759
|
-
function inspectNetworkProviderBinding(input2) {
|
|
14760
|
-
try {
|
|
14761
|
-
const { provider, providerId, repoPath } = input2;
|
|
14762
|
-
const contexts = JSON.parse(
|
|
14763
|
-
read(provider, [
|
|
14764
|
-
"context",
|
|
14765
|
-
"list",
|
|
14766
|
-
...provider === "devsy" ? ["--result-format", "json"] : ["--output", "json"]
|
|
14767
|
-
])
|
|
14768
|
-
);
|
|
14769
|
-
if (!Array.isArray(contexts) || contexts.length > 128) throw new Error();
|
|
14770
|
-
const selected = contexts.map(object3).filter(
|
|
14771
|
-
(row) => input2.providerContext ? row.name === input2.providerContext : row.default === true
|
|
14772
|
-
);
|
|
14773
|
-
if (selected.length !== 1 || typeof selected[0].name !== "string") throw new Error();
|
|
14774
|
-
const providerContext = selected[0].name;
|
|
14775
|
-
if (!/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(providerContext)) throw new Error();
|
|
14776
|
-
const contextArgs = ["--context", providerContext];
|
|
14777
|
-
const version = read(provider, provider === "devsy" ? ["--version"] : ["version"]);
|
|
14778
|
-
const parsedVersion = version.match(/\b(?:v)?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\b/)?.[1];
|
|
14779
|
-
if (provider === "devsy" ? !isSupportedDevsyVersion(parsedVersion) : parsedVersion !== "0.6.15")
|
|
14780
|
-
throw new Error();
|
|
14781
|
-
const definitions = object3(
|
|
14782
|
-
JSON.parse(
|
|
14783
|
-
read(
|
|
14784
|
-
provider,
|
|
14785
|
-
provider === "devsy" ? ["provider", "list", "--result-format", "json", ...contextArgs] : ["provider", "list", "--output", "json", ...contextArgs]
|
|
14786
|
-
)
|
|
14787
|
-
)
|
|
14788
|
-
);
|
|
14789
|
-
const entry = object3(definitions.docker);
|
|
14790
|
-
const definitionSha256 = qualifyNetworkProviderDefinition(entry.config, provider);
|
|
14791
|
-
const rows2 = JSON.parse(
|
|
14792
|
-
read(
|
|
14793
|
-
provider,
|
|
14794
|
-
provider === "devsy" ? ["workspace", "list", "--result-format", "json", "--skip-pro", ...contextArgs] : ["list", "--output", "json", "--skip-pro", ...contextArgs]
|
|
14795
|
-
)
|
|
14796
|
-
);
|
|
14797
|
-
if (!Array.isArray(rows2) || rows2.length > 4096) throw new Error();
|
|
14798
|
-
const matching = rows2.map(object3).filter((row) => row.id === providerId || object3(row.source).localFolder === repoPath);
|
|
14799
|
-
if (matching.length > 1) throw new Error();
|
|
14800
|
-
const workspace = matching[0];
|
|
14801
|
-
if (workspace && (workspace.id !== providerId || object3(workspace.source).localFolder !== repoPath))
|
|
14802
|
-
throw new Error();
|
|
14803
|
-
const workspaceProvider = workspace ? object3(workspace.provider) : void 0;
|
|
14804
|
-
const state = object3(entry.state);
|
|
14805
|
-
const settings = object3(state.options ?? {});
|
|
14806
|
-
const stored = workspaceProvider ? object3(workspaceProvider.options ?? {}) : {};
|
|
14807
|
-
const option = (key, localOnly = false) => {
|
|
14808
|
-
const value = localOnly ? stored[key] : stored[key] ?? settings[key];
|
|
14809
|
-
if (value === void 0) return null;
|
|
14810
|
-
const text6 = object3(value).value;
|
|
14811
|
-
if (typeof text6 !== "string") throw new Error();
|
|
14812
|
-
return text6 || null;
|
|
14813
|
-
};
|
|
14814
|
-
if (workspaceProvider && workspaceProvider.name !== "docker") throw new Error();
|
|
14815
|
-
if (option("DOCKER_ELEVATION") && option("DOCKER_ELEVATION") !== "none") throw new Error();
|
|
14816
|
-
const endpoint = input2.endpoint ?? option("DOCKER_HOST");
|
|
14817
|
-
if (!endpoint || !input2.endpoint && (process.env.DOCKER_CONTEXT || option("DOCKER_CONTEXT") || (option("DOCKER_PATH") ?? "docker") !== "docker" || !workspace && entry.default !== true))
|
|
14818
|
-
throw new Error();
|
|
14819
|
-
return {
|
|
14820
|
-
provider,
|
|
14821
|
-
providerContext,
|
|
14822
|
-
providerId,
|
|
14823
|
-
endpoint,
|
|
14824
|
-
daemonId: inspectManagedStopDaemon(endpoint),
|
|
14825
|
-
versionQualified: true,
|
|
14826
|
-
definitionSha256,
|
|
14827
|
-
providerName: "docker",
|
|
14828
|
-
dockerPath: option("DOCKER_PATH") ?? "docker",
|
|
14829
|
-
persistedEndpoint: workspace ? option("DOCKER_HOST", true) : null,
|
|
14830
|
-
persistedContext: option("DOCKER_CONTEXT"),
|
|
14831
|
-
registration: workspace ? "owned" : "absent"
|
|
14832
|
-
};
|
|
14833
|
-
} catch {
|
|
14834
|
-
throw new Error(
|
|
14835
|
-
"Network provider destination could not be qualified; no allocation is permitted."
|
|
14836
|
-
);
|
|
14837
|
-
}
|
|
14838
|
-
}
|
|
14839
|
-
var import_node_child_process18, import_node_crypto17;
|
|
14840
|
-
var init_network_provider_inspect = __esm({
|
|
14841
|
-
"src/core/network-provider-inspect.ts"() {
|
|
14842
|
-
"use strict";
|
|
14843
|
-
import_node_child_process18 = require("child_process");
|
|
14844
|
-
import_node_crypto17 = require("crypto");
|
|
14845
|
-
init_devpod_environment();
|
|
14846
|
-
init_devsy_agent();
|
|
14847
|
-
}
|
|
14848
|
-
});
|
|
14849
|
-
|
|
14850
15384
|
// src/core/network-provider-effect.ts
|
|
14851
15385
|
function networkProviderEffectOptions(provider, providerId, repoPath) {
|
|
14852
15386
|
const claim2 = findOwnedNetworkClaim(repoPath);
|
|
@@ -14880,7 +15414,7 @@ var init_network_provider_effect = __esm({
|
|
|
14880
15414
|
|
|
14881
15415
|
// src/core/devsy-mutation.ts
|
|
14882
15416
|
function withMutationLock(activity, target, operation) {
|
|
14883
|
-
|
|
15417
|
+
import_node_fs32.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
14884
15418
|
return withFileLockSync(
|
|
14885
15419
|
DEVSY_MUTATION_LOCK_FILE,
|
|
14886
15420
|
{
|
|
@@ -14900,7 +15434,7 @@ function runDevsyAction(action2, devsyId, force = false, repoPath) {
|
|
|
14900
15434
|
const args = action2 === "delete" ? ["delete", devsyId, ...force ? ["--force"] : [], "--ignore-not-found"] : ["stop", devsyId];
|
|
14901
15435
|
claimLifecycleEffect();
|
|
14902
15436
|
const binding = repoPath ? networkProviderEffectOptions("devsy", devsyId, repoPath) : { args: [] };
|
|
14903
|
-
const result = (0,
|
|
15437
|
+
const result = (0, import_node_child_process22.spawnSync)("devsy", ["workspace", ...args, ...binding.args], {
|
|
14904
15438
|
encoding: "utf-8",
|
|
14905
15439
|
...binding.env ? { env: binding.env } : {}
|
|
14906
15440
|
});
|
|
@@ -14917,7 +15451,7 @@ function inspectExactOwnership(devsyId, worktreePath) {
|
|
|
14917
15451
|
}
|
|
14918
15452
|
function checkoutVanished(worktreePath) {
|
|
14919
15453
|
try {
|
|
14920
|
-
|
|
15454
|
+
import_node_fs32.default.lstatSync(worktreePath);
|
|
14921
15455
|
return false;
|
|
14922
15456
|
} catch (error) {
|
|
14923
15457
|
return error.code === "ENOENT";
|
|
@@ -14987,13 +15521,13 @@ function stopOwnedDevsyWorkspace(devsyId, worktreePath) {
|
|
|
14987
15521
|
function deleteOwnedDevsyWorkspace(devsyId, worktreePath) {
|
|
14988
15522
|
return mutateOwnedDevsyWorkspace("delete", devsyId, worktreePath);
|
|
14989
15523
|
}
|
|
14990
|
-
var
|
|
15524
|
+
var import_node_child_process22, import_node_fs32, import_node_path39, DEVSY_MUTATION_LOCK_FILE, DEVSY_MUTATION_WAIT_MS;
|
|
14991
15525
|
var init_devsy_mutation = __esm({
|
|
14992
15526
|
"src/core/devsy-mutation.ts"() {
|
|
14993
15527
|
"use strict";
|
|
14994
|
-
|
|
14995
|
-
|
|
14996
|
-
|
|
15528
|
+
import_node_child_process22 = require("child_process");
|
|
15529
|
+
import_node_fs32 = __toESM(require("fs"));
|
|
15530
|
+
import_node_path39 = __toESM(require("path"));
|
|
14997
15531
|
init_devsy_agent();
|
|
14998
15532
|
init_devsy_workspaces();
|
|
14999
15533
|
init_file_lock();
|
|
@@ -15002,7 +15536,7 @@ var init_devsy_mutation = __esm({
|
|
|
15002
15536
|
init_network_provider_effect();
|
|
15003
15537
|
init_reliability_context();
|
|
15004
15538
|
init_router();
|
|
15005
|
-
DEVSY_MUTATION_LOCK_FILE =
|
|
15539
|
+
DEVSY_MUTATION_LOCK_FILE = import_node_path39.default.join(DEVROUTER_HOME, "devsy-mutation.lock");
|
|
15006
15540
|
DEVSY_MUTATION_WAIT_MS = 18e5;
|
|
15007
15541
|
}
|
|
15008
15542
|
});
|
|
@@ -15079,15 +15613,15 @@ function assertFreshBootstrapRequest(identity2, options) {
|
|
|
15079
15613
|
throw new Error("Fresh bootstrap refuses a retained runtime or provider registration.");
|
|
15080
15614
|
qualifiedContext(readDevcontainerConfig(identity2.repoPath).source);
|
|
15081
15615
|
}
|
|
15082
|
-
var
|
|
15616
|
+
var import_node_child_process23, import_node_crypto21, import_node_fs33, import_node_os6, import_node_path40, import_node_util11, import_yaml4;
|
|
15083
15617
|
var init_managed_fresh_bootstrap = __esm({
|
|
15084
15618
|
"src/core/managed-fresh-bootstrap.ts"() {
|
|
15085
15619
|
"use strict";
|
|
15086
|
-
|
|
15087
|
-
|
|
15088
|
-
|
|
15620
|
+
import_node_child_process23 = require("child_process");
|
|
15621
|
+
import_node_crypto21 = require("crypto");
|
|
15622
|
+
import_node_fs33 = __toESM(require("fs"));
|
|
15089
15623
|
import_node_os6 = __toESM(require("os"));
|
|
15090
|
-
|
|
15624
|
+
import_node_path40 = __toESM(require("path"));
|
|
15091
15625
|
import_node_util11 = require("util");
|
|
15092
15626
|
import_yaml4 = __toESM(require("yaml"));
|
|
15093
15627
|
init_devcontainer_config();
|
|
@@ -15108,289 +15642,6 @@ var init_managed_fresh_bootstrap = __esm({
|
|
|
15108
15642
|
}
|
|
15109
15643
|
});
|
|
15110
15644
|
|
|
15111
|
-
// src/core/managed-host-ports.ts
|
|
15112
|
-
function unavailableEntry(declaration, reason2) {
|
|
15113
|
-
return { ...declaration, status: "unavailable", reason: reason2 };
|
|
15114
|
-
}
|
|
15115
|
-
function livePublishedBindings(containerId, target) {
|
|
15116
|
-
const result = (0, import_node_child_process21.spawnSync)("docker", ["port", containerId, `${target}/tcp`], {
|
|
15117
|
-
encoding: "utf-8",
|
|
15118
|
-
timeout: PORT_LOOKUP_TIMEOUT_MS,
|
|
15119
|
-
maxBuffer: PORT_LOOKUP_MAX_BUFFER,
|
|
15120
|
-
...networkDockerOptions()
|
|
15121
|
-
});
|
|
15122
|
-
if (result.error || result.status === null) return void 0;
|
|
15123
|
-
if (result.status !== 0) return "";
|
|
15124
|
-
return typeof result.stdout === "string" ? result.stdout : void 0;
|
|
15125
|
-
}
|
|
15126
|
-
function parseLoopbackBinding(output2) {
|
|
15127
|
-
const lines = output2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
|
|
15128
|
-
if (lines.length === 0) return { reason: "not-published" };
|
|
15129
|
-
if (lines.length > 1) return { reason: "ambiguous" };
|
|
15130
|
-
const match = LOOPBACK_BINDING.exec(lines[0]);
|
|
15131
|
-
if (!match) return { reason: "not-published" };
|
|
15132
|
-
const port = Number(match[1]);
|
|
15133
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) return { reason: "not-published" };
|
|
15134
|
-
return { endpoint: { host: "127.0.0.1", port } };
|
|
15135
|
-
}
|
|
15136
|
-
function revalidateLiveOwner(containerId, input2, composeProject, composeFiles2, service) {
|
|
15137
|
-
try {
|
|
15138
|
-
const current = inspectWorkspaceContainers({ ids: [containerId] });
|
|
15139
|
-
if (current.length !== 1 || current[0].id !== containerId) return "unavailable";
|
|
15140
|
-
if (!hasExactComposeIdentity(current[0], {
|
|
15141
|
-
repoPath: input2.repoPath,
|
|
15142
|
-
service,
|
|
15143
|
-
composeProject,
|
|
15144
|
-
composeFiles: composeFiles2
|
|
15145
|
-
})) {
|
|
15146
|
-
return "unavailable";
|
|
15147
|
-
}
|
|
15148
|
-
return current[0].state.Running ? "available" : "not-running";
|
|
15149
|
-
} catch {
|
|
15150
|
-
return "unavailable";
|
|
15151
|
-
}
|
|
15152
|
-
}
|
|
15153
|
-
function resolveManagedHostPorts(input2) {
|
|
15154
|
-
const report = {};
|
|
15155
|
-
const selectedServices = new Set(input2.selectedServices);
|
|
15156
|
-
const selectedKeys = [];
|
|
15157
|
-
for (const [key, declaration] of Object.entries(input2.declarations)) {
|
|
15158
|
-
if (!selectedServices.has(declaration.service)) {
|
|
15159
|
-
report[key] = { ...declaration, status: "inactive" };
|
|
15160
|
-
continue;
|
|
15161
|
-
}
|
|
15162
|
-
selectedKeys.push(key);
|
|
15163
|
-
report[key] = { ...declaration, status: "unavailable", reason: "unavailable" };
|
|
15164
|
-
}
|
|
15165
|
-
if (selectedKeys.length === 0) return report;
|
|
15166
|
-
const composeProject = input2.composeProject;
|
|
15167
|
-
const composeFiles2 = input2.composeFiles;
|
|
15168
|
-
if (typeof composeProject !== "string" || composeProject.length === 0 || composeFiles2 === void 0 || composeFiles2.length === 0 || composeFiles2.some((file) => file.length === 0)) {
|
|
15169
|
-
return report;
|
|
15170
|
-
}
|
|
15171
|
-
if (selectedKeys.some((key) => {
|
|
15172
|
-
const target = input2.declarations[key].target;
|
|
15173
|
-
return !Number.isInteger(target) || target < 1 || target > 65535;
|
|
15174
|
-
})) {
|
|
15175
|
-
return report;
|
|
15176
|
-
}
|
|
15177
|
-
const liveContainers = input2.containers === void 0;
|
|
15178
|
-
let containers2 = input2.containers;
|
|
15179
|
-
if (containers2 === void 0) {
|
|
15180
|
-
try {
|
|
15181
|
-
containers2 = inspectWorkspaceContainers({ composeProject });
|
|
15182
|
-
} catch {
|
|
15183
|
-
return report;
|
|
15184
|
-
}
|
|
15185
|
-
}
|
|
15186
|
-
const publishedBindings = input2.publishedBindings ?? livePublishedBindings;
|
|
15187
|
-
for (const key of selectedKeys) {
|
|
15188
|
-
const declaration = input2.declarations[key];
|
|
15189
|
-
let owners;
|
|
15190
|
-
try {
|
|
15191
|
-
owners = containers2.filter(
|
|
15192
|
-
(container) => hasExactComposeIdentity(container, {
|
|
15193
|
-
repoPath: input2.repoPath,
|
|
15194
|
-
service: declaration.service,
|
|
15195
|
-
composeProject,
|
|
15196
|
-
composeFiles: composeFiles2
|
|
15197
|
-
})
|
|
15198
|
-
);
|
|
15199
|
-
} catch {
|
|
15200
|
-
report[key] = unavailableEntry(declaration, "unavailable");
|
|
15201
|
-
continue;
|
|
15202
|
-
}
|
|
15203
|
-
if (owners.length === 0) {
|
|
15204
|
-
report[key] = unavailableEntry(declaration, "not-found");
|
|
15205
|
-
continue;
|
|
15206
|
-
}
|
|
15207
|
-
if (owners.length > 1) {
|
|
15208
|
-
report[key] = unavailableEntry(declaration, "ambiguous");
|
|
15209
|
-
continue;
|
|
15210
|
-
}
|
|
15211
|
-
const owner = owners[0];
|
|
15212
|
-
if (!owner.state.Running) {
|
|
15213
|
-
report[key] = unavailableEntry(declaration, "not-running");
|
|
15214
|
-
continue;
|
|
15215
|
-
}
|
|
15216
|
-
let output2;
|
|
15217
|
-
try {
|
|
15218
|
-
output2 = publishedBindings(owner.id, declaration.target);
|
|
15219
|
-
} catch {
|
|
15220
|
-
output2 = void 0;
|
|
15221
|
-
}
|
|
15222
|
-
if (typeof output2 !== "string") {
|
|
15223
|
-
report[key] = unavailableEntry(declaration, "unavailable");
|
|
15224
|
-
continue;
|
|
15225
|
-
}
|
|
15226
|
-
const binding = parseLoopbackBinding(output2);
|
|
15227
|
-
if (!binding.endpoint) {
|
|
15228
|
-
report[key] = unavailableEntry(declaration, binding.reason ?? "unavailable");
|
|
15229
|
-
continue;
|
|
15230
|
-
}
|
|
15231
|
-
if (liveContainers) {
|
|
15232
|
-
const proof = revalidateLiveOwner(
|
|
15233
|
-
owner.id,
|
|
15234
|
-
input2,
|
|
15235
|
-
composeProject,
|
|
15236
|
-
composeFiles2,
|
|
15237
|
-
declaration.service
|
|
15238
|
-
);
|
|
15239
|
-
if (proof !== "available") {
|
|
15240
|
-
report[key] = unavailableEntry(declaration, proof);
|
|
15241
|
-
continue;
|
|
15242
|
-
}
|
|
15243
|
-
}
|
|
15244
|
-
report[key] = {
|
|
15245
|
-
...declaration,
|
|
15246
|
-
status: "available",
|
|
15247
|
-
endpoint: binding.endpoint
|
|
15248
|
-
};
|
|
15249
|
-
}
|
|
15250
|
-
return report;
|
|
15251
|
-
}
|
|
15252
|
-
function managedHostPortDeclarationsIdentity(declarations) {
|
|
15253
|
-
const keys2 = Object.keys(declarations).sort();
|
|
15254
|
-
if (keys2.length === 0) return void 0;
|
|
15255
|
-
const canonical = keys2.map((key) => [key, declarations[key].service, declarations[key].target]);
|
|
15256
|
-
return (0, import_node_crypto19.createHash)("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
15257
|
-
}
|
|
15258
|
-
function assertManagedHostPortsAvailable(report) {
|
|
15259
|
-
const unavailable = Object.entries(report).filter(([, entry]) => entry.status === "unavailable").map(([key]) => key).sort();
|
|
15260
|
-
if (unavailable.length > 0) {
|
|
15261
|
-
throw new Error(`Selected managed host ports are unavailable: ${unavailable.join(", ")}.`);
|
|
15262
|
-
}
|
|
15263
|
-
}
|
|
15264
|
-
var import_node_child_process21, import_node_crypto19, PORT_LOOKUP_TIMEOUT_MS, PORT_LOOKUP_MAX_BUFFER, LOOPBACK_BINDING;
|
|
15265
|
-
var init_managed_host_ports = __esm({
|
|
15266
|
-
"src/core/managed-host-ports.ts"() {
|
|
15267
|
-
"use strict";
|
|
15268
|
-
import_node_child_process21 = require("child_process");
|
|
15269
|
-
import_node_crypto19 = require("crypto");
|
|
15270
|
-
init_devpod_environment();
|
|
15271
|
-
init_network_effect_scope();
|
|
15272
|
-
PORT_LOOKUP_TIMEOUT_MS = 1e4;
|
|
15273
|
-
PORT_LOOKUP_MAX_BUFFER = 64 * 1024;
|
|
15274
|
-
LOOPBACK_BINDING = /^127\.0\.0\.1:(\d+)$/;
|
|
15275
|
-
}
|
|
15276
|
-
});
|
|
15277
|
-
|
|
15278
|
-
// src/core/managed-post-start.ts
|
|
15279
|
-
function readRegularFileBytes(filePath) {
|
|
15280
|
-
if (!import_node_fs32.default.existsSync(filePath) || !import_node_fs32.default.lstatSync(filePath).isFile()) return void 0;
|
|
15281
|
-
return import_node_fs32.default.readFileSync(filePath);
|
|
15282
|
-
}
|
|
15283
|
-
function readRegularFile(filePath) {
|
|
15284
|
-
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
15285
|
-
}
|
|
15286
|
-
function adapterFingerprint(adapter) {
|
|
15287
|
-
return (0, import_node_crypto20.createHash)("sha256").update(adapter).digest("hex");
|
|
15288
|
-
}
|
|
15289
|
-
function resolveManagedPostStartPlan(repoPath) {
|
|
15290
|
-
const adapterPath = import_node_path40.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
15291
|
-
const adapterBytes = readRegularFileBytes(adapterPath);
|
|
15292
|
-
const adapterText = adapterBytes?.toString("utf-8");
|
|
15293
|
-
const dockerfilePath = import_node_path40.default.join(repoPath, ".devcontainer", "Dockerfile");
|
|
15294
|
-
const devcontainerPath = import_node_path40.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
15295
|
-
const dockerfile = readRegularFile(dockerfilePath) ?? "";
|
|
15296
|
-
const devcontainer = readRegularFile(devcontainerPath) ?? "";
|
|
15297
|
-
const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
|
|
15298
|
-
(value) => value.includes("DEVROUTER_PROCESS_HELPER") || value.includes("devrouter-process")
|
|
15299
|
-
);
|
|
15300
|
-
if (adapterBytes === void 0) {
|
|
15301
|
-
if (devrouterPattern) {
|
|
15302
|
-
throw new Error(
|
|
15303
|
-
"Devrouter lifecycle wiring is incomplete: add the managed post-start adapter or remove the stale devrouter-process references."
|
|
15304
|
-
);
|
|
15305
|
-
}
|
|
15306
|
-
return { kind: "unmanaged" };
|
|
15307
|
-
}
|
|
15308
|
-
const adapter = adapterBytes.toString("utf-8");
|
|
15309
|
-
if (!adapter.includes(MANAGED_MARKER)) {
|
|
15310
|
-
if (devrouterPattern) {
|
|
15311
|
-
throw new Error(
|
|
15312
|
-
"Devrouter-looking post-start adapter is missing the 'devrouter:managed devcontainer' marker. Regenerate or migrate the devcontainer, then retry devrouter ensure."
|
|
15313
|
-
);
|
|
15314
|
-
}
|
|
15315
|
-
return { kind: "unmanaged" };
|
|
15316
|
-
}
|
|
15317
|
-
assertManagedDevcontainerLifecycle(repoPath);
|
|
15318
|
-
if (adapter.includes("DEVROUTER_PROCESS_HELPER")) {
|
|
15319
|
-
return {
|
|
15320
|
-
kind: "runtime",
|
|
15321
|
-
adapterPath: MANAGED_ADAPTER_PATH,
|
|
15322
|
-
adapterSha256: adapterFingerprint(adapterBytes),
|
|
15323
|
-
adapterContents: adapterBytes
|
|
15324
|
-
};
|
|
15325
|
-
}
|
|
15326
|
-
if (dockerfile.includes("devrouter-process") && devcontainer.includes("postStartCommand")) {
|
|
15327
|
-
return { kind: "legacy" };
|
|
15328
|
-
}
|
|
15329
|
-
throw new Error(
|
|
15330
|
-
"Managed post-start must use DEVROUTER_PROCESS_HELPER before removing the legacy image helper and postStartCommand. Regenerate or migrate the devcontainer, then retry devrouter ensure."
|
|
15331
|
-
);
|
|
15332
|
-
}
|
|
15333
|
-
function assertSafeProcessName(name) {
|
|
15334
|
-
if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(name)) {
|
|
15335
|
-
throw new Error(`Managed process '${name}' is not a safe exact identifier.`);
|
|
15336
|
-
}
|
|
15337
|
-
}
|
|
15338
|
-
function runManagedProcessAction(options) {
|
|
15339
|
-
assertSafeProcessName(options.name);
|
|
15340
|
-
const result = (0, import_node_child_process22.spawnSync)(
|
|
15341
|
-
"docker",
|
|
15342
|
-
[
|
|
15343
|
-
"exec",
|
|
15344
|
-
"--workdir",
|
|
15345
|
-
options.container.workspacePath,
|
|
15346
|
-
"--env",
|
|
15347
|
-
`DEVROUTER_PROCESS_HELPER=${RUNTIME_HELPER_PATH}`,
|
|
15348
|
-
options.container.id,
|
|
15349
|
-
"bash",
|
|
15350
|
-
"-c",
|
|
15351
|
-
'exec "$DEVROUTER_PROCESS_HELPER" "$1" --name "$2"',
|
|
15352
|
-
"devrouter-process",
|
|
15353
|
-
options.action,
|
|
15354
|
-
options.name
|
|
15355
|
-
],
|
|
15356
|
-
{
|
|
15357
|
-
encoding: "utf-8",
|
|
15358
|
-
stdio: options.action === "status" ? ["ignore", "pipe", "pipe"] : ["ignore", 2, "inherit"],
|
|
15359
|
-
...networkDockerOptions()
|
|
15360
|
-
}
|
|
15361
|
-
);
|
|
15362
|
-
if (options.action === "stop") {
|
|
15363
|
-
if (result.status !== 0) {
|
|
15364
|
-
throw new Error(`Could not stop managed process '${options.name}'.`);
|
|
15365
|
-
}
|
|
15366
|
-
return "stopped";
|
|
15367
|
-
}
|
|
15368
|
-
try {
|
|
15369
|
-
const parsed = JSON.parse(result.stdout.trim());
|
|
15370
|
-
if (parsed.status === "running" || parsed.status === "stopped" || parsed.status === "foreign" || parsed.status === "drifted") {
|
|
15371
|
-
return parsed.status;
|
|
15372
|
-
}
|
|
15373
|
-
} catch {
|
|
15374
|
-
}
|
|
15375
|
-
return "drifted";
|
|
15376
|
-
}
|
|
15377
|
-
var import_node_child_process22, import_node_crypto20, import_node_fs32, import_node_path40, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH;
|
|
15378
|
-
var init_managed_post_start = __esm({
|
|
15379
|
-
"src/core/managed-post-start.ts"() {
|
|
15380
|
-
"use strict";
|
|
15381
|
-
import_node_child_process22 = require("child_process");
|
|
15382
|
-
import_node_crypto20 = require("crypto");
|
|
15383
|
-
import_node_fs32 = __toESM(require("fs"));
|
|
15384
|
-
import_node_path40 = __toESM(require("path"));
|
|
15385
|
-
init_devcontainer_config();
|
|
15386
|
-
init_managed_host_ports();
|
|
15387
|
-
init_network_effect_scope();
|
|
15388
|
-
MANAGED_MARKER = "devrouter:managed devcontainer";
|
|
15389
|
-
MANAGED_ADAPTER_PATH = ".devcontainer/post-start.sh";
|
|
15390
|
-
RUNTIME_HELPER_PATH = "/tmp/devrouter/bin/devrouter-process";
|
|
15391
|
-
}
|
|
15392
|
-
});
|
|
15393
|
-
|
|
15394
15645
|
// src/core/recovery-budget.ts
|
|
15395
15646
|
function recoverySelectors(input2) {
|
|
15396
15647
|
const declared = new Set(input2.services);
|
|
@@ -16247,14 +16498,14 @@ var init_reliability_model = __esm({
|
|
|
16247
16498
|
|
|
16248
16499
|
// src/core/lifecycle-diagnostics.ts
|
|
16249
16500
|
function privateDirectory(directory) {
|
|
16250
|
-
const stat =
|
|
16501
|
+
const stat = import_node_fs34.default.lstatSync(directory);
|
|
16251
16502
|
return stat.isDirectory() && stat.uid === process.getuid?.() && (stat.mode & 63) === 0;
|
|
16252
16503
|
}
|
|
16253
16504
|
function lifecycleDiagnosticsPath(identity2) {
|
|
16254
16505
|
return import_node_path41.default.join(
|
|
16255
16506
|
DEVROUTER_HOME,
|
|
16256
16507
|
"lifecycle-diagnostics",
|
|
16257
|
-
`${(0,
|
|
16508
|
+
`${(0, import_node_crypto22.createHash)("sha256").update(identity2.repoPath).digest("hex")}.json`
|
|
16258
16509
|
);
|
|
16259
16510
|
}
|
|
16260
16511
|
function readReceipt(identity2) {
|
|
@@ -16262,15 +16513,15 @@ function readReceipt(identity2) {
|
|
|
16262
16513
|
try {
|
|
16263
16514
|
const file = lifecycleDiagnosticsPath(identity2);
|
|
16264
16515
|
if (!privateDirectory(import_node_path41.default.dirname(file))) return void 0;
|
|
16265
|
-
descriptor =
|
|
16516
|
+
descriptor = import_node_fs34.default.openSync(
|
|
16266
16517
|
file,
|
|
16267
|
-
|
|
16518
|
+
import_node_fs34.default.constants.O_RDONLY | import_node_fs34.default.constants.O_NOFOLLOW | import_node_fs34.default.constants.O_NONBLOCK
|
|
16268
16519
|
);
|
|
16269
|
-
const stat =
|
|
16520
|
+
const stat = import_node_fs34.default.fstatSync(descriptor);
|
|
16270
16521
|
if (!stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0 || stat.size > MAX_RECEIPT_BYTES)
|
|
16271
16522
|
return void 0;
|
|
16272
16523
|
const buffer = Buffer.alloc(MAX_RECEIPT_BYTES + 1);
|
|
16273
|
-
const size =
|
|
16524
|
+
const size = import_node_fs34.default.readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
16274
16525
|
if (size > MAX_RECEIPT_BYTES) return void 0;
|
|
16275
16526
|
const receipt = JSON.parse(buffer.subarray(0, size).toString("utf8"));
|
|
16276
16527
|
const timestamp = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
@@ -16287,7 +16538,7 @@ function readReceipt(identity2) {
|
|
|
16287
16538
|
} catch {
|
|
16288
16539
|
return void 0;
|
|
16289
16540
|
} finally {
|
|
16290
|
-
if (descriptor !== void 0)
|
|
16541
|
+
if (descriptor !== void 0) import_node_fs34.default.closeSync(descriptor);
|
|
16291
16542
|
}
|
|
16292
16543
|
}
|
|
16293
16544
|
function readLifecycleDiagnostics(identity2, now = Date.now()) {
|
|
@@ -16325,12 +16576,12 @@ function readLifecycleDiagnostics(identity2, now = Date.now()) {
|
|
|
16325
16576
|
return void 0;
|
|
16326
16577
|
}
|
|
16327
16578
|
}
|
|
16328
|
-
var
|
|
16579
|
+
var import_node_crypto22, import_node_fs34, import_node_path41, import_node_util12, MAX_TAIL_BYTES, MAX_RECEIPT_BYTES, PACKAGE_TASK, LifecycleDiagnosticRecorder;
|
|
16329
16580
|
var init_lifecycle_diagnostics = __esm({
|
|
16330
16581
|
"src/core/lifecycle-diagnostics.ts"() {
|
|
16331
16582
|
"use strict";
|
|
16332
|
-
|
|
16333
|
-
|
|
16583
|
+
import_node_crypto22 = require("crypto");
|
|
16584
|
+
import_node_fs34 = __toESM(require("fs"));
|
|
16334
16585
|
import_node_path41 = __toESM(require("path"));
|
|
16335
16586
|
import_node_util12 = require("util");
|
|
16336
16587
|
init_atomic_file();
|
|
@@ -16426,7 +16677,7 @@ var init_lifecycle_diagnostics = __esm({
|
|
|
16426
16677
|
this.receipt.output = chunks;
|
|
16427
16678
|
this.receipt.updatedAtMs = Date.now();
|
|
16428
16679
|
const file = lifecycleDiagnosticsPath(this.request.identity);
|
|
16429
|
-
|
|
16680
|
+
import_node_fs34.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true, mode: 448 });
|
|
16430
16681
|
if (!privateDirectory(import_node_path41.default.dirname(file))) return;
|
|
16431
16682
|
writeFileAtomically(file, `${JSON.stringify(this.receipt)}
|
|
16432
16683
|
`);
|
|
@@ -16460,11 +16711,11 @@ function workerGroupAbsent(pid) {
|
|
|
16460
16711
|
if (process.platform !== "linux") return false;
|
|
16461
16712
|
let observedZombie = false;
|
|
16462
16713
|
try {
|
|
16463
|
-
for (const entry of
|
|
16714
|
+
for (const entry of import_node_fs35.default.readdirSync("/proc")) {
|
|
16464
16715
|
if (!/^\d+$/.test(entry)) continue;
|
|
16465
16716
|
let stat;
|
|
16466
16717
|
try {
|
|
16467
|
-
stat =
|
|
16718
|
+
stat = import_node_fs35.default.readFileSync(`/proc/${entry}/stat`, "utf8");
|
|
16468
16719
|
} catch (error) {
|
|
16469
16720
|
if (error.code === "ENOENT") continue;
|
|
16470
16721
|
return false;
|
|
@@ -16496,9 +16747,9 @@ async function runLifecycleWorker(request2, supervision, beforeAdmission) {
|
|
|
16496
16747
|
if (process.platform === "win32")
|
|
16497
16748
|
throw new Error("Lifecycle workers require POSIX process-group ownership.");
|
|
16498
16749
|
const workerPath = import_node_path42.default.join(__dirname, "devrouter-lifecycle-worker.js");
|
|
16499
|
-
if (!
|
|
16750
|
+
if (!import_node_fs35.default.existsSync(workerPath))
|
|
16500
16751
|
throw new Error("The packaged lifecycle worker is missing; rebuild the CLI.");
|
|
16501
|
-
const child = (0,
|
|
16752
|
+
const child = (0, import_node_child_process24.fork)(workerPath, [], {
|
|
16502
16753
|
detached: true,
|
|
16503
16754
|
stdio: supervision ? ["ignore", "pipe", "pipe", "ipc"] : request2.kind === "ensure" ? ["inherit", "pipe", "pipe", "ipc"] : ["inherit", "inherit", "inherit", "ipc"],
|
|
16504
16755
|
execArgv: []
|
|
@@ -16787,15 +17038,15 @@ async function runLifecycleWorker(request2, supervision, beforeAdmission) {
|
|
|
16787
17038
|
}
|
|
16788
17039
|
}
|
|
16789
17040
|
function newLifecycleIds() {
|
|
16790
|
-
return { requestId: (0,
|
|
17041
|
+
return { requestId: (0, import_node_crypto23.randomUUID)(), operationId: (0, import_node_crypto23.randomUUID)(), workerId: (0, import_node_crypto23.randomUUID)() };
|
|
16791
17042
|
}
|
|
16792
|
-
var
|
|
17043
|
+
var import_node_child_process24, import_node_crypto23, import_node_fs35, import_node_path42, OUTPUT_BUFFER_LIMIT, DEFAULT_OUTPUT_PAGE_BYTES, LifecycleOutput, LifecycleWorkerAdmissionBusyError;
|
|
16793
17044
|
var init_reliability_worker = __esm({
|
|
16794
17045
|
"src/core/reliability-worker.ts"() {
|
|
16795
17046
|
"use strict";
|
|
16796
|
-
|
|
16797
|
-
|
|
16798
|
-
|
|
17047
|
+
import_node_child_process24 = require("child_process");
|
|
17048
|
+
import_node_crypto23 = require("crypto");
|
|
17049
|
+
import_node_fs35 = __toESM(require("fs"));
|
|
16799
17050
|
import_node_path42 = __toESM(require("path"));
|
|
16800
17051
|
init_file_lock();
|
|
16801
17052
|
init_lifecycle_diagnostics();
|
|
@@ -16915,7 +17166,7 @@ var init_reliability_worker = __esm({
|
|
|
16915
17166
|
|
|
16916
17167
|
// src/core/devpod-mutation.ts
|
|
16917
17168
|
function withMutationLock2(activity, target, operation) {
|
|
16918
|
-
|
|
17169
|
+
import_node_fs36.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
16919
17170
|
return withFileLockSync(
|
|
16920
17171
|
DEVPOD_MUTATION_LOCK_FILE,
|
|
16921
17172
|
{
|
|
@@ -16935,7 +17186,7 @@ function runDevpodAction(action2, devpodId, force = false, repoPath) {
|
|
|
16935
17186
|
const args = action2 === "delete" ? [action2, devpodId, ...force ? ["--force"] : [], "--ignore-not-found"] : [action2, devpodId];
|
|
16936
17187
|
claimLifecycleEffect();
|
|
16937
17188
|
const binding = repoPath ? networkProviderEffectOptions("devpod", devpodId, repoPath) : { args: [] };
|
|
16938
|
-
const result = (0,
|
|
17189
|
+
const result = (0, import_node_child_process25.spawnSync)("devpod", [...args, ...binding.args], {
|
|
16939
17190
|
encoding: "utf-8",
|
|
16940
17191
|
...binding.env ? { env: binding.env } : {}
|
|
16941
17192
|
});
|
|
@@ -17005,12 +17256,12 @@ function deleteOwnedDevpodWorkspace(devpodId, worktreePath) {
|
|
|
17005
17256
|
resetWorkspaceRuntimeCaches();
|
|
17006
17257
|
return result;
|
|
17007
17258
|
}
|
|
17008
|
-
var
|
|
17259
|
+
var import_node_child_process25, import_node_fs36, import_node_path43, DEVPOD_MUTATION_LOCK_FILE, DEVPOD_MUTATION_WAIT_MS;
|
|
17009
17260
|
var init_devpod_mutation = __esm({
|
|
17010
17261
|
"src/core/devpod-mutation.ts"() {
|
|
17011
17262
|
"use strict";
|
|
17012
|
-
|
|
17013
|
-
|
|
17263
|
+
import_node_child_process25 = require("child_process");
|
|
17264
|
+
import_node_fs36 = __toESM(require("fs"));
|
|
17014
17265
|
import_node_path43 = __toESM(require("path"));
|
|
17015
17266
|
init_devpod_workspaces();
|
|
17016
17267
|
init_devsy_mutation();
|
|
@@ -17121,7 +17372,7 @@ function hostPortBindingsConflict(desired, holder) {
|
|
|
17121
17372
|
(desired.hostIp === null || holder.hostIp === null || desired.hostIp === holder.hostIp);
|
|
17122
17373
|
}
|
|
17123
17374
|
function runDocker(args) {
|
|
17124
|
-
const result = (0,
|
|
17375
|
+
const result = (0, import_node_child_process26.spawnSync)("docker", args, {
|
|
17125
17376
|
...networkDockerOptions(),
|
|
17126
17377
|
encoding: "utf-8",
|
|
17127
17378
|
timeout: DOCKER_TIMEOUT_MS,
|
|
@@ -17191,7 +17442,7 @@ function listHolderSnapshots() {
|
|
|
17191
17442
|
}
|
|
17192
17443
|
function renderManagedComposeModel(plan, workspace) {
|
|
17193
17444
|
const fileArgs = plan.composeFiles.flatMap((file) => ["-f", file]);
|
|
17194
|
-
const result = (0,
|
|
17445
|
+
const result = (0, import_node_child_process26.spawnSync)(
|
|
17195
17446
|
"docker",
|
|
17196
17447
|
[
|
|
17197
17448
|
"compose",
|
|
@@ -17284,11 +17535,11 @@ function detectHostPortClaimConflicts(options) {
|
|
|
17284
17535
|
}
|
|
17285
17536
|
return conflicts;
|
|
17286
17537
|
}
|
|
17287
|
-
var
|
|
17538
|
+
var import_node_child_process26, import_node_path44, COMPOSE_RENDER_TIMEOUT_MS, COMPOSE_RENDER_MAX_BUFFER, DOCKER_TIMEOUT_MS, DOCKER_MAX_BUFFER, MAX_DESIRED_HOST_PORTS, MAX_RUNNING_HOLDERS, HOST_PORT_INSPECT_TEMPLATE;
|
|
17288
17539
|
var init_host_port_claims = __esm({
|
|
17289
17540
|
"src/core/host-port-claims.ts"() {
|
|
17290
17541
|
"use strict";
|
|
17291
|
-
|
|
17542
|
+
import_node_child_process26 = require("child_process");
|
|
17292
17543
|
import_node_path44 = __toESM(require("path"));
|
|
17293
17544
|
init_devcontainer_profile();
|
|
17294
17545
|
init_network_effect_scope();
|
|
@@ -17331,7 +17582,7 @@ function probeHttpRoute(host, options = {}) {
|
|
|
17331
17582
|
args.push("--cacert", CERT_FILE);
|
|
17332
17583
|
}
|
|
17333
17584
|
args.push(url);
|
|
17334
|
-
const result = (0,
|
|
17585
|
+
const result = (0, import_node_child_process27.spawnSync)("curl", args, { encoding: "utf-8" });
|
|
17335
17586
|
const stdout = result.stdout?.trim() ?? "";
|
|
17336
17587
|
const status = /^\d{3}$/.test(stdout) ? Number(stdout) : void 0;
|
|
17337
17588
|
const ok = result.status === 0 && status !== void 0 && status >= 100 && status < 500;
|
|
@@ -17366,7 +17617,7 @@ function probeHttpReadinessSync(host, readiness, maxTimeSeconds, repoPath) {
|
|
|
17366
17617
|
}
|
|
17367
17618
|
let result;
|
|
17368
17619
|
try {
|
|
17369
|
-
result = (0,
|
|
17620
|
+
result = (0, import_node_child_process27.spawnSync)("curl", args, {
|
|
17370
17621
|
encoding: "utf-8",
|
|
17371
17622
|
maxBuffer: CONTRACT_MAX_BUFFER,
|
|
17372
17623
|
timeout: Math.ceil(parentTimeoutMs)
|
|
@@ -17448,11 +17699,11 @@ function transportFailure() {
|
|
|
17448
17699
|
classification: "transport"
|
|
17449
17700
|
};
|
|
17450
17701
|
}
|
|
17451
|
-
var
|
|
17702
|
+
var import_node_child_process27, DEFAULT_MAX_TIME_SECONDS, CONTROLLER_CURL_MAX_TIME_SECONDS, PARENT_TIMEOUT_PADDING_MS, CONTRACT_MAX_BUFFER, MIME_TOKEN_RE2;
|
|
17452
17703
|
var init_http_route_probe = __esm({
|
|
17453
17704
|
"src/core/http-route-probe.ts"() {
|
|
17454
17705
|
"use strict";
|
|
17455
|
-
|
|
17706
|
+
import_node_child_process27 = require("child_process");
|
|
17456
17707
|
init_router();
|
|
17457
17708
|
init_tls();
|
|
17458
17709
|
DEFAULT_MAX_TIME_SECONDS = 5;
|
|
@@ -17464,12 +17715,12 @@ var init_http_route_probe = __esm({
|
|
|
17464
17715
|
});
|
|
17465
17716
|
|
|
17466
17717
|
// src/core/managed-host-preparation.ts
|
|
17467
|
-
var
|
|
17718
|
+
var import_node_child_process28, import_node_fs37;
|
|
17468
17719
|
var init_managed_host_preparation = __esm({
|
|
17469
17720
|
"src/core/managed-host-preparation.ts"() {
|
|
17470
17721
|
"use strict";
|
|
17471
|
-
|
|
17472
|
-
|
|
17722
|
+
import_node_child_process28 = require("child_process");
|
|
17723
|
+
import_node_fs37 = __toESM(require("fs"));
|
|
17473
17724
|
init_repo_config();
|
|
17474
17725
|
}
|
|
17475
17726
|
});
|
|
@@ -17594,7 +17845,7 @@ function classifyManagedMountNesting(configured, effectiveDestinations, containe
|
|
|
17594
17845
|
};
|
|
17595
17846
|
}
|
|
17596
17847
|
function readContainerMountinfo(containerId, options) {
|
|
17597
|
-
const result = (0,
|
|
17848
|
+
const result = (0, import_node_child_process29.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
|
|
17598
17849
|
encoding: "utf-8",
|
|
17599
17850
|
timeout: options.timeoutMs ?? 5e3,
|
|
17600
17851
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -17609,11 +17860,11 @@ function observeManagedMountNesting(container, options = {}) {
|
|
|
17609
17860
|
const effective = destinations.some((_destination, index) => isNestedIndex(destinations, index)) ? readContainerMountinfo(container.id, options) : null;
|
|
17610
17861
|
return classifyManagedMountNesting(container.mounts, effective, container.id);
|
|
17611
17862
|
}
|
|
17612
|
-
var
|
|
17863
|
+
var import_node_child_process29, NESTED_MOUNT_REASON, UNREADABLE_MOUNT_REASON;
|
|
17613
17864
|
var init_managed_mount_nesting = __esm({
|
|
17614
17865
|
"src/core/managed-mount-nesting.ts"() {
|
|
17615
17866
|
"use strict";
|
|
17616
|
-
|
|
17867
|
+
import_node_child_process29 = require("child_process");
|
|
17617
17868
|
init_network_effect_scope();
|
|
17618
17869
|
NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
|
|
17619
17870
|
UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
|
|
@@ -18175,7 +18426,7 @@ function readDocker(endpoint, args, timeoutMs) {
|
|
|
18175
18426
|
const env = { ...process.env };
|
|
18176
18427
|
delete env.DOCKER_CONTEXT;
|
|
18177
18428
|
delete env.DOCKER_HOST;
|
|
18178
|
-
const result = (0,
|
|
18429
|
+
const result = (0, import_node_child_process30.spawnSync)("docker", ["--host", endpoint, ...args], {
|
|
18179
18430
|
env,
|
|
18180
18431
|
encoding: "utf-8",
|
|
18181
18432
|
timeout: timeoutMs,
|
|
@@ -18337,11 +18588,11 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
|
|
|
18337
18588
|
}
|
|
18338
18589
|
return result;
|
|
18339
18590
|
}
|
|
18340
|
-
var
|
|
18591
|
+
var import_node_child_process30, NetworkInventoryError, MAX_IDS, MAX_OUTPUT_BYTES, FULL_ID, NETWORK_TEMPLATE, CONTAINER_TEMPLATE;
|
|
18341
18592
|
var init_network_inventory = __esm({
|
|
18342
18593
|
"src/core/network-inventory.ts"() {
|
|
18343
18594
|
"use strict";
|
|
18344
|
-
|
|
18595
|
+
import_node_child_process30 = require("child_process");
|
|
18345
18596
|
init_devpod_environment();
|
|
18346
18597
|
NetworkInventoryError = class extends Error {
|
|
18347
18598
|
};
|
|
@@ -18669,26 +18920,26 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18669
18920
|
try {
|
|
18670
18921
|
if (!endpoint.startsWith("unix:///")) return false;
|
|
18671
18922
|
const socket = endpoint.slice("unix://".length);
|
|
18672
|
-
const table =
|
|
18923
|
+
const table = import_node_fs38.default.readFileSync(import_node_path45.default.join(procRoot, "net/unix"), "utf8");
|
|
18673
18924
|
if (Buffer.byteLength(table) > 1024 * 1024) return false;
|
|
18674
18925
|
const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
|
|
18675
18926
|
if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
|
|
18676
18927
|
const inode = `socket:[${rows2[0][6]}]`;
|
|
18677
|
-
const ownNamespace =
|
|
18678
|
-
const pids =
|
|
18928
|
+
const ownNamespace = import_node_fs38.default.readlinkSync(import_node_path45.default.join(procRoot, "self/ns/net"));
|
|
18929
|
+
const pids = import_node_fs38.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
|
|
18679
18930
|
if (pids.length > 4096) return false;
|
|
18680
18931
|
for (const pid of pids) {
|
|
18681
18932
|
if (Date.now() > deadline) return false;
|
|
18682
18933
|
try {
|
|
18683
18934
|
const root = import_node_path45.default.join(procRoot, pid);
|
|
18684
|
-
if (import_node_path45.default.basename(
|
|
18685
|
-
if (
|
|
18686
|
-
const descriptors =
|
|
18935
|
+
if (import_node_path45.default.basename(import_node_fs38.default.readlinkSync(import_node_path45.default.join(root, "exe"))) !== "dockerd") continue;
|
|
18936
|
+
if (import_node_fs38.default.readlinkSync(import_node_path45.default.join(root, "ns/net")) !== ownNamespace) continue;
|
|
18937
|
+
const descriptors = import_node_fs38.default.readdirSync(import_node_path45.default.join(root, "fd"));
|
|
18687
18938
|
if (descriptors.length > 4096) continue;
|
|
18688
18939
|
if (descriptors.some((fd) => {
|
|
18689
18940
|
if (Date.now() > deadline) return false;
|
|
18690
18941
|
try {
|
|
18691
|
-
return
|
|
18942
|
+
return import_node_fs38.default.readlinkSync(import_node_path45.default.join(root, "fd", fd)) === inode;
|
|
18692
18943
|
} catch {
|
|
18693
18944
|
return false;
|
|
18694
18945
|
}
|
|
@@ -18702,11 +18953,11 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18702
18953
|
}
|
|
18703
18954
|
return false;
|
|
18704
18955
|
}
|
|
18705
|
-
var
|
|
18956
|
+
var import_node_fs38, import_node_path45;
|
|
18706
18957
|
var init_network_local_daemon = __esm({
|
|
18707
18958
|
"src/core/network-local-daemon.ts"() {
|
|
18708
18959
|
"use strict";
|
|
18709
|
-
|
|
18960
|
+
import_node_fs38 = __toESM(require("fs"));
|
|
18710
18961
|
import_node_path45 = __toESM(require("path"));
|
|
18711
18962
|
}
|
|
18712
18963
|
});
|
|
@@ -18735,7 +18986,7 @@ function parseLinuxNetworkRoutes(output2) {
|
|
|
18735
18986
|
function collectNetworkRoutes(options) {
|
|
18736
18987
|
if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
|
|
18737
18988
|
return { status: "unknown", routes: [] };
|
|
18738
|
-
const result = (0,
|
|
18989
|
+
const result = (0, import_node_child_process31.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
|
|
18739
18990
|
encoding: "utf8",
|
|
18740
18991
|
timeout: 5e3,
|
|
18741
18992
|
maxBuffer: 1024 * 1024
|
|
@@ -18743,11 +18994,11 @@ function collectNetworkRoutes(options) {
|
|
|
18743
18994
|
if (result.error || result.status !== 0) return { status: "unknown", routes: [] };
|
|
18744
18995
|
return parseLinuxNetworkRoutes(result.stdout);
|
|
18745
18996
|
}
|
|
18746
|
-
var
|
|
18997
|
+
var import_node_child_process31, import_node_net3;
|
|
18747
18998
|
var init_network_routes = __esm({
|
|
18748
18999
|
"src/core/network-routes.ts"() {
|
|
18749
19000
|
"use strict";
|
|
18750
|
-
|
|
19001
|
+
import_node_child_process31 = require("child_process");
|
|
18751
19002
|
import_node_net3 = require("net");
|
|
18752
19003
|
init_network_capacity();
|
|
18753
19004
|
init_network_local_daemon();
|
|
@@ -18915,11 +19166,11 @@ function extendDockerComposeFile(nativeConfig, overlayPath) {
|
|
|
18915
19166
|
const config = { ...nativeConfig, dockerComposeFile };
|
|
18916
19167
|
return { status: "ready", config, reasons: [] };
|
|
18917
19168
|
}
|
|
18918
|
-
var
|
|
19169
|
+
var import_node_crypto24;
|
|
18919
19170
|
var init_network_compose = __esm({
|
|
18920
19171
|
"src/core/network-compose.ts"() {
|
|
18921
19172
|
"use strict";
|
|
18922
|
-
|
|
19173
|
+
import_node_crypto24 = require("crypto");
|
|
18923
19174
|
}
|
|
18924
19175
|
});
|
|
18925
19176
|
|
|
@@ -18928,7 +19179,7 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18928
19179
|
const overlay = deriveComposeNetworkOverlay(subnet);
|
|
18929
19180
|
if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
|
|
18930
19181
|
const overlayPath = import_node_path46.default.join(plan.composeDirectory, OVERLAY);
|
|
18931
|
-
const ignored = (0,
|
|
19182
|
+
const ignored = (0, import_node_child_process32.spawnSync)("git", [
|
|
18932
19183
|
"-C",
|
|
18933
19184
|
plan.composeDirectory,
|
|
18934
19185
|
"check-ignore",
|
|
@@ -18942,9 +19193,9 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18942
19193
|
const bytes2 = `${MARKER}
|
|
18943
19194
|
${import_yaml5.default.stringify(overlay.overlay)}`;
|
|
18944
19195
|
const assertOwnership = () => {
|
|
18945
|
-
if (!
|
|
18946
|
-
const stat =
|
|
18947
|
-
if (!stat.isFile() || stat.size > MAX_BYTES3 ||
|
|
19196
|
+
if (!import_node_fs39.default.existsSync(overlayPath)) return;
|
|
19197
|
+
const stat = import_node_fs39.default.lstatSync(overlayPath);
|
|
19198
|
+
if (!stat.isFile() || stat.size > MAX_BYTES3 || import_node_fs39.default.readFileSync(overlayPath, "utf8") !== bytes2)
|
|
18948
19199
|
throw new Error("Retained network overlay changed; repair is required.");
|
|
18949
19200
|
};
|
|
18950
19201
|
assertOwnership();
|
|
@@ -18958,7 +19209,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18958
19209
|
...plan,
|
|
18959
19210
|
contents,
|
|
18960
19211
|
composeFiles: [...plan.composeFiles, overlayPath],
|
|
18961
|
-
effectiveConfigSha256: (0,
|
|
19212
|
+
effectiveConfigSha256: (0, import_node_crypto25.createHash)("sha256").update(contents).digest("hex")
|
|
18962
19213
|
};
|
|
18963
19214
|
return {
|
|
18964
19215
|
plan: result,
|
|
@@ -18968,13 +19219,13 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18968
19219
|
}
|
|
18969
19220
|
};
|
|
18970
19221
|
}
|
|
18971
|
-
var
|
|
19222
|
+
var import_node_child_process32, import_node_crypto25, import_node_fs39, import_node_path46, import_yaml5, OVERLAY, MARKER, MAX_BYTES3;
|
|
18972
19223
|
var init_network_compose_files = __esm({
|
|
18973
19224
|
"src/core/network-compose-files.ts"() {
|
|
18974
19225
|
"use strict";
|
|
18975
|
-
|
|
18976
|
-
|
|
18977
|
-
|
|
19226
|
+
import_node_child_process32 = require("child_process");
|
|
19227
|
+
import_node_crypto25 = require("crypto");
|
|
19228
|
+
import_node_fs39 = __toESM(require("fs"));
|
|
18978
19229
|
import_node_path46 = __toESM(require("path"));
|
|
18979
19230
|
import_yaml5 = __toESM(require("yaml"));
|
|
18980
19231
|
init_atomic_file();
|
|
@@ -18987,11 +19238,11 @@ var init_network_compose_files = __esm({
|
|
|
18987
19238
|
});
|
|
18988
19239
|
|
|
18989
19240
|
// src/core/network-connected-route.ts
|
|
18990
|
-
var
|
|
19241
|
+
var import_node_child_process33;
|
|
18991
19242
|
var init_network_connected_route = __esm({
|
|
18992
19243
|
"src/core/network-connected-route.ts"() {
|
|
18993
19244
|
"use strict";
|
|
18994
|
-
|
|
19245
|
+
import_node_child_process33 = require("child_process");
|
|
18995
19246
|
init_network_capacity();
|
|
18996
19247
|
}
|
|
18997
19248
|
});
|
|
@@ -19007,11 +19258,11 @@ var init_network_lifecycle = __esm({
|
|
|
19007
19258
|
});
|
|
19008
19259
|
|
|
19009
19260
|
// src/core/network-managed.ts
|
|
19010
|
-
var
|
|
19261
|
+
var import_node_crypto26;
|
|
19011
19262
|
var init_network_managed = __esm({
|
|
19012
19263
|
"src/core/network-managed.ts"() {
|
|
19013
19264
|
"use strict";
|
|
19014
|
-
|
|
19265
|
+
import_node_crypto26 = require("crypto");
|
|
19015
19266
|
init_devpod_environment();
|
|
19016
19267
|
init_network_capacity();
|
|
19017
19268
|
init_network_claim_lookup();
|
|
@@ -19081,12 +19332,12 @@ function resolveLinkedTarget(repoPath) {
|
|
|
19081
19332
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
19082
19333
|
};
|
|
19083
19334
|
}
|
|
19084
|
-
var
|
|
19335
|
+
var import_node_child_process34, import_node_fs40, import_node_path47;
|
|
19085
19336
|
var init_workspace_ensure = __esm({
|
|
19086
19337
|
"src/core/workspace-ensure.ts"() {
|
|
19087
19338
|
"use strict";
|
|
19088
|
-
|
|
19089
|
-
|
|
19339
|
+
import_node_child_process34 = require("child_process");
|
|
19340
|
+
import_node_fs40 = __toESM(require("fs"));
|
|
19090
19341
|
import_node_path47 = __toESM(require("path"));
|
|
19091
19342
|
init_devcontainer_profile();
|
|
19092
19343
|
init_devpod_environment();
|
|
@@ -19110,6 +19361,7 @@ var init_workspace_ensure = __esm({
|
|
|
19110
19361
|
init_network_managed();
|
|
19111
19362
|
init_network_recovery();
|
|
19112
19363
|
init_reliability_lifecycle();
|
|
19364
|
+
init_reliability_operation_store();
|
|
19113
19365
|
init_repo_config();
|
|
19114
19366
|
init_route_publication();
|
|
19115
19367
|
init_router();
|
|
@@ -19199,6 +19451,29 @@ function preflightRuntimeVariant(repoPath, options) {
|
|
|
19199
19451
|
}
|
|
19200
19452
|
return variant;
|
|
19201
19453
|
}
|
|
19454
|
+
function preflightAppReplacement(identity2, options) {
|
|
19455
|
+
if (!options.replaceApp) return void 0;
|
|
19456
|
+
if (identity2.provider !== "devsy" || options.repair || options.initializeNew)
|
|
19457
|
+
throw new Error("--replace-app requires managed Devsy without --repair or --initialize-new.");
|
|
19458
|
+
const record6 = readReliabilityOperation(identity2);
|
|
19459
|
+
if (record6?.version !== 1 || record6.enrollment || record6.capacity || capacityPolicyTargets(identity2.repoPath) || record6.state.executionPolicy !== "manual" || record6.worker || record6.state.desired !== "stopped-by-user" || record6.state.phase === "stopping" || !record6.state.stopProof.workloadsStopped || !record6.state.stopProof.routesRemoved || record6.state.operation && !record6.state.operation.drained || findOwnedNetworkClaim(identity2.repoPath) || readAppReplacementAttempt(identity2))
|
|
19460
|
+
throw new Error(
|
|
19461
|
+
"App replacement requires a proved manual canonical stop without an earlier replacement attempt, enrollment or network allocation."
|
|
19462
|
+
);
|
|
19463
|
+
const state = readManagedRuntimeState(identity2.repoPath, identity2.workspace ?? void 0);
|
|
19464
|
+
if (!state || options.profile !== void 0 && options.profile !== state.profile || (options.variant ?? "default") !== (state.variant ?? "default") || listHostRouteState().some((r) => sameWorkspacePath(r.repoPath, identity2.repoPath)))
|
|
19465
|
+
throw new Error(
|
|
19466
|
+
"App replacement requires the retained profile, variant and zero checkout routes."
|
|
19467
|
+
);
|
|
19468
|
+
const proof = withMutationLock(
|
|
19469
|
+
"Prove stopped app replacement",
|
|
19470
|
+
identity2.repoPath,
|
|
19471
|
+
() => captureManagedAppReplacementProof(state)
|
|
19472
|
+
);
|
|
19473
|
+
if (!(0, import_node_util13.isDeepStrictEqual)(readReliabilityOperation(identity2), record6))
|
|
19474
|
+
throw new Error("Stopped replacement generation changed during preflight.");
|
|
19475
|
+
return { stoppedFence: reliabilityFence(record6.state), preflightSha256: proof.digest };
|
|
19476
|
+
}
|
|
19202
19477
|
function prepareManagedLifecycleOperation(input2) {
|
|
19203
19478
|
if (input2.kind === "exec" ? !Array.isArray(input2.command) || input2.command.length === 0 || input2.command.some((arg) => typeof arg !== "string" || arg.includes("\0")) : input2.command !== void 0)
|
|
19204
19479
|
throw new Error("Invalid managed operation command.");
|
|
@@ -19620,6 +19895,9 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19620
19895
|
provider: resolveWorkspaceRuntimeOrDefault(repoPath)
|
|
19621
19896
|
};
|
|
19622
19897
|
const ids2 = newLifecycleIds();
|
|
19898
|
+
if (options.replaceApp && kind !== "ensure")
|
|
19899
|
+
throw new Error("App replacement is an ensure intent.");
|
|
19900
|
+
const replacement = preflightAppReplacement(identity2, options);
|
|
19623
19901
|
const copiedOptions = { ...options };
|
|
19624
19902
|
if (kind === "ensure") assertFreshBootstrapRequest(identity2, options);
|
|
19625
19903
|
const copiedCommand = command ? [...command] : void 0;
|
|
@@ -19745,6 +20023,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19745
20023
|
...ids2,
|
|
19746
20024
|
fence: { ...expectedFence },
|
|
19747
20025
|
options: copiedOptions,
|
|
20026
|
+
...replacement ? { replacement } : {},
|
|
19748
20027
|
...copiedCommand ? { command: copiedCommand } : {},
|
|
19749
20028
|
...retainedExecProof ? { retainedExecProof } : {},
|
|
19750
20029
|
admission: {
|
|
@@ -19905,7 +20184,7 @@ async function superviseThroughController(input2) {
|
|
|
19905
20184
|
try {
|
|
19906
20185
|
const bind = () => observeControllerBinding(directory, {
|
|
19907
20186
|
path: input2.repoPath,
|
|
19908
|
-
session: (0,
|
|
20187
|
+
session: (0, import_node_crypto27.randomUUID)(),
|
|
19909
20188
|
profile: input2.profile ?? "full",
|
|
19910
20189
|
// The protocol requires at least one readiness selector, and every
|
|
19911
20190
|
// supervised operation depends on runtime readiness; "runtime" is the
|
|
@@ -20061,11 +20340,11 @@ function bindLifecycleCapacity(request2, binding, directory = import_node_path48
|
|
|
20061
20340
|
stepRecord(record6, { ...request2.fence, type: "admission", result: "admitted" });
|
|
20062
20341
|
});
|
|
20063
20342
|
}
|
|
20064
|
-
var
|
|
20343
|
+
var import_node_crypto27, import_node_path48, import_node_util13, activeWorker, lockHeld, BUSY_LIFECYCLE_WAIT_MS, BUSY_LIFECYCLE_POLL_MS, CAPACITY_CLIENT_WAIT_MS, BUSY_LIFECYCLE_PROGRESS_MS;
|
|
20065
20344
|
var init_reliability_lifecycle = __esm({
|
|
20066
20345
|
"src/core/reliability-lifecycle.ts"() {
|
|
20067
20346
|
"use strict";
|
|
20068
|
-
|
|
20347
|
+
import_node_crypto27 = require("crypto");
|
|
20069
20348
|
import_node_path48 = __toESM(require("path"));
|
|
20070
20349
|
import_node_util13 = require("util");
|
|
20071
20350
|
init_capacity_accounting();
|
|
@@ -20087,6 +20366,7 @@ var init_reliability_lifecycle = __esm({
|
|
|
20087
20366
|
init_managed_post_start();
|
|
20088
20367
|
init_managed_runtime_state();
|
|
20089
20368
|
init_managed_stop_recovery();
|
|
20369
|
+
init_network_claim_lookup();
|
|
20090
20370
|
init_recovery_budget();
|
|
20091
20371
|
init_reliability_context();
|
|
20092
20372
|
init_reliability_contract();
|
|
@@ -20448,7 +20728,7 @@ var init_capacity_startup_witness = __esm({
|
|
|
20448
20728
|
function readHostWakeEpoch(platform = process.platform) {
|
|
20449
20729
|
if (platform !== "darwin") return void 0;
|
|
20450
20730
|
try {
|
|
20451
|
-
const result = (0,
|
|
20731
|
+
const result = (0, import_node_child_process35.spawnSync)("/usr/sbin/sysctl", ["-n", "kern.wake_abs_time"], {
|
|
20452
20732
|
encoding: "utf8",
|
|
20453
20733
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20454
20734
|
timeout: 250,
|
|
@@ -20463,11 +20743,11 @@ function readHostWakeEpoch(platform = process.platform) {
|
|
|
20463
20743
|
return null;
|
|
20464
20744
|
}
|
|
20465
20745
|
}
|
|
20466
|
-
var
|
|
20746
|
+
var import_node_child_process35;
|
|
20467
20747
|
var init_host_wake = __esm({
|
|
20468
20748
|
"src/core/host-wake.ts"() {
|
|
20469
20749
|
"use strict";
|
|
20470
|
-
|
|
20750
|
+
import_node_child_process35 = require("child_process");
|
|
20471
20751
|
}
|
|
20472
20752
|
});
|
|
20473
20753
|
|
|
@@ -20693,7 +20973,7 @@ function createCapacityController(options) {
|
|
|
20693
20973
|
controller,
|
|
20694
20974
|
policyRevision: policy.revision
|
|
20695
20975
|
});
|
|
20696
|
-
const payloadKey = (0,
|
|
20976
|
+
const payloadKey = (0, import_node_crypto28.randomBytes)(32);
|
|
20697
20977
|
const acceptedPayloads = /* @__PURE__ */ new Map();
|
|
20698
20978
|
const settlePreparations = () => {
|
|
20699
20979
|
if (lifetime.signal.aborted) return;
|
|
@@ -20857,7 +21137,7 @@ function createCapacityController(options) {
|
|
|
20857
21137
|
{
|
|
20858
21138
|
...charge,
|
|
20859
21139
|
operationId: prepared.operationId,
|
|
20860
|
-
reservationId: (0,
|
|
21140
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
20861
21141
|
policyRevision: target.current.revision
|
|
20862
21142
|
},
|
|
20863
21143
|
{
|
|
@@ -20961,7 +21241,7 @@ function createCapacityController(options) {
|
|
|
20961
21241
|
throw error;
|
|
20962
21242
|
}
|
|
20963
21243
|
}
|
|
20964
|
-
const signature = (0,
|
|
21244
|
+
const signature = (0, import_node_crypto28.createHmac)("sha256", payloadKey).update(
|
|
20965
21245
|
JSON.stringify({
|
|
20966
21246
|
repoPath: identity2.repoPath,
|
|
20967
21247
|
profile: environment.profile,
|
|
@@ -20982,7 +21262,7 @@ function createCapacityController(options) {
|
|
|
20982
21262
|
{
|
|
20983
21263
|
...charge,
|
|
20984
21264
|
operationId: prepared.operationId,
|
|
20985
|
-
reservationId: (0,
|
|
21265
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
20986
21266
|
policyRevision: current.revision
|
|
20987
21267
|
},
|
|
20988
21268
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -21117,7 +21397,7 @@ function createCapacityController(options) {
|
|
|
21117
21397
|
// the budget module then falls back to the conservative wall duration.
|
|
21118
21398
|
activeElapsedMs: null,
|
|
21119
21399
|
profile: environment.profile,
|
|
21120
|
-
incidentId: `incident-${(0,
|
|
21400
|
+
incidentId: `incident-${(0, import_node_crypto28.randomUUID)()}`
|
|
21121
21401
|
});
|
|
21122
21402
|
} catch {
|
|
21123
21403
|
return;
|
|
@@ -21135,7 +21415,7 @@ function createCapacityController(options) {
|
|
|
21135
21415
|
{
|
|
21136
21416
|
...charge,
|
|
21137
21417
|
operationId: prepared.operationId,
|
|
21138
|
-
reservationId: (0,
|
|
21418
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
21139
21419
|
policyRevision: current.revision
|
|
21140
21420
|
},
|
|
21141
21421
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -21155,11 +21435,11 @@ function createCapacityController(options) {
|
|
|
21155
21435
|
}
|
|
21156
21436
|
};
|
|
21157
21437
|
}
|
|
21158
|
-
var
|
|
21438
|
+
var import_node_crypto28, import_node_path49, import_node_util15;
|
|
21159
21439
|
var init_capacity_controller = __esm({
|
|
21160
21440
|
"src/core/capacity-controller.ts"() {
|
|
21161
21441
|
"use strict";
|
|
21162
|
-
|
|
21442
|
+
import_node_crypto28 = require("crypto");
|
|
21163
21443
|
import_node_path49 = __toESM(require("path"));
|
|
21164
21444
|
import_node_util15 = require("util");
|
|
21165
21445
|
init_capacity_accounting();
|
|
@@ -21257,7 +21537,7 @@ printf '%s %s %s\n' "$pid" "$birth" "$fingerprint"
|
|
|
21257
21537
|
|
|
21258
21538
|
// src/core/controller-observation.ts
|
|
21259
21539
|
function digest2(value) {
|
|
21260
|
-
return (0,
|
|
21540
|
+
return (0, import_node_crypto29.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
21261
21541
|
}
|
|
21262
21542
|
function readRoutes() {
|
|
21263
21543
|
return readHostRouteStateReadOnly((file) => readControllerEvidence(file, 1048576));
|
|
@@ -21341,7 +21621,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21341
21621
|
() => persisted.contents[3]
|
|
21342
21622
|
);
|
|
21343
21623
|
const source = parseDevcontainerConfig(persisted.contents[4], sourcePath);
|
|
21344
|
-
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0,
|
|
21624
|
+
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0, import_node_crypto29.createHash)("sha256").update(persisted.contents[4]).digest("hex") !== state.sourceConfigSha256 || (0, import_node_crypto29.createHash)("sha256").update(persisted.contents[5]).digest("hex") !== state.effectiveConfigSha256)
|
|
21345
21625
|
throw new ControllerObservationBindingChanged("Observation retained configuration changed.");
|
|
21346
21626
|
const identity2 = {
|
|
21347
21627
|
repoPath: environment.repoPath,
|
|
@@ -21516,11 +21796,11 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21516
21796
|
};
|
|
21517
21797
|
};
|
|
21518
21798
|
}
|
|
21519
|
-
var
|
|
21799
|
+
var import_node_crypto29, import_node_path50, OBSERVATION_INSPECT_TEMPLATE;
|
|
21520
21800
|
var init_controller_observation = __esm({
|
|
21521
21801
|
"src/core/controller-observation.ts"() {
|
|
21522
21802
|
"use strict";
|
|
21523
|
-
|
|
21803
|
+
import_node_crypto29 = require("crypto");
|
|
21524
21804
|
import_node_path50 = __toESM(require("path"));
|
|
21525
21805
|
init_controller_binding();
|
|
21526
21806
|
init_controller_monitor();
|
|
@@ -21545,11 +21825,11 @@ var init_controller_observation = __esm({
|
|
|
21545
21825
|
});
|
|
21546
21826
|
|
|
21547
21827
|
// src/core/controller-sessions.ts
|
|
21548
|
-
var
|
|
21828
|
+
var import_node_crypto30, import_node_util16, ControllerSessions;
|
|
21549
21829
|
var init_controller_sessions = __esm({
|
|
21550
21830
|
"src/core/controller-sessions.ts"() {
|
|
21551
21831
|
"use strict";
|
|
21552
|
-
|
|
21832
|
+
import_node_crypto30 = require("crypto");
|
|
21553
21833
|
import_node_util16 = require("util");
|
|
21554
21834
|
ControllerSessions = class {
|
|
21555
21835
|
constructor(store, readWakeEpoch = () => void 0) {
|
|
@@ -21743,7 +22023,7 @@ var init_controller_sessions = __esm({
|
|
|
21743
22023
|
const session = {
|
|
21744
22024
|
id: id5,
|
|
21745
22025
|
environmentId: environment.id,
|
|
21746
|
-
generation: (0,
|
|
22026
|
+
generation: (0, import_node_crypto30.randomUUID)(),
|
|
21747
22027
|
requirements: required,
|
|
21748
22028
|
renewedAtMs: wall,
|
|
21749
22029
|
parkingConsent: "protected",
|
|
@@ -21771,7 +22051,7 @@ var init_controller_sessions = __esm({
|
|
|
21771
22051
|
const session = {
|
|
21772
22052
|
id: previous.session,
|
|
21773
22053
|
environmentId: environment.id,
|
|
21774
|
-
generation: (0,
|
|
22054
|
+
generation: (0, import_node_crypto30.randomUUID)(),
|
|
21775
22055
|
requirements: required,
|
|
21776
22056
|
renewedAtMs: wall,
|
|
21777
22057
|
parkingConsent: "protected",
|
|
@@ -21936,21 +22216,21 @@ function privateDirectory2(directory) {
|
|
|
21936
22216
|
for (const part of absolute2.slice(current.length).split(import_node_path51.default.sep)) {
|
|
21937
22217
|
current = import_node_path51.default.join(current, part);
|
|
21938
22218
|
try {
|
|
21939
|
-
const stat2 =
|
|
22219
|
+
const stat2 = import_node_fs41.default.lstatSync(current);
|
|
21940
22220
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
21941
22221
|
throw new Error("Unsafe controller directory.");
|
|
21942
22222
|
} catch (error) {
|
|
21943
22223
|
if (error.code !== "ENOENT") throw error;
|
|
21944
|
-
|
|
22224
|
+
import_node_fs41.default.mkdirSync(current, { mode: 448 });
|
|
21945
22225
|
}
|
|
21946
22226
|
}
|
|
21947
|
-
const stat =
|
|
22227
|
+
const stat = import_node_fs41.default.lstatSync(absolute2);
|
|
21948
22228
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
21949
22229
|
throw new Error("Controller directory is not private.");
|
|
21950
22230
|
}
|
|
21951
22231
|
function validateOwnedFile(file, socket) {
|
|
21952
22232
|
try {
|
|
21953
|
-
const stat =
|
|
22233
|
+
const stat = import_node_fs41.default.lstatSync(file);
|
|
21954
22234
|
if (stat.uid !== process.getuid?.() || (socket ? !stat.isSocket() : !stat.isFile()) || (stat.mode & 63) !== 0)
|
|
21955
22235
|
throw new Error("Unsafe controller artifact.");
|
|
21956
22236
|
return true;
|
|
@@ -21975,7 +22255,7 @@ async function runController(options) {
|
|
|
21975
22255
|
privateDirectory2(options.directory);
|
|
21976
22256
|
const lockPath = import_node_path51.default.join(options.directory, "owner.lock");
|
|
21977
22257
|
try {
|
|
21978
|
-
const stat =
|
|
22258
|
+
const stat = import_node_fs41.default.lstatSync(lockPath);
|
|
21979
22259
|
if (!stat.isFile() || stat.uid !== process.getuid?.())
|
|
21980
22260
|
throw new Error("Unsafe controller owner lock.");
|
|
21981
22261
|
} catch (error) {
|
|
@@ -21986,7 +22266,7 @@ async function runController(options) {
|
|
|
21986
22266
|
await withFileLock(lockPath, { activity: "controller ownership", waitMs: 0 }, async () => {
|
|
21987
22267
|
const staleSocket = validateOwnedFile(socketPath, true);
|
|
21988
22268
|
const sessions = new ControllerSessions(store, options.wakeEpoch ?? readHostWakeEpoch);
|
|
21989
|
-
if (staleSocket)
|
|
22269
|
+
if (staleSocket) import_node_fs41.default.unlinkSync(socketPath);
|
|
21990
22270
|
const incarnation = sessions.read();
|
|
21991
22271
|
const { resolve, collect } = options.createBindings?.(store.bindingFingerprint()) ?? {
|
|
21992
22272
|
resolve: options.resolve,
|
|
@@ -22532,7 +22812,7 @@ async function runController(options) {
|
|
|
22532
22812
|
resolve2();
|
|
22533
22813
|
});
|
|
22534
22814
|
});
|
|
22535
|
-
|
|
22815
|
+
import_node_fs41.default.chmodSync(socketPath, 384);
|
|
22536
22816
|
await new Promise((resolve2) => {
|
|
22537
22817
|
finish = resolve2;
|
|
22538
22818
|
options.signal.addEventListener("abort", shutdown, { once: true });
|
|
@@ -22551,11 +22831,11 @@ async function runController(options) {
|
|
|
22551
22831
|
}
|
|
22552
22832
|
});
|
|
22553
22833
|
}
|
|
22554
|
-
var
|
|
22834
|
+
var import_node_fs41, import_node_net4, import_node_path51, FRAME_BYTES;
|
|
22555
22835
|
var init_controller_server = __esm({
|
|
22556
22836
|
"src/core/controller-server.ts"() {
|
|
22557
22837
|
"use strict";
|
|
22558
|
-
|
|
22838
|
+
import_node_fs41 = __toESM(require("fs"));
|
|
22559
22839
|
import_node_net4 = __toESM(require("net"));
|
|
22560
22840
|
import_node_path51 = __toESM(require("path"));
|
|
22561
22841
|
init_controller_monitor();
|
|
@@ -22842,27 +23122,27 @@ function replaceDevrouterSection(content) {
|
|
|
22842
23122
|
}
|
|
22843
23123
|
function writeRepoFile(repoPath, relPath, content) {
|
|
22844
23124
|
const absolutePath = (0, import_node_path54.join)(repoPath, relPath);
|
|
22845
|
-
(0,
|
|
22846
|
-
(0,
|
|
23125
|
+
(0, import_node_fs42.mkdirSync)((0, import_node_path54.dirname)(absolutePath), { recursive: true });
|
|
23126
|
+
(0, import_node_fs42.writeFileSync)(absolutePath, content, "utf-8");
|
|
22847
23127
|
return absolutePath;
|
|
22848
23128
|
}
|
|
22849
23129
|
function ensureAgentsMdSection(repoPath) {
|
|
22850
23130
|
const filePath = (0, import_node_path54.join)(repoPath, AGENTS_MD);
|
|
22851
|
-
if ((0,
|
|
22852
|
-
const content = (0,
|
|
23131
|
+
if ((0, import_node_fs42.existsSync)(filePath)) {
|
|
23132
|
+
const content = (0, import_node_fs42.readFileSync)(filePath, "utf-8");
|
|
22853
23133
|
if (content.includes(DEVROUTER_SENTINEL)) {
|
|
22854
23134
|
const updated = replaceDevrouterSection(content);
|
|
22855
23135
|
if (updated === void 0 || updated === content) return { path: filePath, written: false };
|
|
22856
|
-
(0,
|
|
23136
|
+
(0, import_node_fs42.writeFileSync)(filePath, updated, "utf-8");
|
|
22857
23137
|
return { path: filePath, written: true };
|
|
22858
23138
|
}
|
|
22859
|
-
(0,
|
|
23139
|
+
(0, import_node_fs42.writeFileSync)(filePath, `${content.trimEnd()}
|
|
22860
23140
|
|
|
22861
23141
|
${buildDevrouterSection()}
|
|
22862
23142
|
`, "utf-8");
|
|
22863
23143
|
return { path: filePath, written: true };
|
|
22864
23144
|
}
|
|
22865
|
-
(0,
|
|
23145
|
+
(0, import_node_fs42.writeFileSync)(filePath, `# AGENTS.md
|
|
22866
23146
|
|
|
22867
23147
|
${buildDevrouterSection()}
|
|
22868
23148
|
`, "utf-8");
|
|
@@ -22872,11 +23152,11 @@ function ensureSkillFile(repoPath) {
|
|
|
22872
23152
|
const filePath = writeRepoFile(repoPath, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT);
|
|
22873
23153
|
return { path: filePath, written: true };
|
|
22874
23154
|
}
|
|
22875
|
-
var
|
|
23155
|
+
var import_node_fs42, import_node_path54, DEVROUTER_SENTINEL, DEVROUTER_END_SENTINEL, LEGACY_DEVROUTER_SECTION_END, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
|
|
22876
23156
|
var init_agents_md = __esm({
|
|
22877
23157
|
"src/core/agents-md.ts"() {
|
|
22878
23158
|
"use strict";
|
|
22879
|
-
|
|
23159
|
+
import_node_fs42 = require("fs");
|
|
22880
23160
|
import_node_path54 = require("path");
|
|
22881
23161
|
DEVROUTER_SENTINEL = "<!-- devrouter -->";
|
|
22882
23162
|
DEVROUTER_END_SENTINEL = "<!-- /devrouter -->";
|
|
@@ -23499,6 +23779,8 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
23499
23779
|
"- Managed process reuse fingerprints command argv, workspace identity, and the exact adapter snapshot. Variant and current host-port identity always compose with an explicit --fingerprint. 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.",
|
|
23500
23780
|
"- 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.",
|
|
23501
23781
|
"- 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.",
|
|
23782
|
+
"- Explicit retained replacement: after canonical stop, ensure <checkout> --replace-app replaces only the proved primary writable layer. It requires manual Devsy 1.24.0, committed unchanged managed source, qualified preserving hooks, a retained dependency and named storage. Anonymous mounts, namespace consumers, allocated networks and capacity enrollment refuse. One durable attempt survives cancellation, stop and rollover; never clear it or retry through a raw provider. Proved stop/stop --repair retains data. This does not apply changed Compose overlays.",
|
|
23783
|
+
"- Lifecycle journal compatibility: older CLIs refuse records written by a newer release, including stop and global enumeration. Never edit a writer stamp or durable receipt to bypass refusal.",
|
|
23502
23784
|
"- Explicit first initialization: managedRuntime.devcontainer.freshBootstrap declares literal command argv, dataVolumes and optional sharedCaches keys. ensure <new-checkout> --initialize-new requires qualified Devsy 1.19.0 or 1.24.0, new local data volumes and repository-owned database identity/emptiness checks. A durable attempt prevents replay after failure, unknown completion, cancellation, stop, replacement or settlement. Ordinary hooks must preserve data. Consult docs/DEVCONTAINER.md for context and mount prerequisites; never clear the attempt fence or infer reset authority.",
|
|
23503
23785
|
"- Managed Devsy startup on supported local Unix Docker endpoints captures exact stop ownership before application readiness. With that baseline, canonical stop tolerates changed or missing repository configuration and preserves containers and volumes. Older records without a baseline retain configuration-dependent stop; installing a new CLI does not establish historical ownership. Invalid or changed ownership never falls back. Do not replay destructive bootstrap hooks to obtain a baseline.",
|
|
23504
23786
|
"- 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.",
|
|
@@ -23669,7 +23951,7 @@ var init_ai_prompt = __esm({
|
|
|
23669
23951
|
purpose: "Write/update devrouter section in the repo's AGENTS.md and install the devrouter skill."
|
|
23670
23952
|
},
|
|
23671
23953
|
{
|
|
23672
|
-
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair | --initialize-new] [--open] [--json]",
|
|
23954
|
+
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair | --initialize-new | --replace-app] [--open] [--json]",
|
|
23673
23955
|
purpose: "Canonical startup and proof for an exact primary or linked checkout; atomically publishes routes after readiness."
|
|
23674
23956
|
},
|
|
23675
23957
|
{
|
|
@@ -24387,11 +24669,11 @@ function extractCurrentVersionFromRepoConfig(repoPath) {
|
|
|
24387
24669
|
};
|
|
24388
24670
|
}
|
|
24389
24671
|
function readPromptDirectory(promptDirPath) {
|
|
24390
|
-
if (!
|
|
24672
|
+
if (!import_node_fs43.default.existsSync(promptDirPath)) {
|
|
24391
24673
|
throw new Error(`Missing ${UPGRADE_PROMPTS_DIR} directory at ${promptDirPath}.`);
|
|
24392
24674
|
}
|
|
24393
24675
|
const releases = [];
|
|
24394
|
-
const files =
|
|
24676
|
+
const files = import_node_fs43.default.readdirSync(promptDirPath, { withFileTypes: true });
|
|
24395
24677
|
for (const file of files) {
|
|
24396
24678
|
if (!file.isFile() || !file.name.endsWith(".md")) {
|
|
24397
24679
|
continue;
|
|
@@ -24402,7 +24684,7 @@ function readPromptDirectory(promptDirPath) {
|
|
|
24402
24684
|
}
|
|
24403
24685
|
const version = normalizeVersion(basename);
|
|
24404
24686
|
const promptPath = import_node_path55.default.join(promptDirPath, file.name);
|
|
24405
|
-
const prompt =
|
|
24687
|
+
const prompt = import_node_fs43.default.readFileSync(promptPath, "utf-8").trim();
|
|
24406
24688
|
releases.push({ version, prompt, promptPath });
|
|
24407
24689
|
}
|
|
24408
24690
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -24427,7 +24709,7 @@ function resolvePromptDirectory(explicitPath) {
|
|
|
24427
24709
|
}
|
|
24428
24710
|
const entryFile = process.argv[1] ? import_node_path55.default.resolve(process.argv[1]) : __filename;
|
|
24429
24711
|
const entryDir = import_node_path55.default.dirname(entryFile);
|
|
24430
|
-
const resolvedEntryDir =
|
|
24712
|
+
const resolvedEntryDir = import_node_fs43.default.existsSync(entryFile) ? import_node_path55.default.dirname(import_node_fs43.default.realpathSync(entryFile)) : entryDir;
|
|
24431
24713
|
const candidates = [
|
|
24432
24714
|
import_node_path55.default.resolve(resolvedEntryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24433
24715
|
import_node_path55.default.resolve(entryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
@@ -24435,7 +24717,7 @@ function resolvePromptDirectory(explicitPath) {
|
|
|
24435
24717
|
import_node_path55.default.resolve(__dirname, "..", "..", UPGRADE_PROMPTS_DIR),
|
|
24436
24718
|
import_node_path55.default.resolve(process.cwd(), UPGRADE_PROMPTS_DIR)
|
|
24437
24719
|
];
|
|
24438
|
-
const existing = candidates.find((candidate) =>
|
|
24720
|
+
const existing = candidates.find((candidate) => import_node_fs43.default.existsSync(candidate));
|
|
24439
24721
|
return existing ?? candidates[0];
|
|
24440
24722
|
}
|
|
24441
24723
|
function loadUpgradeCatalog(options = {}) {
|
|
@@ -24451,11 +24733,11 @@ function loadUpgradeCatalog(options = {}) {
|
|
|
24451
24733
|
releases
|
|
24452
24734
|
};
|
|
24453
24735
|
}
|
|
24454
|
-
var
|
|
24736
|
+
var import_node_fs43, import_node_path55, SEMVER_RE, UPGRADE_PROMPTS_DIR;
|
|
24455
24737
|
var init_upgrade = __esm({
|
|
24456
24738
|
"src/core/upgrade.ts"() {
|
|
24457
24739
|
"use strict";
|
|
24458
|
-
|
|
24740
|
+
import_node_fs43 = __toESM(require("fs"));
|
|
24459
24741
|
import_node_path55 = __toESM(require("path"));
|
|
24460
24742
|
init_repo_config();
|
|
24461
24743
|
SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)$/;
|
|
@@ -24609,7 +24891,7 @@ function isLoopbackHost(host) {
|
|
|
24609
24891
|
return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
|
|
24610
24892
|
}
|
|
24611
24893
|
function inspectCompose(composeFile, _workspace) {
|
|
24612
|
-
if (!
|
|
24894
|
+
if (!import_node_fs44.default.existsSync(composeFile)) {
|
|
24613
24895
|
return {
|
|
24614
24896
|
aliases: [],
|
|
24615
24897
|
publishedPorts: [],
|
|
@@ -24618,7 +24900,7 @@ function inspectCompose(composeFile, _workspace) {
|
|
|
24618
24900
|
};
|
|
24619
24901
|
}
|
|
24620
24902
|
try {
|
|
24621
|
-
const raw =
|
|
24903
|
+
const raw = import_node_fs44.default.readFileSync(composeFile, "utf-8");
|
|
24622
24904
|
const parsed = import_yaml6.default.parse(raw);
|
|
24623
24905
|
const root = asRecord(parsed);
|
|
24624
24906
|
const services = asRecord(root?.services);
|
|
@@ -24716,7 +24998,7 @@ function buildHostPortClaimsCheck(repoPath, workspace) {
|
|
|
24716
24998
|
}
|
|
24717
24999
|
function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
24718
25000
|
const devcontainerDir = import_node_path56.default.join(repoPath, ".devcontainer");
|
|
24719
|
-
if (!
|
|
25001
|
+
if (!import_node_fs44.default.existsSync(devcontainerDir)) {
|
|
24720
25002
|
return [];
|
|
24721
25003
|
}
|
|
24722
25004
|
const compose = inspectCompose(import_node_path56.default.join(devcontainerDir, "docker-compose.yml"), workspace);
|
|
@@ -24747,8 +25029,8 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24747
25029
|
suggestion: compose.parseError || compose.publishedPorts.length > 0 ? "Remove published ports and route services through devnet aliases with devrouter proxy apps." : void 0
|
|
24748
25030
|
});
|
|
24749
25031
|
const dockerfilePath = import_node_path56.default.join(devcontainerDir, "Dockerfile");
|
|
24750
|
-
const dockerfileExists =
|
|
24751
|
-
const dockerfile = dockerfileExists ?
|
|
25032
|
+
const dockerfileExists = import_node_fs44.default.existsSync(dockerfilePath);
|
|
25033
|
+
const dockerfile = dockerfileExists ? import_node_fs44.default.readFileSync(dockerfilePath, "utf-8") : "";
|
|
24752
25034
|
const devrouterArtifacts = ["@devrouter/cli", "devrouter-process"].filter(
|
|
24753
25035
|
(artifact) => dockerfile.includes(artifact)
|
|
24754
25036
|
);
|
|
@@ -24806,11 +25088,11 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24806
25088
|
});
|
|
24807
25089
|
return checks;
|
|
24808
25090
|
}
|
|
24809
|
-
var
|
|
25091
|
+
var import_node_fs44, import_node_path56, import_yaml6;
|
|
24810
25092
|
var init_devcontainer_diagnostics = __esm({
|
|
24811
25093
|
"src/core/devcontainer-diagnostics.ts"() {
|
|
24812
25094
|
"use strict";
|
|
24813
|
-
|
|
25095
|
+
import_node_fs44 = __toESM(require("fs"));
|
|
24814
25096
|
import_node_path56 = __toESM(require("path"));
|
|
24815
25097
|
import_yaml6 = __toESM(require("yaml"));
|
|
24816
25098
|
init_devcontainer_profile();
|
|
@@ -24907,11 +25189,11 @@ function reconcileRouteRunConflict(repoPath, app) {
|
|
|
24907
25189
|
}
|
|
24908
25190
|
}
|
|
24909
25191
|
}
|
|
24910
|
-
var
|
|
25192
|
+
var import_node_fs45;
|
|
24911
25193
|
var init_route_state = __esm({
|
|
24912
25194
|
"src/core/route-state.ts"() {
|
|
24913
25195
|
"use strict";
|
|
24914
|
-
|
|
25196
|
+
import_node_fs45 = __toESM(require("fs"));
|
|
24915
25197
|
init_host_routes();
|
|
24916
25198
|
init_workspace();
|
|
24917
25199
|
}
|
|
@@ -25086,7 +25368,7 @@ function toRepoStatus(repoPath) {
|
|
|
25086
25368
|
const resolvedRepoPath = resolveRepoPath(repoPath);
|
|
25087
25369
|
const configPath = getRepoConfigPath(resolvedRepoPath);
|
|
25088
25370
|
const explicitRepo = typeof repoPath === "string" && repoPath.trim().length > 0;
|
|
25089
|
-
const configExists =
|
|
25371
|
+
const configExists = import_node_fs46.default.existsSync(configPath);
|
|
25090
25372
|
if (!explicitRepo && !configExists) {
|
|
25091
25373
|
return void 0;
|
|
25092
25374
|
}
|
|
@@ -25204,13 +25486,18 @@ async function collectRouterStatus(repoPath) {
|
|
|
25204
25486
|
nextSteps.push(`Run: dev repo init --repo ${repo.path}`);
|
|
25205
25487
|
} else if (repo && !repo.valid) {
|
|
25206
25488
|
nextSteps.push("Fix .devrouter.yml validation errors and re-run `dev doctor --repo <path>`");
|
|
25207
|
-
} else if (repo?.valid && repo.appCount === 0) {
|
|
25489
|
+
} else if (repo?.valid && repo.managedRuntime?.mode !== "managed" && repo.appCount === 0) {
|
|
25208
25490
|
nextSteps.push(
|
|
25209
25491
|
`Run: dev app add --name <name> --host <name>.localhost --protocol http --runtime host --repo ${repo.path}`
|
|
25210
25492
|
);
|
|
25211
25493
|
} else if (repo?.valid) {
|
|
25212
|
-
|
|
25213
|
-
|
|
25494
|
+
if (repo.managedRuntime?.mode === "managed") {
|
|
25495
|
+
const repoArgument = `'${repo.path.replaceAll("'", `'\\''`)}'`;
|
|
25496
|
+
nextSteps.push(`Run: devrouter ensure ${repoArgument}`);
|
|
25497
|
+
} else {
|
|
25498
|
+
nextSteps.push(`Run: dev app ls --repo ${repo.path}`);
|
|
25499
|
+
nextSteps.push("Run: dev app run <name> --repo <path> --yes");
|
|
25500
|
+
}
|
|
25214
25501
|
nextSteps.push("Run: dev ls");
|
|
25215
25502
|
if (repo.managedRuntime?.mountNesting?.status === "unwound") {
|
|
25216
25503
|
nextSteps.push(
|
|
@@ -25239,11 +25526,11 @@ async function collectRouterStatus(repoPath) {
|
|
|
25239
25526
|
}
|
|
25240
25527
|
};
|
|
25241
25528
|
}
|
|
25242
|
-
var
|
|
25529
|
+
var import_node_fs46;
|
|
25243
25530
|
var init_status = __esm({
|
|
25244
25531
|
"src/core/status.ts"() {
|
|
25245
25532
|
"use strict";
|
|
25246
|
-
|
|
25533
|
+
import_node_fs46 = __toESM(require("fs"));
|
|
25247
25534
|
init_docker();
|
|
25248
25535
|
init_managed_runtime_state();
|
|
25249
25536
|
init_managed_runtime_status();
|
|
@@ -25305,14 +25592,14 @@ ${env}
|
|
|
25305
25592
|
function readInstalledIdleFor(plistPath) {
|
|
25306
25593
|
let contents;
|
|
25307
25594
|
try {
|
|
25308
|
-
contents =
|
|
25595
|
+
contents = import_node_fs47.default.readFileSync(plistPath, "utf-8");
|
|
25309
25596
|
} catch {
|
|
25310
25597
|
return void 0;
|
|
25311
25598
|
}
|
|
25312
25599
|
return /<string>--idle-for<\/string>\s*<string>([^<]+)<\/string>/.exec(contents)?.[1] ?? "unknown";
|
|
25313
25600
|
}
|
|
25314
25601
|
function locateTool(name) {
|
|
25315
|
-
const result = (0,
|
|
25602
|
+
const result = (0, import_node_child_process36.spawnSync)("/bin/sh", ["-c", `command -v ${name}`], { encoding: "utf-8" });
|
|
25316
25603
|
const found = result.status === 0 ? result.stdout.trim() : "";
|
|
25317
25604
|
return found.startsWith("/") ? found : void 0;
|
|
25318
25605
|
}
|
|
@@ -25338,9 +25625,9 @@ function installIdleSweep(input2) {
|
|
|
25338
25625
|
throw new Error("The idle sweep uses launchd and is only available on macOS.");
|
|
25339
25626
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25340
25627
|
const launchctl = input2.launchctl ?? defaultLaunchctl;
|
|
25341
|
-
const entryPath = input2.entryPath ??
|
|
25342
|
-
|
|
25343
|
-
|
|
25628
|
+
const entryPath = input2.entryPath ?? import_node_fs47.default.realpathSync(process.argv[1]);
|
|
25629
|
+
import_node_fs47.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25630
|
+
import_node_fs47.default.mkdirSync(import_node_path57.default.dirname(paths.plist), { recursive: true });
|
|
25344
25631
|
const contents = renderIdleSweepPlist({
|
|
25345
25632
|
nodePath: process.execPath,
|
|
25346
25633
|
entryPath,
|
|
@@ -25349,7 +25636,7 @@ function installIdleSweep(input2) {
|
|
|
25349
25636
|
logPath: paths.log
|
|
25350
25637
|
});
|
|
25351
25638
|
launchctl(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25352
|
-
|
|
25639
|
+
import_node_fs47.default.writeFileSync(paths.plist, contents, { mode: 420 });
|
|
25353
25640
|
const loaded = launchctl(["bootstrap", launchDomain(), paths.plist]);
|
|
25354
25641
|
if (loaded.status !== 0)
|
|
25355
25642
|
throw new Error(
|
|
@@ -25359,9 +25646,9 @@ function installIdleSweep(input2) {
|
|
|
25359
25646
|
}
|
|
25360
25647
|
function removeIdleSweep(input2 = {}) {
|
|
25361
25648
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25362
|
-
if (!
|
|
25649
|
+
if (!import_node_fs47.default.existsSync(paths.plist)) return false;
|
|
25363
25650
|
(input2.launchctl ?? defaultLaunchctl)(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25364
|
-
|
|
25651
|
+
import_node_fs47.default.rmSync(paths.plist, { force: true });
|
|
25365
25652
|
return true;
|
|
25366
25653
|
}
|
|
25367
25654
|
function summarizeSweep(idleFor, stops, error) {
|
|
@@ -25376,13 +25663,13 @@ function summarizeSweep(idleFor, stops, error) {
|
|
|
25376
25663
|
};
|
|
25377
25664
|
}
|
|
25378
25665
|
function writeLastSweep(record6, paths = idleSweepPaths()) {
|
|
25379
|
-
|
|
25380
|
-
|
|
25666
|
+
import_node_fs47.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25667
|
+
import_node_fs47.default.writeFileSync(paths.lastSweep, `${JSON.stringify(record6, null, 2)}
|
|
25381
25668
|
`, { mode: 384 });
|
|
25382
25669
|
}
|
|
25383
25670
|
function readLastSweep(paths) {
|
|
25384
25671
|
try {
|
|
25385
|
-
return JSON.parse(
|
|
25672
|
+
return JSON.parse(import_node_fs47.default.readFileSync(paths.lastSweep, "utf-8"));
|
|
25386
25673
|
} catch {
|
|
25387
25674
|
return void 0;
|
|
25388
25675
|
}
|
|
@@ -25427,12 +25714,12 @@ function idleSweepCheck(paths = idleSweepPaths(), nowMs = Date.now()) {
|
|
|
25427
25714
|
...stale || last.failed > 0 ? { suggestion: `Inspect: ${paths.log}` } : {}
|
|
25428
25715
|
};
|
|
25429
25716
|
}
|
|
25430
|
-
var
|
|
25717
|
+
var import_node_child_process36, import_node_fs47, import_node_os7, import_node_path57, IDLE_SWEEP_LABEL, SWEEP_INTERVAL_SECONDS, SYSTEM_PATH, defaultLaunchctl;
|
|
25431
25718
|
var init_idle_sweep = __esm({
|
|
25432
25719
|
"src/core/idle-sweep.ts"() {
|
|
25433
25720
|
"use strict";
|
|
25434
|
-
|
|
25435
|
-
|
|
25721
|
+
import_node_child_process36 = require("child_process");
|
|
25722
|
+
import_node_fs47 = __toESM(require("fs"));
|
|
25436
25723
|
import_node_os7 = __toESM(require("os"));
|
|
25437
25724
|
import_node_path57 = __toESM(require("path"));
|
|
25438
25725
|
init_router();
|
|
@@ -25440,7 +25727,7 @@ var init_idle_sweep = __esm({
|
|
|
25440
25727
|
SWEEP_INTERVAL_SECONDS = 300;
|
|
25441
25728
|
SYSTEM_PATH = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
25442
25729
|
defaultLaunchctl = (args) => {
|
|
25443
|
-
const result = (0,
|
|
25730
|
+
const result = (0, import_node_child_process36.spawnSync)("launchctl", args, { encoding: "utf-8" });
|
|
25444
25731
|
return { status: result.status, stderr: result.stderr || result.error?.message || "" };
|
|
25445
25732
|
};
|
|
25446
25733
|
}
|
|
@@ -25454,7 +25741,7 @@ function outputFromResult(result) {
|
|
|
25454
25741
|
return output2.length > 0 ? output2 : void 0;
|
|
25455
25742
|
}
|
|
25456
25743
|
function runTool(command, args = []) {
|
|
25457
|
-
const result = (0,
|
|
25744
|
+
const result = (0, import_node_child_process37.spawnSync)(command, args, {
|
|
25458
25745
|
encoding: "utf-8"
|
|
25459
25746
|
});
|
|
25460
25747
|
if (result.error) {
|
|
@@ -25512,11 +25799,11 @@ function parseMinimumNodeMajor(value) {
|
|
|
25512
25799
|
}
|
|
25513
25800
|
function readPackageJson(repoPath) {
|
|
25514
25801
|
const packagePath = import_node_path58.default.join(repoPath, "package.json");
|
|
25515
|
-
if (!
|
|
25802
|
+
if (!import_node_fs48.default.existsSync(packagePath)) {
|
|
25516
25803
|
return void 0;
|
|
25517
25804
|
}
|
|
25518
25805
|
try {
|
|
25519
|
-
return JSON.parse(
|
|
25806
|
+
return JSON.parse(import_node_fs48.default.readFileSync(packagePath, "utf-8"));
|
|
25520
25807
|
} catch {
|
|
25521
25808
|
return void 0;
|
|
25522
25809
|
}
|
|
@@ -25621,17 +25908,17 @@ function realpathOrUndefined(value) {
|
|
|
25621
25908
|
return void 0;
|
|
25622
25909
|
}
|
|
25623
25910
|
try {
|
|
25624
|
-
return
|
|
25911
|
+
return import_node_fs48.default.realpathSync(value);
|
|
25625
25912
|
} catch {
|
|
25626
25913
|
return void 0;
|
|
25627
25914
|
}
|
|
25628
25915
|
}
|
|
25629
25916
|
function isExecutableFile(filePath) {
|
|
25630
25917
|
try {
|
|
25631
|
-
if (!
|
|
25918
|
+
if (!import_node_fs48.default.statSync(filePath).isFile()) {
|
|
25632
25919
|
return false;
|
|
25633
25920
|
}
|
|
25634
|
-
|
|
25921
|
+
import_node_fs48.default.accessSync(filePath, import_node_fs48.default.constants.X_OK);
|
|
25635
25922
|
return true;
|
|
25636
25923
|
} catch {
|
|
25637
25924
|
return false;
|
|
@@ -25645,7 +25932,7 @@ function displayPath(filePath) {
|
|
|
25645
25932
|
return `~${filePath.slice(home.length)}`;
|
|
25646
25933
|
}
|
|
25647
25934
|
function probeInstalledCliVersion(executable) {
|
|
25648
|
-
const result = (0,
|
|
25935
|
+
const result = (0, import_node_child_process37.spawnSync)(executable, ["-V"], {
|
|
25649
25936
|
encoding: "utf-8",
|
|
25650
25937
|
timeout: CLI_PATH_PROBE_TIMEOUT_MS
|
|
25651
25938
|
});
|
|
@@ -25656,7 +25943,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
25656
25943
|
}
|
|
25657
25944
|
function buildCliPathCheck(options = {}) {
|
|
25658
25945
|
const id5 = "global.cli-path";
|
|
25659
|
-
const runningVersion = options.runningVersion ?? (true ? "0.6.
|
|
25946
|
+
const runningVersion = options.runningVersion ?? (true ? "0.6.5" : "0.0.0-dev");
|
|
25660
25947
|
if (runningVersion === "0.0.0-dev") {
|
|
25661
25948
|
return {
|
|
25662
25949
|
id: id5,
|
|
@@ -25830,12 +26117,12 @@ function buildGlobalToolChecksWithoutTelemetry(repoPath) {
|
|
|
25830
26117
|
checks.push(nodeToolchainCheck(repoPath));
|
|
25831
26118
|
return checks;
|
|
25832
26119
|
}
|
|
25833
|
-
var
|
|
26120
|
+
var import_node_child_process37, import_node_fs48, import_node_path58, DEVSY_DISABLE_TELEMETRY, CLI_PATH_PROBE_TIMEOUT_MS, INSTALLED_CLI_VERSION_RE;
|
|
25834
26121
|
var init_tool_diagnostics = __esm({
|
|
25835
26122
|
"src/core/tool-diagnostics.ts"() {
|
|
25836
26123
|
"use strict";
|
|
25837
|
-
|
|
25838
|
-
|
|
26124
|
+
import_node_child_process37 = require("child_process");
|
|
26125
|
+
import_node_fs48 = __toESM(require("fs"));
|
|
25839
26126
|
import_node_path58 = __toESM(require("path"));
|
|
25840
26127
|
init_devsy_agent();
|
|
25841
26128
|
init_idle_sweep();
|
|
@@ -26186,11 +26473,11 @@ function inspectPostgresCredentials(repoPath, config) {
|
|
|
26186
26473
|
parseErrors.push(`${app.name}: ${composeFile} (${message})`);
|
|
26187
26474
|
continue;
|
|
26188
26475
|
}
|
|
26189
|
-
if (!
|
|
26476
|
+
if (!import_node_fs49.default.existsSync(absolutePath)) {
|
|
26190
26477
|
continue;
|
|
26191
26478
|
}
|
|
26192
26479
|
try {
|
|
26193
|
-
const raw =
|
|
26480
|
+
const raw = import_node_fs49.default.readFileSync(absolutePath, "utf-8");
|
|
26194
26481
|
const parsed = import_yaml7.default.parse(raw);
|
|
26195
26482
|
const root = asRecord2(parsed);
|
|
26196
26483
|
const services = asRecord2(root?.services);
|
|
@@ -26554,7 +26841,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26554
26841
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
26555
26842
|
});
|
|
26556
26843
|
}
|
|
26557
|
-
const cliVersion = true ? "0.6.
|
|
26844
|
+
const cliVersion = true ? "0.6.5" : "0.0.0-dev";
|
|
26558
26845
|
const configVersion = config.devrouter?.version;
|
|
26559
26846
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
26560
26847
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -26592,7 +26879,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26592
26879
|
filePath,
|
|
26593
26880
|
absolutePath: import_node_path60.default.resolve(repo.path, filePath)
|
|
26594
26881
|
}))
|
|
26595
|
-
).filter((entry) => !
|
|
26882
|
+
).filter((entry) => !import_node_fs49.default.existsSync(entry.absolutePath));
|
|
26596
26883
|
addCheck(checks, {
|
|
26597
26884
|
id: "repo.compose-files",
|
|
26598
26885
|
level: missingComposeFiles.length === 0 ? "ok" : "error",
|
|
@@ -26636,7 +26923,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26636
26923
|
app: app.name,
|
|
26637
26924
|
cwd: app.hostRun.cwd,
|
|
26638
26925
|
absolutePath: import_node_path60.default.resolve(repo.path, app.hostRun.cwd)
|
|
26639
|
-
})).filter((entry) => !
|
|
26926
|
+
})).filter((entry) => !import_node_fs49.default.existsSync(entry.absolutePath));
|
|
26640
26927
|
addCheck(checks, {
|
|
26641
26928
|
id: "repo.host-cwd",
|
|
26642
26929
|
level: missingHostCwds.length === 0 ? "ok" : "error",
|
|
@@ -26780,11 +27067,11 @@ async function buildDoctorReport(options = {}) {
|
|
|
26780
27067
|
nextSteps
|
|
26781
27068
|
};
|
|
26782
27069
|
}
|
|
26783
|
-
var
|
|
27070
|
+
var import_node_fs49, import_node_path60, import_yaml7, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
|
|
26784
27071
|
var init_doctor = __esm({
|
|
26785
27072
|
"src/core/doctor.ts"() {
|
|
26786
27073
|
"use strict";
|
|
26787
|
-
|
|
27074
|
+
import_node_fs49 = __toESM(require("fs"));
|
|
26788
27075
|
import_node_path60 = __toESM(require("path"));
|
|
26789
27076
|
import_yaml7 = __toESM(require("yaml"));
|
|
26790
27077
|
init_capacity_store();
|
|
@@ -26814,6 +27101,7 @@ var init_doctor = __esm({
|
|
|
26814
27101
|
"journal-directory-unsafe": "Restore private ownership and mode 0700 on the reliability journal directory, then retry.",
|
|
26815
27102
|
"journal-directory-unreadable": "Restore read access to the reliability journal directory, then retry.",
|
|
26816
27103
|
"journal-invalid": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
27104
|
+
"journal-writer-newer": "Use the devrouter CLI that wrote the named journal or a newer version before retrying admission; preserve the journal.",
|
|
26817
27105
|
"journal-unreadable": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
26818
27106
|
"journal-entry-unsafe": "Restore private ownership, mode 0600 and a bounded size on the named journal entry, then retry."
|
|
26819
27107
|
};
|
|
@@ -27181,12 +27469,12 @@ function parseSsPortListeners(stdout, port) {
|
|
|
27181
27469
|
return listeners;
|
|
27182
27470
|
}
|
|
27183
27471
|
function findPortListeners(port) {
|
|
27184
|
-
const result = (0,
|
|
27472
|
+
const result = (0, import_node_child_process38.spawnSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
|
|
27185
27473
|
encoding: "utf-8"
|
|
27186
27474
|
});
|
|
27187
27475
|
if (result.error && result.error.code === "ENOENT") {
|
|
27188
27476
|
if (process.platform === "linux") {
|
|
27189
|
-
const ssResult = (0,
|
|
27477
|
+
const ssResult = (0, import_node_child_process38.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
27190
27478
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
27191
27479
|
return parseSsPortListeners(ssResult.stdout, port);
|
|
27192
27480
|
}
|
|
@@ -27215,11 +27503,11 @@ function findPortListeners(port) {
|
|
|
27215
27503
|
};
|
|
27216
27504
|
});
|
|
27217
27505
|
}
|
|
27218
|
-
var
|
|
27506
|
+
var import_node_child_process38;
|
|
27219
27507
|
var init_ports = __esm({
|
|
27220
27508
|
"src/util/ports.ts"() {
|
|
27221
27509
|
"use strict";
|
|
27222
|
-
|
|
27510
|
+
import_node_child_process38 = require("child_process");
|
|
27223
27511
|
}
|
|
27224
27512
|
});
|
|
27225
27513
|
|
|
@@ -27306,6 +27594,7 @@ async function runEnsureCommand(options) {
|
|
|
27306
27594
|
profile: options.profile,
|
|
27307
27595
|
...options.repair ? { repair: true } : {},
|
|
27308
27596
|
...options.initializeNew ? { initializeNew: true } : {},
|
|
27597
|
+
...options.replaceApp ? { replaceApp: true } : {},
|
|
27309
27598
|
...options.variant !== void 0 ? { variant: options.variant } : {}
|
|
27310
27599
|
};
|
|
27311
27600
|
const result = await superviseLifecycle(
|
|
@@ -27553,7 +27842,7 @@ function buildHostEnvReport(input2) {
|
|
|
27553
27842
|
};
|
|
27554
27843
|
}
|
|
27555
27844
|
function listDevcontainerContainers(repoPath) {
|
|
27556
|
-
const listed = (0,
|
|
27845
|
+
const listed = (0, import_node_child_process39.spawnSync)(
|
|
27557
27846
|
"docker",
|
|
27558
27847
|
[
|
|
27559
27848
|
"ps",
|
|
@@ -27574,7 +27863,7 @@ function listDevcontainerContainers(repoPath) {
|
|
|
27574
27863
|
}
|
|
27575
27864
|
}
|
|
27576
27865
|
function dockerPortBindings(containerId, port) {
|
|
27577
|
-
const result = (0,
|
|
27866
|
+
const result = (0, import_node_child_process39.spawnSync)("docker", ["port", containerId, `${port}/tcp`], {
|
|
27578
27867
|
encoding: "utf-8",
|
|
27579
27868
|
...networkDockerOptions()
|
|
27580
27869
|
});
|
|
@@ -27689,11 +27978,11 @@ function hostEnvVariables(report, processEnv) {
|
|
|
27689
27978
|
}
|
|
27690
27979
|
return variables;
|
|
27691
27980
|
}
|
|
27692
|
-
var
|
|
27981
|
+
var import_node_child_process39, import_node_path61, LOOPBACK_UPSTREAM_HOSTS, ROUTED_TCP_PARAMS;
|
|
27693
27982
|
var init_host_env = __esm({
|
|
27694
27983
|
"src/core/host-env.ts"() {
|
|
27695
27984
|
"use strict";
|
|
27696
|
-
|
|
27985
|
+
import_node_child_process39 = require("child_process");
|
|
27697
27986
|
import_node_path61 = __toESM(require("path"));
|
|
27698
27987
|
init_devcontainer_profile();
|
|
27699
27988
|
init_devpod_environment();
|
|
@@ -27791,7 +28080,7 @@ function hostCommandEnvironment(report, processEnv) {
|
|
|
27791
28080
|
}
|
|
27792
28081
|
function runHostCommand(command, env) {
|
|
27793
28082
|
return new Promise((resolve) => {
|
|
27794
|
-
const child = (0,
|
|
28083
|
+
const child = (0, import_node_child_process40.spawn)(command[0], command.slice(1), { env, stdio: "inherit" });
|
|
27795
28084
|
const forward = (signal) => () => child.kill(signal);
|
|
27796
28085
|
const handlers = [
|
|
27797
28086
|
["SIGINT", forward("SIGINT")],
|
|
@@ -27831,11 +28120,11 @@ async function runEnvCommand(invocation) {
|
|
|
27831
28120
|
}
|
|
27832
28121
|
process.stdout.write(formatEnvReport(report));
|
|
27833
28122
|
}
|
|
27834
|
-
var
|
|
28123
|
+
var import_node_child_process40, import_node_os8, HOST_PORT_ENV_PREFIX;
|
|
27835
28124
|
var init_env = __esm({
|
|
27836
28125
|
"src/commands/env.ts"() {
|
|
27837
28126
|
"use strict";
|
|
27838
|
-
|
|
28127
|
+
import_node_child_process40 = require("child_process");
|
|
27839
28128
|
import_node_os8 = require("os");
|
|
27840
28129
|
init_host_env();
|
|
27841
28130
|
init_managed_host_ports();
|
|
@@ -27885,7 +28174,7 @@ var init_status2 = __esm({
|
|
|
27885
28174
|
|
|
27886
28175
|
// src/core/harness-continuation.ts
|
|
27887
28176
|
function harnessContinuationPath(repoRoot) {
|
|
27888
|
-
const key = (0,
|
|
28177
|
+
const key = (0, import_node_crypto31.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
|
|
27889
28178
|
return import_node_path62.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
|
|
27890
28179
|
}
|
|
27891
28180
|
function counter4(value) {
|
|
@@ -27899,7 +28188,7 @@ function validEntry(value) {
|
|
|
27899
28188
|
function readLedgerSync(file, nowMs) {
|
|
27900
28189
|
let stat;
|
|
27901
28190
|
try {
|
|
27902
|
-
stat =
|
|
28191
|
+
stat = import_node_fs50.default.lstatSync(file);
|
|
27903
28192
|
} catch {
|
|
27904
28193
|
return [];
|
|
27905
28194
|
}
|
|
@@ -27907,7 +28196,7 @@ function readLedgerSync(file, nowMs) {
|
|
|
27907
28196
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0) return [];
|
|
27908
28197
|
let parsed;
|
|
27909
28198
|
try {
|
|
27910
|
-
parsed = JSON.parse(
|
|
28199
|
+
parsed = JSON.parse(import_node_fs50.default.readFileSync(file, "utf-8"));
|
|
27911
28200
|
} catch {
|
|
27912
28201
|
return [];
|
|
27913
28202
|
}
|
|
@@ -27927,7 +28216,7 @@ function claimHarnessContinuation(repoRoot, claim2) {
|
|
|
27927
28216
|
const nowMs = claim2.nowMs ?? Date.now();
|
|
27928
28217
|
try {
|
|
27929
28218
|
const file = harnessContinuationPath(repoRoot);
|
|
27930
|
-
|
|
28219
|
+
import_node_fs50.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27931
28220
|
return withFileLockSync(
|
|
27932
28221
|
`${file}.lock`,
|
|
27933
28222
|
{ activity: "harness continuation claim", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27959,7 +28248,7 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27959
28248
|
const nowMs = settlement.nowMs ?? Date.now();
|
|
27960
28249
|
try {
|
|
27961
28250
|
const file = harnessContinuationPath(repoRoot);
|
|
27962
|
-
|
|
28251
|
+
import_node_fs50.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27963
28252
|
withFileLockSync(
|
|
27964
28253
|
`${file}.lock`,
|
|
27965
28254
|
{ activity: "harness continuation settlement", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27983,12 +28272,12 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27983
28272
|
} catch {
|
|
27984
28273
|
}
|
|
27985
28274
|
}
|
|
27986
|
-
var
|
|
28275
|
+
var import_node_crypto31, import_node_fs50, import_node_path62, HARNESS_CONTINUATION_MAX_ENTRIES, HARNESS_CONTINUATION_TTL_MS, HARNESS_CONTINUATION_LOCK_WAIT_MS, MAX_LEDGER_BYTES, MAX_TOOL_USE_ID_LENGTH, MAX_PHASE_LENGTH;
|
|
27987
28276
|
var init_harness_continuation = __esm({
|
|
27988
28277
|
"src/core/harness-continuation.ts"() {
|
|
27989
28278
|
"use strict";
|
|
27990
|
-
|
|
27991
|
-
|
|
28279
|
+
import_node_crypto31 = require("crypto");
|
|
28280
|
+
import_node_fs50 = __toESM(require("fs"));
|
|
27992
28281
|
import_node_path62 = __toESM(require("path"));
|
|
27993
28282
|
init_atomic_file();
|
|
27994
28283
|
init_file_lock();
|
|
@@ -28010,7 +28299,7 @@ function isTransitionalHarnessPhase(phase) {
|
|
|
28010
28299
|
function findHarnessGateRepoRoot(cwd) {
|
|
28011
28300
|
let current = import_node_path63.default.resolve(cwd);
|
|
28012
28301
|
for (let depth = 0; depth < REPO_ROOT_MAX_DEPTH; depth += 1) {
|
|
28013
|
-
if (
|
|
28302
|
+
if (import_node_fs51.default.existsSync(import_node_path63.default.join(current, ".devrouter.yml"))) {
|
|
28014
28303
|
return current;
|
|
28015
28304
|
}
|
|
28016
28305
|
const parent = import_node_path63.default.dirname(current);
|
|
@@ -28105,11 +28394,11 @@ function parseHarnessGateBudget(value) {
|
|
|
28105
28394
|
}
|
|
28106
28395
|
return Math.min(Math.trunc(parsed), HARNESS_GATE_MAX_BUDGET_MS);
|
|
28107
28396
|
}
|
|
28108
|
-
var
|
|
28397
|
+
var import_node_fs51, import_node_path63, HARNESS_GATE_DEFAULT_BUDGET_MS, HARNESS_GATE_MAX_BUDGET_MS, HARNESS_GATE_POLL_INTERVAL_MS, TRANSITIONAL_PHASES, REPO_ROOT_MAX_DEPTH;
|
|
28109
28398
|
var init_harness_gate = __esm({
|
|
28110
28399
|
"src/core/harness-gate.ts"() {
|
|
28111
28400
|
"use strict";
|
|
28112
|
-
|
|
28401
|
+
import_node_fs51 = __toESM(require("fs"));
|
|
28113
28402
|
import_node_path63 = __toESM(require("path"));
|
|
28114
28403
|
init_reliability_operation_store();
|
|
28115
28404
|
init_workspace();
|
|
@@ -28369,7 +28658,7 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28369
28658
|
}
|
|
28370
28659
|
const budgetMs = parseHarnessGateBudget(options.waitBudgetMs);
|
|
28371
28660
|
const toolUseId = typeof payload.tool_use_id === "string" && payload.tool_use_id.length > 0 && payload.tool_use_id.length <= MAX_TOOL_USE_ID_LENGTH2 ? payload.tool_use_id : void 0;
|
|
28372
|
-
const payloadSha256 = (0,
|
|
28661
|
+
const payloadSha256 = (0, import_node_crypto32.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
|
|
28373
28662
|
const claim2 = dependencies.claim ?? ((root, input2) => {
|
|
28374
28663
|
const outcome = claimHarnessContinuation(root, input2);
|
|
28375
28664
|
if (outcome.kind === "claimed") {
|
|
@@ -28477,11 +28766,11 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28477
28766
|
`
|
|
28478
28767
|
);
|
|
28479
28768
|
}
|
|
28480
|
-
var
|
|
28769
|
+
var import_node_crypto32, MAX_HOOK_PAYLOAD_BYTES, STDIN_TIMEOUT_MS, MAX_TOOL_USE_ID_LENGTH2, DEVROUTER_EXECUTABLES, LAUNCHER_WORDS, LAUNCHER_SUBCOMMANDS, COMMAND_WORD_LIMIT;
|
|
28481
28770
|
var init_harness = __esm({
|
|
28482
28771
|
"src/commands/harness.ts"() {
|
|
28483
28772
|
"use strict";
|
|
28484
|
-
|
|
28773
|
+
import_node_crypto32 = require("crypto");
|
|
28485
28774
|
init_harness_continuation();
|
|
28486
28775
|
init_harness_gate();
|
|
28487
28776
|
MAX_HOOK_PAYLOAD_BYTES = 256 * 1024;
|
|
@@ -28597,7 +28886,7 @@ async function runOpenCommand(name) {
|
|
|
28597
28886
|
);
|
|
28598
28887
|
return;
|
|
28599
28888
|
}
|
|
28600
|
-
const result = (0,
|
|
28889
|
+
const result = (0, import_node_child_process41.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
28601
28890
|
if (result.status !== 0) {
|
|
28602
28891
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
28603
28892
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -28605,11 +28894,11 @@ async function runOpenCommand(name) {
|
|
|
28605
28894
|
process.stdout.write(`Opened ${url}
|
|
28606
28895
|
`);
|
|
28607
28896
|
}
|
|
28608
|
-
var
|
|
28897
|
+
var import_node_child_process41;
|
|
28609
28898
|
var init_open = __esm({
|
|
28610
28899
|
"src/commands/open.ts"() {
|
|
28611
28900
|
"use strict";
|
|
28612
|
-
|
|
28901
|
+
import_node_child_process41 = require("child_process");
|
|
28613
28902
|
init_docker();
|
|
28614
28903
|
init_host_routes();
|
|
28615
28904
|
init_repo_config();
|
|
@@ -28653,7 +28942,7 @@ async function runLogsCommand(options) {
|
|
|
28653
28942
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
28654
28943
|
if (options.follow) {
|
|
28655
28944
|
args.splice(1, 0, "-f");
|
|
28656
|
-
const child = (0,
|
|
28945
|
+
const child = (0, import_node_child_process42.spawn)("docker", args, { stdio: "inherit" });
|
|
28657
28946
|
const onSignal = () => {
|
|
28658
28947
|
child.kill("SIGTERM");
|
|
28659
28948
|
};
|
|
@@ -28667,17 +28956,17 @@ async function runLogsCommand(options) {
|
|
|
28667
28956
|
});
|
|
28668
28957
|
});
|
|
28669
28958
|
} else {
|
|
28670
|
-
const result = (0,
|
|
28959
|
+
const result = (0, import_node_child_process42.spawnSync)("docker", args, { stdio: "inherit" });
|
|
28671
28960
|
if (result.status !== 0) {
|
|
28672
28961
|
throw new Error("Failed to retrieve router logs.");
|
|
28673
28962
|
}
|
|
28674
28963
|
}
|
|
28675
28964
|
}
|
|
28676
|
-
var
|
|
28965
|
+
var import_node_child_process42;
|
|
28677
28966
|
var init_logs = __esm({
|
|
28678
28967
|
"src/commands/logs.ts"() {
|
|
28679
28968
|
"use strict";
|
|
28680
|
-
|
|
28969
|
+
import_node_child_process42 = require("child_process");
|
|
28681
28970
|
init_docker();
|
|
28682
28971
|
init_lifecycle_diagnostics();
|
|
28683
28972
|
init_router();
|
|
@@ -28721,11 +29010,11 @@ function asRecord3(value) {
|
|
|
28721
29010
|
return value;
|
|
28722
29011
|
}
|
|
28723
29012
|
function readJson(filePath) {
|
|
28724
|
-
if (!
|
|
29013
|
+
if (!import_node_fs52.default.existsSync(filePath)) {
|
|
28725
29014
|
return void 0;
|
|
28726
29015
|
}
|
|
28727
29016
|
try {
|
|
28728
|
-
return JSON.parse(
|
|
29017
|
+
return JSON.parse(import_node_fs52.default.readFileSync(filePath, "utf-8"));
|
|
28729
29018
|
} catch {
|
|
28730
29019
|
return void 0;
|
|
28731
29020
|
}
|
|
@@ -28772,7 +29061,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
28772
29061
|
["bun.lock", "bun"]
|
|
28773
29062
|
];
|
|
28774
29063
|
for (const [fileName, name] of lockfiles) {
|
|
28775
|
-
if (
|
|
29064
|
+
if (import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28776
29065
|
return { name, source: fileName };
|
|
28777
29066
|
}
|
|
28778
29067
|
}
|
|
@@ -28788,8 +29077,8 @@ function inspectNode(repoPath, pkg) {
|
|
|
28788
29077
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
28789
29078
|
}
|
|
28790
29079
|
const nvmrc = import_node_path64.default.join(repoPath, ".nvmrc");
|
|
28791
|
-
if (
|
|
28792
|
-
const version =
|
|
29080
|
+
if (import_node_fs52.default.existsSync(nvmrc)) {
|
|
29081
|
+
const version = import_node_fs52.default.readFileSync(nvmrc, "utf-8").trim();
|
|
28793
29082
|
return { version, source: ".nvmrc" };
|
|
28794
29083
|
}
|
|
28795
29084
|
return void 0;
|
|
@@ -28868,7 +29157,7 @@ function composeFiles(repoPath) {
|
|
|
28868
29157
|
...configuredComposeFiles(repoPath)
|
|
28869
29158
|
];
|
|
28870
29159
|
return Array.from(new Set(candidates)).filter(
|
|
28871
|
-
(fileName) =>
|
|
29160
|
+
(fileName) => import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))
|
|
28872
29161
|
);
|
|
28873
29162
|
}
|
|
28874
29163
|
function stringArray2(value) {
|
|
@@ -28906,7 +29195,7 @@ function inspectServices(repoPath) {
|
|
|
28906
29195
|
const services = [];
|
|
28907
29196
|
for (const fileName of composeFiles(repoPath)) {
|
|
28908
29197
|
try {
|
|
28909
|
-
const parsed = import_yaml8.default.parse(
|
|
29198
|
+
const parsed = import_yaml8.default.parse(import_node_fs52.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8"));
|
|
28910
29199
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
28911
29200
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
28912
29201
|
const service = asRecord3(value);
|
|
@@ -28941,8 +29230,8 @@ function inspectServices(repoPath) {
|
|
|
28941
29230
|
return services;
|
|
28942
29231
|
}
|
|
28943
29232
|
function inspectEnvFiles(repoPath) {
|
|
28944
|
-
const files =
|
|
28945
|
-
const content =
|
|
29233
|
+
const files = import_node_fs52.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
29234
|
+
const content = import_node_fs52.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8");
|
|
28946
29235
|
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();
|
|
28947
29236
|
return { path: fileName, names };
|
|
28948
29237
|
});
|
|
@@ -28957,17 +29246,17 @@ function inspectEnvFiles(repoPath) {
|
|
|
28957
29246
|
}
|
|
28958
29247
|
function inspectDevcontainer(repoPath) {
|
|
28959
29248
|
const dir = import_node_path64.default.join(repoPath, ".devcontainer");
|
|
28960
|
-
if (!
|
|
29249
|
+
if (!import_node_fs52.default.existsSync(dir)) {
|
|
28961
29250
|
return { exists: false, files: [] };
|
|
28962
29251
|
}
|
|
28963
29252
|
return {
|
|
28964
29253
|
exists: true,
|
|
28965
|
-
files:
|
|
29254
|
+
files: import_node_fs52.default.readdirSync(dir).filter((fileName) => import_node_fs52.default.statSync(import_node_path64.default.join(dir, fileName)).isFile()).sort().map((fileName) => `.devcontainer/${fileName}`)
|
|
28966
29255
|
};
|
|
28967
29256
|
}
|
|
28968
29257
|
function inspectDevrouter(repoPath) {
|
|
28969
29258
|
const configPath = getRepoConfigPath(repoPath);
|
|
28970
|
-
if (!
|
|
29259
|
+
if (!import_node_fs52.default.existsSync(configPath)) {
|
|
28971
29260
|
return {
|
|
28972
29261
|
exists: false,
|
|
28973
29262
|
configPath,
|
|
@@ -29011,15 +29300,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
29011
29300
|
["AGENTS.md", "agents"],
|
|
29012
29301
|
["CLAUDE.md", "claude"]
|
|
29013
29302
|
]) {
|
|
29014
|
-
if (
|
|
29303
|
+
if (import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
29015
29304
|
results.push({ path: fileName, kind });
|
|
29016
29305
|
}
|
|
29017
29306
|
}
|
|
29018
29307
|
const skillsDir = import_node_path64.default.join(repoPath, ".agents", "skills");
|
|
29019
|
-
if (
|
|
29020
|
-
for (const name of
|
|
29308
|
+
if (import_node_fs52.default.existsSync(skillsDir)) {
|
|
29309
|
+
for (const name of import_node_fs52.default.readdirSync(skillsDir).sort()) {
|
|
29021
29310
|
const skillPath = import_node_path64.default.join(skillsDir, name, "SKILL.md");
|
|
29022
|
-
if (
|
|
29311
|
+
if (import_node_fs52.default.existsSync(skillPath)) {
|
|
29023
29312
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
29024
29313
|
}
|
|
29025
29314
|
}
|
|
@@ -29081,11 +29370,11 @@ function inspectRepo(options = {}) {
|
|
|
29081
29370
|
issues: buildIssues(reportWithoutIssues)
|
|
29082
29371
|
};
|
|
29083
29372
|
}
|
|
29084
|
-
var
|
|
29373
|
+
var import_node_fs52, import_node_path64, import_yaml8;
|
|
29085
29374
|
var init_repo_inspect = __esm({
|
|
29086
29375
|
"src/core/repo-inspect.ts"() {
|
|
29087
29376
|
"use strict";
|
|
29088
|
-
|
|
29377
|
+
import_node_fs52 = __toESM(require("fs"));
|
|
29089
29378
|
import_node_path64 = __toESM(require("path"));
|
|
29090
29379
|
import_yaml8 = __toESM(require("yaml"));
|
|
29091
29380
|
init_repo_config();
|
|
@@ -29191,7 +29480,7 @@ function requiredFileChecks(repoPath) {
|
|
|
29191
29480
|
".devcontainer/docker-compose.yml",
|
|
29192
29481
|
".devrouter.yml"
|
|
29193
29482
|
];
|
|
29194
|
-
const missing = required.filter((fileName) => !
|
|
29483
|
+
const missing = required.filter((fileName) => !import_node_fs53.default.existsSync(import_node_path65.default.join(repoPath, fileName)));
|
|
29195
29484
|
return {
|
|
29196
29485
|
id: "repo.devcontainer.verify-files",
|
|
29197
29486
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -29416,11 +29705,11 @@ async function verifyDevcontainer(options = {}) {
|
|
|
29416
29705
|
nextSteps: collectNextSteps3(checks)
|
|
29417
29706
|
};
|
|
29418
29707
|
}
|
|
29419
|
-
var
|
|
29708
|
+
var import_node_fs53, import_node_path65;
|
|
29420
29709
|
var init_devcontainer_verify = __esm({
|
|
29421
29710
|
"src/core/devcontainer-verify.ts"() {
|
|
29422
29711
|
"use strict";
|
|
29423
|
-
|
|
29712
|
+
import_node_fs53 = __toESM(require("fs"));
|
|
29424
29713
|
import_node_path65 = __toESM(require("path"));
|
|
29425
29714
|
init_capabilities();
|
|
29426
29715
|
init_doctor();
|
|
@@ -29764,7 +30053,7 @@ function plannedFiles(repoPath, version) {
|
|
|
29764
30053
|
}
|
|
29765
30054
|
function classifyFile(repoPath, file) {
|
|
29766
30055
|
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29767
|
-
if (!
|
|
30056
|
+
if (!import_node_fs54.default.existsSync(absolutePath)) {
|
|
29768
30057
|
return {
|
|
29769
30058
|
path: file.relativePath,
|
|
29770
30059
|
action: "create",
|
|
@@ -29772,7 +30061,7 @@ function classifyFile(repoPath, file) {
|
|
|
29772
30061
|
bytes: Buffer.byteLength(file.content)
|
|
29773
30062
|
};
|
|
29774
30063
|
}
|
|
29775
|
-
const current =
|
|
30064
|
+
const current = import_node_fs54.default.readFileSync(absolutePath, "utf-8");
|
|
29776
30065
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
29777
30066
|
return {
|
|
29778
30067
|
path: file.relativePath,
|
|
@@ -29830,10 +30119,10 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
29830
30119
|
}
|
|
29831
30120
|
function writeFile(repoPath, file) {
|
|
29832
30121
|
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29833
|
-
|
|
29834
|
-
|
|
30122
|
+
import_node_fs54.default.mkdirSync(import_node_path66.default.dirname(absolutePath), { recursive: true });
|
|
30123
|
+
import_node_fs54.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
29835
30124
|
if (file.executable) {
|
|
29836
|
-
|
|
30125
|
+
import_node_fs54.default.chmodSync(absolutePath, 493);
|
|
29837
30126
|
}
|
|
29838
30127
|
}
|
|
29839
30128
|
function writeDevcontainer(options = {}) {
|
|
@@ -29871,11 +30160,11 @@ function writeDevcontainer(options = {}) {
|
|
|
29871
30160
|
nextSteps: postWriteNextSteps(repoPath)
|
|
29872
30161
|
};
|
|
29873
30162
|
}
|
|
29874
|
-
var
|
|
30163
|
+
var import_node_fs54, import_node_path66, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
29875
30164
|
var init_devcontainer_write = __esm({
|
|
29876
30165
|
"src/core/devcontainer-write.ts"() {
|
|
29877
30166
|
"use strict";
|
|
29878
|
-
|
|
30167
|
+
import_node_fs54 = __toESM(require("fs"));
|
|
29879
30168
|
import_node_path66 = __toESM(require("path"));
|
|
29880
30169
|
init_repo_config();
|
|
29881
30170
|
init_repo_inspect();
|
|
@@ -30216,7 +30505,7 @@ function loadContract(repoPath, contractPath) {
|
|
|
30216
30505
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
30217
30506
|
let metadata;
|
|
30218
30507
|
try {
|
|
30219
|
-
metadata =
|
|
30508
|
+
metadata = import_node_fs55.default.lstatSync(absolutePath);
|
|
30220
30509
|
} catch (error) {
|
|
30221
30510
|
fail3(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
30222
30511
|
}
|
|
@@ -30226,10 +30515,10 @@ function loadContract(repoPath, contractPath) {
|
|
|
30226
30515
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
30227
30516
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30228
30517
|
}
|
|
30229
|
-
const realRepo =
|
|
30230
|
-
const realContract =
|
|
30518
|
+
const realRepo = import_node_fs55.default.realpathSync(repoPath);
|
|
30519
|
+
const realContract = import_node_fs55.default.realpathSync(absolutePath);
|
|
30231
30520
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
30232
|
-
const source =
|
|
30521
|
+
const source = import_node_fs55.default.readFileSync(absolutePath, "utf-8");
|
|
30233
30522
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
30234
30523
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30235
30524
|
}
|
|
@@ -30249,11 +30538,11 @@ function resolveProfilePlan(options) {
|
|
|
30249
30538
|
contractPath: loaded.contractPath
|
|
30250
30539
|
});
|
|
30251
30540
|
}
|
|
30252
|
-
var
|
|
30541
|
+
var import_node_fs55, import_node_path67, import_yaml9, CONTRACT_VERSION, MAX_CONTRACT_BYTES, MAX_APP_MAPPINGS, MAX_BINDING_KEYS, MAX_BINDING_VALUES, MAX_LITERAL_LENGTH, BINDING_KEY;
|
|
30253
30542
|
var init_profile_plan = __esm({
|
|
30254
30543
|
"src/core/profile-plan.ts"() {
|
|
30255
30544
|
"use strict";
|
|
30256
|
-
|
|
30545
|
+
import_node_fs55 = __toESM(require("fs"));
|
|
30257
30546
|
import_node_path67 = __toESM(require("path"));
|
|
30258
30547
|
import_yaml9 = require("yaml");
|
|
30259
30548
|
init_paths();
|
|
@@ -30727,7 +31016,7 @@ function loadPreviewManifest(repoPath) {
|
|
|
30727
31016
|
const manifestPath = assertPathWithinRepo(MANIFEST_FILE_NAME, resolvedRepo, "Preview manifest");
|
|
30728
31017
|
let metadata;
|
|
30729
31018
|
try {
|
|
30730
|
-
metadata =
|
|
31019
|
+
metadata = import_node_fs56.default.lstatSync(manifestPath);
|
|
30731
31020
|
} catch (error) {
|
|
30732
31021
|
fail4(`could not inspect preview manifest '${MANIFEST_FILE_NAME}': ${error.message}`);
|
|
30733
31022
|
}
|
|
@@ -30737,24 +31026,24 @@ function loadPreviewManifest(repoPath) {
|
|
|
30737
31026
|
if (metadata.size > MAX_MANIFEST_BYTES) {
|
|
30738
31027
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30739
31028
|
}
|
|
30740
|
-
const realRepo =
|
|
30741
|
-
const realManifest =
|
|
31029
|
+
const realRepo = import_node_fs56.default.realpathSync(resolvedRepo);
|
|
31030
|
+
const realManifest = import_node_fs56.default.realpathSync(manifestPath);
|
|
30742
31031
|
assertPathWithinRepo(realManifest, realRepo, "Preview manifest");
|
|
30743
|
-
const source =
|
|
31032
|
+
const source = import_node_fs56.default.readFileSync(manifestPath, "utf-8");
|
|
30744
31033
|
if (Buffer.byteLength(source, "utf-8") > MAX_MANIFEST_BYTES) {
|
|
30745
31034
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30746
31035
|
}
|
|
30747
31036
|
return {
|
|
30748
31037
|
manifest: parsePreviewManifest(source),
|
|
30749
|
-
digest: (0,
|
|
31038
|
+
digest: (0, import_node_crypto33.createHash)("sha256").update(source, "utf-8").digest("hex")
|
|
30750
31039
|
};
|
|
30751
31040
|
}
|
|
30752
|
-
var
|
|
31041
|
+
var import_node_crypto33, import_node_fs56, import_node_path69, import_yaml10, MANIFEST_FILE_NAME, MAX_MANIFEST_BYTES, MAX_COLLECTION_ENTRIES, MAX_BINDING_VALUES2, MAX_COMMAND_ARGS, MAX_LITERAL_LENGTH2, MAX_REPO_PATH_LENGTH, NAME_RE, IMAGE_REFERENCE_RE;
|
|
30753
31042
|
var init_manifest = __esm({
|
|
30754
31043
|
"src/core/preview/manifest.ts"() {
|
|
30755
31044
|
"use strict";
|
|
30756
|
-
|
|
30757
|
-
|
|
31045
|
+
import_node_crypto33 = require("crypto");
|
|
31046
|
+
import_node_fs56 = __toESM(require("fs"));
|
|
30758
31047
|
import_node_path69 = __toESM(require("path"));
|
|
30759
31048
|
import_yaml10 = require("yaml");
|
|
30760
31049
|
init_paths();
|
|
@@ -31898,7 +32187,7 @@ var init_state = __esm({
|
|
|
31898
32187
|
function previewIdentityKey(identity2) {
|
|
31899
32188
|
if (!/^[a-z0-9.-]+$/.test(identity2.forgeHost) || identity2.forgeHost.length > 253 || !/^[A-Za-z0-9_-]{1,128}$/.test(identity2.projectId) || !Number.isSafeInteger(identity2.change) || identity2.change < 1)
|
|
31900
32189
|
throw new Error("Invalid immutable preview identity.");
|
|
31901
|
-
return (0,
|
|
32190
|
+
return (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify([identity2.forgeHost, identity2.projectId, identity2.change])).digest("hex");
|
|
31902
32191
|
}
|
|
31903
32192
|
function costs(pool) {
|
|
31904
32193
|
return Object.values(pool.sessions).reduce((total, entry) => total + entry.reservedCents, 0);
|
|
@@ -31954,11 +32243,11 @@ function sessionReady(entry, now, expiresAt) {
|
|
|
31954
32243
|
...expiresAt === void 0 ? {} : { expiresAt }
|
|
31955
32244
|
});
|
|
31956
32245
|
}
|
|
31957
|
-
var
|
|
32246
|
+
var import_node_crypto34, PreviewAdmissionSuperseded, PreviewEngine;
|
|
31958
32247
|
var init_engine = __esm({
|
|
31959
32248
|
"src/core/preview/engine.ts"() {
|
|
31960
32249
|
"use strict";
|
|
31961
|
-
|
|
32250
|
+
import_node_crypto34 = require("crypto");
|
|
31962
32251
|
init_command();
|
|
31963
32252
|
init_lifecycle();
|
|
31964
32253
|
init_state();
|
|
@@ -32092,7 +32381,7 @@ var init_engine = __esm({
|
|
|
32092
32381
|
} else {
|
|
32093
32382
|
if (current && current.session.status !== "stopped" && current.session.status !== "expired")
|
|
32094
32383
|
throw new Error("Previous generation cleanup is incomplete.");
|
|
32095
|
-
const generation = (0,
|
|
32384
|
+
const generation = (0, import_node_crypto34.createHash)("sha256").update(receipt).digest("hex").slice(0, 24);
|
|
32096
32385
|
pool2.sessions[id5] = {
|
|
32097
32386
|
identity: input2.identity,
|
|
32098
32387
|
session: createPreviewSession({
|
|
@@ -32748,11 +33037,11 @@ function decodeInbox(raw) {
|
|
|
32748
33037
|
}
|
|
32749
33038
|
return structuredClone(row);
|
|
32750
33039
|
}
|
|
32751
|
-
var
|
|
33040
|
+
var import_node_crypto35, PreviewController;
|
|
32752
33041
|
var init_controller2 = __esm({
|
|
32753
33042
|
"src/core/preview/controller.ts"() {
|
|
32754
33043
|
"use strict";
|
|
32755
|
-
|
|
33044
|
+
import_node_crypto35 = require("crypto");
|
|
32756
33045
|
init_command();
|
|
32757
33046
|
init_engine();
|
|
32758
33047
|
init_status3();
|
|
@@ -32959,7 +33248,7 @@ Command refused: ${inbox.refusal}. Post a new command when the condition is reso
|
|
|
32959
33248
|
Available profiles: ${this.options.aliases.map((alias) => `\`${alias}\``).join(", ")}.` : ""}
|
|
32960
33249
|
|
|
32961
33250
|
${marker}`;
|
|
32962
|
-
const fingerprint = (0,
|
|
33251
|
+
const fingerprint = (0, import_node_crypto35.createHash)("sha256").update(body).digest("hex"), now = this.options.now();
|
|
32963
33252
|
if (inbox.status?.bodyDigest === fingerprint) {
|
|
32964
33253
|
if (inbox.needsStatus) await this.update(change, (row) => ({ ...row, needsStatus: false }));
|
|
32965
33254
|
return;
|
|
@@ -32970,7 +33259,7 @@ ${marker}`;
|
|
|
32970
33259
|
let commentId = inbox.status?.commentId;
|
|
32971
33260
|
if (!commentId) commentId = await this.options.forge.findStatus(change, marker) ?? void 0;
|
|
32972
33261
|
let create = false;
|
|
32973
|
-
const intentId = (0,
|
|
33262
|
+
const intentId = (0, import_node_crypto35.randomUUID)();
|
|
32974
33263
|
if (!inbox.status)
|
|
32975
33264
|
inbox = await this.update(change, (row) => {
|
|
32976
33265
|
create = !row.status;
|
|
@@ -33720,7 +34009,7 @@ function canonicalizeImageConfiguration(configuration) {
|
|
|
33720
34009
|
return JSON.stringify(normalizeConfiguration(configuration, "image configuration"));
|
|
33721
34010
|
}
|
|
33722
34011
|
function imageConfigurationDigest(configuration) {
|
|
33723
|
-
return `sha256:${(0,
|
|
34012
|
+
return `sha256:${(0, import_node_crypto36.createHash)("sha256").update(canonicalizeImageConfiguration(configuration), "utf-8").digest("hex")}`;
|
|
33724
34013
|
}
|
|
33725
34014
|
function targetKey(target, configurationDigest) {
|
|
33726
34015
|
return `${target}\0${configurationDigest}`;
|
|
@@ -33975,11 +34264,11 @@ function resolvePreviewImages(plan, prepared, expectedProducer, value) {
|
|
|
33975
34264
|
images: Object.fromEntries(resourceReceipts)
|
|
33976
34265
|
};
|
|
33977
34266
|
}
|
|
33978
|
-
var
|
|
34267
|
+
var import_node_crypto36, MAX_COLLECTION_ENTRIES2, MAX_CONFIGURATION_ENTRIES, MAX_CONFIGURATION_KEY_LENGTH, MAX_CONFIGURATION_VALUE_BYTES, MAX_IDENTIFIER_LENGTH, NAME_RE2, REVISION_RE2, DIGEST_RE, IMAGE_COMPONENT_RE, RECEIPT_FIELDS;
|
|
33979
34268
|
var init_images = __esm({
|
|
33980
34269
|
"src/core/preview/images.ts"() {
|
|
33981
34270
|
"use strict";
|
|
33982
|
-
|
|
34271
|
+
import_node_crypto36 = require("crypto");
|
|
33983
34272
|
MAX_COLLECTION_ENTRIES2 = 256;
|
|
33984
34273
|
MAX_CONFIGURATION_ENTRIES = 128;
|
|
33985
34274
|
MAX_CONFIGURATION_KEY_LENGTH = 128;
|
|
@@ -34013,8 +34302,8 @@ function commandImageBackend(options) {
|
|
|
34013
34302
|
throw new Error("Invalid installed image resolver command.");
|
|
34014
34303
|
const verify = () => {
|
|
34015
34304
|
for (const file of options.files) {
|
|
34016
|
-
const stat =
|
|
34017
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0,
|
|
34305
|
+
const stat = import_node_fs57.default.lstatSync(file.path);
|
|
34306
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0, import_node_crypto37.createHash)("sha256").update(import_node_fs57.default.readFileSync(file.path)).digest("hex") !== file.sha256)
|
|
34018
34307
|
throw new Error("Installed image resolver fingerprint differs.");
|
|
34019
34308
|
}
|
|
34020
34309
|
};
|
|
@@ -34026,7 +34315,7 @@ function commandImageBackend(options) {
|
|
|
34026
34315
|
platform: options.platform,
|
|
34027
34316
|
configurations: options.context(entry)
|
|
34028
34317
|
});
|
|
34029
|
-
const correlation = (0,
|
|
34318
|
+
const correlation = (0, import_node_crypto37.createHash)("sha256").update(
|
|
34030
34319
|
JSON.stringify([
|
|
34031
34320
|
entry.identity,
|
|
34032
34321
|
entry.session.generation,
|
|
@@ -34050,7 +34339,7 @@ function commandImageBackend(options) {
|
|
|
34050
34339
|
});
|
|
34051
34340
|
if (Buffer.byteLength(input2) > 1024 * 1024)
|
|
34052
34341
|
throw new Error("Image request exceeds its bound.");
|
|
34053
|
-
const result = (0,
|
|
34342
|
+
const result = (0, import_node_child_process43.spawnSync)(options.command[0], options.command.slice(1), {
|
|
34054
34343
|
shell: false,
|
|
34055
34344
|
cwd: options.cwd,
|
|
34056
34345
|
encoding: "utf8",
|
|
@@ -34088,13 +34377,13 @@ function commandImageBackend(options) {
|
|
|
34088
34377
|
}
|
|
34089
34378
|
};
|
|
34090
34379
|
}
|
|
34091
|
-
var
|
|
34380
|
+
var import_node_child_process43, import_node_crypto37, import_node_fs57;
|
|
34092
34381
|
var init_image_command = __esm({
|
|
34093
34382
|
"src/core/preview/image-command.ts"() {
|
|
34094
34383
|
"use strict";
|
|
34095
|
-
|
|
34096
|
-
|
|
34097
|
-
|
|
34384
|
+
import_node_child_process43 = require("child_process");
|
|
34385
|
+
import_node_crypto37 = require("crypto");
|
|
34386
|
+
import_node_fs57 = __toESM(require("fs"));
|
|
34098
34387
|
init_images();
|
|
34099
34388
|
init_state();
|
|
34100
34389
|
}
|
|
@@ -34787,9 +35076,9 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
34787
35076
|
const resource = resources.get(id5);
|
|
34788
35077
|
if (!resource?.ports?.some((item) => item.name === port && item.public))
|
|
34789
35078
|
throw new Error("Northflank origin binding requires a selected public port.");
|
|
34790
|
-
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0,
|
|
35079
|
+
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0, import_node_crypto38.createHash)("sha256").update(id5).digest("hex").slice(0, 6)}.${policy.baseDomain}`;
|
|
34791
35080
|
};
|
|
34792
|
-
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0,
|
|
35081
|
+
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0, import_node_crypto38.createHash)("sha256").update(id5).digest("hex").slice(0, 10)}`;
|
|
34793
35082
|
const suffix = (value) => {
|
|
34794
35083
|
if (value === void 0) return "";
|
|
34795
35084
|
if (typeof value !== "string" || value.length > 1024 || !value.startsWith("/") || value.startsWith("//") || value.includes("\\") || new RegExp("\\s|\\p{Cc}", "u").test(value))
|
|
@@ -35216,7 +35505,7 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35216
35505
|
]
|
|
35217
35506
|
}
|
|
35218
35507
|
};
|
|
35219
|
-
const digest5 = (0,
|
|
35508
|
+
const digest5 = (0, import_node_crypto38.createHash)("sha256").update(JSON.stringify({ spec, runtimeSecrets })).digest("hex");
|
|
35220
35509
|
return {
|
|
35221
35510
|
spec,
|
|
35222
35511
|
digest: digest5,
|
|
@@ -35227,11 +35516,11 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35227
35516
|
publicBuildEnvironment
|
|
35228
35517
|
};
|
|
35229
35518
|
}
|
|
35230
|
-
var
|
|
35519
|
+
var import_node_crypto38, import_node_net5, ALLOCATION_PLAN, DATABASE_NAME, SOURCE_NAME, MAX_SOURCE_NAMES, MAX_OUTPUTS, MAX_SECRET_GROUPS, MAX_OUTPUT_ARGUMENTS, MAX_OUTPUT_ARGUMENT_BYTES, MAX_OUTPUT_COMMAND_BYTES, MAX_OUTPUT_BYTES2, MAX_PATTERN_BYTES, boundedStorage;
|
|
35231
35520
|
var init_northflank_graph = __esm({
|
|
35232
35521
|
"src/core/preview/providers/northflank-graph.ts"() {
|
|
35233
35522
|
"use strict";
|
|
35234
|
-
|
|
35523
|
+
import_node_crypto38 = require("crypto");
|
|
35235
35524
|
import_node_net5 = require("net");
|
|
35236
35525
|
ALLOCATION_PLAN = /^[a-zA-Z0-9-]{3,100}$/;
|
|
35237
35526
|
DATABASE_NAME = /^[a-z][a-z0-9_]{0,62}$/;
|
|
@@ -35335,7 +35624,7 @@ function specDigest(value) {
|
|
|
35335
35624
|
return digest3(definition(value));
|
|
35336
35625
|
}
|
|
35337
35626
|
function digest3(value) {
|
|
35338
|
-
return (0,
|
|
35627
|
+
return (0, import_node_crypto39.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
35339
35628
|
}
|
|
35340
35629
|
function bindings(owned) {
|
|
35341
35630
|
return {
|
|
@@ -35360,11 +35649,11 @@ function outputNames(graph) {
|
|
|
35360
35649
|
)
|
|
35361
35650
|
].sort();
|
|
35362
35651
|
}
|
|
35363
|
-
var
|
|
35652
|
+
var import_node_crypto39, resourceKinds, NorthflankOwnershipStore, northflankQualificationKeys, NorthflankFailure, NorthflankFenced, NorthflankPreviewProvider, nativeKinds, emptySpec;
|
|
35364
35653
|
var init_northflank = __esm({
|
|
35365
35654
|
"src/core/preview/providers/northflank.ts"() {
|
|
35366
35655
|
"use strict";
|
|
35367
|
-
|
|
35656
|
+
import_node_crypto39 = require("crypto");
|
|
35368
35657
|
init_command();
|
|
35369
35658
|
init_state();
|
|
35370
35659
|
init_northflank_api();
|
|
@@ -35997,7 +36286,7 @@ var init_northflank = __esm({
|
|
|
35997
36286
|
const settings = this.options.graph.generated?.[name];
|
|
35998
36287
|
if (!settings)
|
|
35999
36288
|
throw new NorthflankFailure("Northflank generated value is undeclared.");
|
|
36000
|
-
value = (0,
|
|
36289
|
+
value = (0, import_node_crypto39.randomBytes)(settings.bytes).toString(settings.encoding);
|
|
36001
36290
|
}
|
|
36002
36291
|
if (kind === "output" && value === void 0)
|
|
36003
36292
|
throw new NorthflankFailure("Northflank output has no verified recipient.");
|
|
@@ -36500,10 +36789,10 @@ __export(installation_exports, {
|
|
|
36500
36789
|
loadPreviewInstallation: () => loadPreviewInstallation
|
|
36501
36790
|
});
|
|
36502
36791
|
function readFile(file) {
|
|
36503
|
-
const stat =
|
|
36792
|
+
const stat = import_node_fs58.default.lstatSync(file);
|
|
36504
36793
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
|
|
36505
36794
|
throw new Error("Preview control files must be regular files of at most 1 MiB.");
|
|
36506
|
-
return
|
|
36795
|
+
return import_node_fs58.default.readFileSync(file, "utf8");
|
|
36507
36796
|
}
|
|
36508
36797
|
function text5(value, pattern) {
|
|
36509
36798
|
if (typeof value !== "string" || !pattern.test(value))
|
|
@@ -36516,7 +36805,7 @@ function integer2(value, min, max) {
|
|
|
36516
36805
|
return value;
|
|
36517
36806
|
}
|
|
36518
36807
|
function loadPreviewInstallation(filename, options = {}) {
|
|
36519
|
-
const root = import_node_path70.default.dirname(
|
|
36808
|
+
const root = import_node_path70.default.dirname(import_node_fs58.default.realpathSync(filename));
|
|
36520
36809
|
const raw = object5(JSON.parse(readFile(filename)), [
|
|
36521
36810
|
"version",
|
|
36522
36811
|
"installationId",
|
|
@@ -36599,7 +36888,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36599
36888
|
const control = (input3) => {
|
|
36600
36889
|
const ref2 = object5(input3, ["file", "sha256"]);
|
|
36601
36890
|
const filename2 = text5(ref2.file, /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/);
|
|
36602
|
-
const file =
|
|
36891
|
+
const file = import_node_fs58.default.realpathSync(import_node_path70.default.join(root, filename2));
|
|
36603
36892
|
if (!file.startsWith(`${root}${import_node_path70.default.sep}`))
|
|
36604
36893
|
throw new Error("Preview control file escapes installation directory.");
|
|
36605
36894
|
const source = readFile(file), expected = text5(ref2.sha256, /^[a-f0-9]{64}$/);
|
|
@@ -36662,7 +36951,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36662
36951
|
return credential(secrets[ref2])();
|
|
36663
36952
|
},
|
|
36664
36953
|
accept: async (entry, urls) => {
|
|
36665
|
-
const result = (0,
|
|
36954
|
+
const result = (0, import_node_child_process44.spawnSync)(command[0], command.slice(1), {
|
|
36666
36955
|
cwd: root,
|
|
36667
36956
|
shell: false,
|
|
36668
36957
|
timeout: 3e4,
|
|
@@ -36724,7 +37013,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36724
37013
|
const item = object5(input3, ["file", "sha256"]);
|
|
36725
37014
|
const verified = control(input3);
|
|
36726
37015
|
return {
|
|
36727
|
-
path:
|
|
37016
|
+
path: import_node_fs58.default.realpathSync(import_node_path70.default.join(root, item.file)),
|
|
36728
37017
|
sha256: verified.digest
|
|
36729
37018
|
};
|
|
36730
37019
|
}) : [];
|
|
@@ -36839,7 +37128,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36839
37128
|
}
|
|
36840
37129
|
},
|
|
36841
37130
|
now,
|
|
36842
|
-
workerId: (0,
|
|
37131
|
+
workerId: (0, import_node_crypto40.randomUUID)(),
|
|
36843
37132
|
policy: {
|
|
36844
37133
|
installationId,
|
|
36845
37134
|
maxActive,
|
|
@@ -36955,13 +37244,13 @@ async function initializePreviewInstallation(installationId, store) {
|
|
|
36955
37244
|
await store.compareAndSwap(witnessKey, null, { installationId });
|
|
36956
37245
|
await store.compareAndSwap(poolKey, null, createPreviewPool(installationId));
|
|
36957
37246
|
}
|
|
36958
|
-
var
|
|
37247
|
+
var import_node_child_process44, import_node_crypto40, import_node_fs58, import_node_path70, MAX_COMMAND_AGE_MS, digest4, envName;
|
|
36959
37248
|
var init_installation = __esm({
|
|
36960
37249
|
"src/core/preview/installation.ts"() {
|
|
36961
37250
|
"use strict";
|
|
36962
|
-
|
|
36963
|
-
|
|
36964
|
-
|
|
37251
|
+
import_node_child_process44 = require("child_process");
|
|
37252
|
+
import_node_crypto40 = require("crypto");
|
|
37253
|
+
import_node_fs58 = __toESM(require("fs"));
|
|
36965
37254
|
import_node_path70 = __toESM(require("path"));
|
|
36966
37255
|
init_repo_config();
|
|
36967
37256
|
init_command();
|
|
@@ -36979,7 +37268,7 @@ var init_installation = __esm({
|
|
|
36979
37268
|
init_state();
|
|
36980
37269
|
init_azure_blob();
|
|
36981
37270
|
MAX_COMMAND_AGE_MS = 15 * 6e4;
|
|
36982
|
-
digest4 = (source) => (0,
|
|
37271
|
+
digest4 = (source) => (0, import_node_crypto40.createHash)("sha256").update(source).digest("hex");
|
|
36983
37272
|
envName = (value) => {
|
|
36984
37273
|
if (typeof value !== "string" || !/^DEVROUTER_PREVIEW_[A-Z0-9_]+$/.test(value))
|
|
36985
37274
|
throw new Error("Preview credential references require scoped environment names.");
|
|
@@ -36998,14 +37287,14 @@ __export(preview_exports, {
|
|
|
36998
37287
|
function readSource(repoPath, filename) {
|
|
36999
37288
|
if (import_node_path71.default.isAbsolute(filename))
|
|
37000
37289
|
throw new Error("Preview source path must be repository-relative.");
|
|
37001
|
-
const root =
|
|
37290
|
+
const root = import_node_fs59.default.realpathSync(repoPath);
|
|
37002
37291
|
const file = assertPathWithinRepo(filename, root, "preview source");
|
|
37003
|
-
const stat =
|
|
37292
|
+
const stat = import_node_fs59.default.lstatSync(file);
|
|
37004
37293
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 1024 * 1024) {
|
|
37005
37294
|
throw new Error("Preview source must be a regular file of at most 1 MiB.");
|
|
37006
37295
|
}
|
|
37007
|
-
assertPathWithinRepo(
|
|
37008
|
-
return JSON.parse(
|
|
37296
|
+
assertPathWithinRepo(import_node_fs59.default.realpathSync(file), root, "preview source");
|
|
37297
|
+
return JSON.parse(import_node_fs59.default.readFileSync(file, "utf8"));
|
|
37009
37298
|
}
|
|
37010
37299
|
async function runPreviewPlanCommand(options) {
|
|
37011
37300
|
const repoPath = resolveRepoPath(options.repo);
|
|
@@ -37020,13 +37309,13 @@ async function runPreviewPlanCommand(options) {
|
|
|
37020
37309
|
`);
|
|
37021
37310
|
return;
|
|
37022
37311
|
}
|
|
37023
|
-
const localConfig =
|
|
37312
|
+
const localConfig = import_node_fs59.default.readFileSync(import_node_path71.default.join(repoPath, ".devrouter.yml"), "utf8");
|
|
37024
37313
|
const report = buildPreviewPlan({
|
|
37025
37314
|
repoPath,
|
|
37026
37315
|
config: loadRepoConfig(repoPath, () => localConfig),
|
|
37027
37316
|
manifest,
|
|
37028
37317
|
manifestDigest: digest5,
|
|
37029
|
-
localConfigDigest: (0,
|
|
37318
|
+
localConfigDigest: (0, import_node_crypto41.createHash)("sha256").update(localConfig).digest("hex"),
|
|
37030
37319
|
...options.alias === void 0 ? {} : { aliases: options.alias.split(",") },
|
|
37031
37320
|
...options.source === void 0 ? {} : { source: readSource(repoPath, options.source) }
|
|
37032
37321
|
});
|
|
@@ -37045,7 +37334,7 @@ async function runPreviewPlanCommand(options) {
|
|
|
37045
37334
|
}
|
|
37046
37335
|
}
|
|
37047
37336
|
async function runPreviewInitCommand(options) {
|
|
37048
|
-
const repoPath =
|
|
37337
|
+
const repoPath = import_node_fs59.default.realpathSync(resolveRepoPath(options.repo));
|
|
37049
37338
|
if (options.integration === "gitlab") return renderGitLabPreviewIntegration(repoPath, options);
|
|
37050
37339
|
if (options.integration) return renderPreviewIntegration(repoPath, options);
|
|
37051
37340
|
loadRepoConfig(repoPath);
|
|
@@ -37071,7 +37360,7 @@ async function runPreviewInitCommand(options) {
|
|
|
37071
37360
|
const content = (0, import_yaml12.stringify)(manifest);
|
|
37072
37361
|
if (options.write) {
|
|
37073
37362
|
const file = import_node_path71.default.join(repoPath, ".devrouter.preview.yml");
|
|
37074
|
-
|
|
37363
|
+
import_node_fs59.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37075
37364
|
}
|
|
37076
37365
|
if (options.json) {
|
|
37077
37366
|
printJSON({
|
|
@@ -37139,9 +37428,9 @@ function previewAsset(name) {
|
|
|
37139
37428
|
import_node_path71.default.resolve(__dirname, "..", "assets", "preview", name),
|
|
37140
37429
|
import_node_path71.default.resolve(__dirname, "..", "..", "assets", "preview", name)
|
|
37141
37430
|
];
|
|
37142
|
-
const file = candidates.find((file2) =>
|
|
37431
|
+
const file = candidates.find((file2) => import_node_fs59.default.existsSync(file2));
|
|
37143
37432
|
if (!file) throw new Error("Installed preview integration asset is missing.");
|
|
37144
|
-
return
|
|
37433
|
+
return import_node_fs59.default.readFileSync(file, "utf8");
|
|
37145
37434
|
}
|
|
37146
37435
|
function renderPreviewAsset(name, replacements) {
|
|
37147
37436
|
return previewAsset(name).replace(/__([A-Z_]+)__/g, (_match, key) => {
|
|
@@ -37176,9 +37465,9 @@ async function renderPreviewIntegration(repoPath, options) {
|
|
|
37176
37465
|
const filename = `.github/workflows/devrouter-preview${options.sweeper ? "-sweep" : ""}.yml`;
|
|
37177
37466
|
if (options.write) {
|
|
37178
37467
|
const file = assertPathWithinRepo(filename, repoPath, "preview workflow");
|
|
37179
|
-
|
|
37180
|
-
assertPathWithinRepo(
|
|
37181
|
-
|
|
37468
|
+
import_node_fs59.default.mkdirSync(import_node_path71.default.dirname(file), { recursive: true });
|
|
37469
|
+
assertPathWithinRepo(import_node_fs59.default.realpathSync(import_node_path71.default.dirname(file)), repoPath, "preview workflow parent");
|
|
37470
|
+
import_node_fs59.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37182
37471
|
}
|
|
37183
37472
|
if (options.json)
|
|
37184
37473
|
printJSON({
|
|
@@ -37196,7 +37485,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37196
37485
|
throw new Error(
|
|
37197
37486
|
"GitLab integration requires reviewed --controller-ref and --controller-image digest."
|
|
37198
37487
|
);
|
|
37199
|
-
const integrity = `sha256-${(0,
|
|
37488
|
+
const integrity = `sha256-${(0, import_node_crypto41.createHash)("sha256").update(previewAsset("gitlab-template.yml")).digest("base64")}`;
|
|
37200
37489
|
const replacements = {
|
|
37201
37490
|
CONTROLLER_REF: String(options.controllerRef),
|
|
37202
37491
|
CONTROLLER_IMAGE: String(options.controllerImage),
|
|
@@ -37205,7 +37494,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37205
37494
|
const content = renderPreviewAsset("gitlab.yml", replacements);
|
|
37206
37495
|
const filename = ".gitlab-ci.yml";
|
|
37207
37496
|
if (options.write)
|
|
37208
|
-
|
|
37497
|
+
import_node_fs59.default.writeFileSync(assertPathWithinRepo(filename, repoPath, "GitLab preview caller"), content, {
|
|
37209
37498
|
flag: "wx",
|
|
37210
37499
|
mode: 384
|
|
37211
37500
|
});
|
|
@@ -37220,12 +37509,12 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37220
37509
|
});
|
|
37221
37510
|
else process.stdout.write(content);
|
|
37222
37511
|
}
|
|
37223
|
-
var
|
|
37512
|
+
var import_node_crypto41, import_node_fs59, import_node_path71, import_yaml12;
|
|
37224
37513
|
var init_preview = __esm({
|
|
37225
37514
|
"src/commands/preview.ts"() {
|
|
37226
37515
|
"use strict";
|
|
37227
|
-
|
|
37228
|
-
|
|
37516
|
+
import_node_crypto41 = require("crypto");
|
|
37517
|
+
import_node_fs59 = __toESM(require("fs"));
|
|
37229
37518
|
import_node_path71 = __toESM(require("path"));
|
|
37230
37519
|
import_yaml12 = require("yaml");
|
|
37231
37520
|
init_output();
|
|
@@ -37518,7 +37807,7 @@ function sanitizeRouterId(value) {
|
|
|
37518
37807
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
37519
37808
|
}
|
|
37520
37809
|
function repoHash(repoPath) {
|
|
37521
|
-
return (0,
|
|
37810
|
+
return (0, import_node_crypto42.createHash)("sha1").update(import_node_path72.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
37522
37811
|
}
|
|
37523
37812
|
function asDockerApp(app) {
|
|
37524
37813
|
return app.runtime === "docker";
|
|
@@ -37598,10 +37887,10 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
37598
37887
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
37599
37888
|
}
|
|
37600
37889
|
const cachePath = import_node_path72.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
37601
|
-
|
|
37890
|
+
import_node_fs60.default.mkdirSync(cachePath, { recursive: true });
|
|
37602
37891
|
const overlayPath = import_node_path72.default.join(cachePath, "compose.devrouter.yml");
|
|
37603
37892
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
37604
|
-
|
|
37893
|
+
import_node_fs60.default.writeFileSync(overlayPath, import_yaml13.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
37605
37894
|
return {
|
|
37606
37895
|
overlayPath,
|
|
37607
37896
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -37615,7 +37904,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37615
37904
|
fileArgs.push("-f", resolved2);
|
|
37616
37905
|
}
|
|
37617
37906
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
37618
|
-
const result = (0,
|
|
37907
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37619
37908
|
encoding: "utf-8",
|
|
37620
37909
|
cwd: repoPath
|
|
37621
37910
|
});
|
|
@@ -37643,7 +37932,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
37643
37932
|
"--services",
|
|
37644
37933
|
...services
|
|
37645
37934
|
];
|
|
37646
|
-
const result = (0,
|
|
37935
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37647
37936
|
encoding: "utf-8",
|
|
37648
37937
|
cwd: repoPath
|
|
37649
37938
|
});
|
|
@@ -37669,7 +37958,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37669
37958
|
fileArgs.push("-f", resolved2);
|
|
37670
37959
|
}
|
|
37671
37960
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
37672
|
-
const result = (0,
|
|
37961
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37673
37962
|
encoding: "utf-8",
|
|
37674
37963
|
cwd: repoPath
|
|
37675
37964
|
});
|
|
@@ -37695,7 +37984,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
37695
37984
|
String(tail),
|
|
37696
37985
|
...services
|
|
37697
37986
|
];
|
|
37698
|
-
(0,
|
|
37987
|
+
(0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37699
37988
|
stdio: "inherit",
|
|
37700
37989
|
cwd: repoPath
|
|
37701
37990
|
});
|
|
@@ -37707,7 +37996,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37707
37996
|
fileArgs.push("-f", resolved2);
|
|
37708
37997
|
}
|
|
37709
37998
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
37710
|
-
const result = (0,
|
|
37999
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37711
38000
|
encoding: "utf-8",
|
|
37712
38001
|
cwd: repoPath
|
|
37713
38002
|
});
|
|
@@ -37721,13 +38010,13 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37721
38010
|
const port = Number(match[1]);
|
|
37722
38011
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
37723
38012
|
}
|
|
37724
|
-
var
|
|
38013
|
+
var import_node_child_process45, import_node_crypto42, import_node_fs60, import_node_path72, import_yaml13;
|
|
37725
38014
|
var init_docker_run = __esm({
|
|
37726
38015
|
"src/core/docker-run.ts"() {
|
|
37727
38016
|
"use strict";
|
|
37728
|
-
|
|
37729
|
-
|
|
37730
|
-
|
|
38017
|
+
import_node_child_process45 = require("child_process");
|
|
38018
|
+
import_node_crypto42 = require("crypto");
|
|
38019
|
+
import_node_fs60 = __toESM(require("fs"));
|
|
37731
38020
|
import_node_path72 = __toESM(require("path"));
|
|
37732
38021
|
import_yaml13 = __toESM(require("yaml"));
|
|
37733
38022
|
init_docker_error_guidance();
|
|
@@ -37818,7 +38107,7 @@ function isProcessRunning(pid) {
|
|
|
37818
38107
|
}
|
|
37819
38108
|
}
|
|
37820
38109
|
function readProcessTree(rootPid) {
|
|
37821
|
-
const result = (0,
|
|
38110
|
+
const result = (0, import_node_child_process46.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
37822
38111
|
if (result.status !== 0) {
|
|
37823
38112
|
return [rootPid];
|
|
37824
38113
|
}
|
|
@@ -37929,12 +38218,12 @@ function detectListeningPorts(pids) {
|
|
|
37929
38218
|
if (pids.length === 0) {
|
|
37930
38219
|
return [];
|
|
37931
38220
|
}
|
|
37932
|
-
const result = (0,
|
|
38221
|
+
const result = (0, import_node_child_process46.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
37933
38222
|
encoding: "utf-8"
|
|
37934
38223
|
});
|
|
37935
38224
|
if (result.error && result.error.code === "ENOENT") {
|
|
37936
38225
|
if (process.platform === "linux") {
|
|
37937
|
-
const ssResult = (0,
|
|
38226
|
+
const ssResult = (0, import_node_child_process46.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
37938
38227
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
37939
38228
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
37940
38229
|
}
|
|
@@ -37993,7 +38282,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
37993
38282
|
app.hostRun.command,
|
|
37994
38283
|
true
|
|
37995
38284
|
) : app.hostRun.command;
|
|
37996
|
-
const child = (0,
|
|
38285
|
+
const child = (0, import_node_child_process46.spawn)(spawnCommand, {
|
|
37997
38286
|
cwd: commandCwd,
|
|
37998
38287
|
stdio: "inherit",
|
|
37999
38288
|
shell: true,
|
|
@@ -38361,7 +38650,7 @@ async function execWithAppEnv(options) {
|
|
|
38361
38650
|
options.command[0],
|
|
38362
38651
|
true
|
|
38363
38652
|
);
|
|
38364
|
-
child = (0,
|
|
38653
|
+
child = (0, import_node_child_process46.spawn)(wrapped, {
|
|
38365
38654
|
cwd: deps.repoPath,
|
|
38366
38655
|
stdio: "inherit",
|
|
38367
38656
|
shell: true,
|
|
@@ -38375,7 +38664,7 @@ async function execWithAppEnv(options) {
|
|
|
38375
38664
|
false
|
|
38376
38665
|
);
|
|
38377
38666
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
38378
|
-
child = (0,
|
|
38667
|
+
child = (0, import_node_child_process46.spawn)(cmd, wrappedArgs, {
|
|
38379
38668
|
cwd: deps.repoPath,
|
|
38380
38669
|
stdio: "inherit",
|
|
38381
38670
|
shell: false,
|
|
@@ -38383,7 +38672,7 @@ async function execWithAppEnv(options) {
|
|
|
38383
38672
|
});
|
|
38384
38673
|
}
|
|
38385
38674
|
} else if (options.shell) {
|
|
38386
|
-
child = (0,
|
|
38675
|
+
child = (0, import_node_child_process46.spawn)(options.command[0], {
|
|
38387
38676
|
cwd: deps.repoPath,
|
|
38388
38677
|
stdio: "inherit",
|
|
38389
38678
|
shell: true,
|
|
@@ -38391,7 +38680,7 @@ async function execWithAppEnv(options) {
|
|
|
38391
38680
|
});
|
|
38392
38681
|
} else {
|
|
38393
38682
|
const [command, ...args] = options.command;
|
|
38394
|
-
child = (0,
|
|
38683
|
+
child = (0, import_node_child_process46.spawn)(command, args, {
|
|
38395
38684
|
cwd: deps.repoPath,
|
|
38396
38685
|
stdio: "inherit",
|
|
38397
38686
|
shell: false,
|
|
@@ -38412,11 +38701,11 @@ async function execWithAppEnv(options) {
|
|
|
38412
38701
|
deps.stopDeps();
|
|
38413
38702
|
}
|
|
38414
38703
|
}
|
|
38415
|
-
var
|
|
38704
|
+
var import_node_child_process46, import_node_net6, import_node_process, import_promises, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
|
|
38416
38705
|
var init_app_run = __esm({
|
|
38417
38706
|
"src/core/app-run.ts"() {
|
|
38418
38707
|
"use strict";
|
|
38419
|
-
|
|
38708
|
+
import_node_child_process46 = require("child_process");
|
|
38420
38709
|
import_node_net6 = __toESM(require("net"));
|
|
38421
38710
|
import_node_process = require("process");
|
|
38422
38711
|
import_promises = require("readline/promises");
|
|
@@ -38562,7 +38851,7 @@ function canonicalJson(value) {
|
|
|
38562
38851
|
`;
|
|
38563
38852
|
}
|
|
38564
38853
|
function sha256Hex(raw) {
|
|
38565
|
-
return (0,
|
|
38854
|
+
return (0, import_node_crypto43.createHash)("sha256").update(raw).digest("hex");
|
|
38566
38855
|
}
|
|
38567
38856
|
function candidateId(candidate) {
|
|
38568
38857
|
const identity2 = {
|
|
@@ -38730,7 +39019,7 @@ function validateManifest(value) {
|
|
|
38730
39019
|
return root;
|
|
38731
39020
|
}
|
|
38732
39021
|
function readManifest(file) {
|
|
38733
|
-
const raw =
|
|
39022
|
+
const raw = import_node_fs61.default.readFileSync(file);
|
|
38734
39023
|
let parsed;
|
|
38735
39024
|
try {
|
|
38736
39025
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -38769,7 +39058,7 @@ function selectManifest(file, expectedSha256, ids2) {
|
|
|
38769
39058
|
return canonicalJson(subset);
|
|
38770
39059
|
}
|
|
38771
39060
|
function gitLine(cwd, args) {
|
|
38772
|
-
const result = (0,
|
|
39061
|
+
const result = (0, import_node_child_process47.spawnSync)("git", ["-C", cwd, ...args], {
|
|
38773
39062
|
encoding: "utf-8",
|
|
38774
39063
|
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
38775
39064
|
});
|
|
@@ -38777,7 +39066,7 @@ function gitLine(cwd, args) {
|
|
|
38777
39066
|
return result.status === 0 && !result.error && output2 ? output2 : void 0;
|
|
38778
39067
|
}
|
|
38779
39068
|
function readWorktreeIdentity(worktreePath) {
|
|
38780
|
-
if (!
|
|
39069
|
+
if (!import_node_fs61.default.existsSync(worktreePath)) return void 0;
|
|
38781
39070
|
const real = comparableWorkspacePath(worktreePath);
|
|
38782
39071
|
const commonDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
38783
39072
|
const gitDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-dir"]);
|
|
@@ -38803,7 +39092,7 @@ function unmanagedActivityEpoch(worktreePath, gitDir) {
|
|
|
38803
39092
|
worktreePath
|
|
38804
39093
|
]) {
|
|
38805
39094
|
try {
|
|
38806
|
-
const seconds = Math.floor(
|
|
39095
|
+
const seconds = Math.floor(import_node_fs61.default.statSync(file).mtimeMs / 1e3);
|
|
38807
39096
|
latest = latest === void 0 ? seconds : Math.max(latest, seconds);
|
|
38808
39097
|
} catch {
|
|
38809
39098
|
}
|
|
@@ -38862,7 +39151,7 @@ function receiptPath(commonDir, manifestSha256, id5) {
|
|
|
38862
39151
|
function matchingReceipt(candidate, manifestSha256) {
|
|
38863
39152
|
try {
|
|
38864
39153
|
const receipt = JSON.parse(
|
|
38865
|
-
|
|
39154
|
+
import_node_fs61.default.readFileSync(receiptPath(candidate.commonDir, manifestSha256, candidate.id), "utf-8")
|
|
38866
39155
|
);
|
|
38867
39156
|
return receipt.kind === RECEIPT_KIND && receipt.schemaVersion === SCHEMA_VERSION && receipt.manifestSha256 === manifestSha256 && receipt.candidateId === candidate.id && receipt.path === candidate.path && receipt.head === candidate.head;
|
|
38868
39157
|
} catch {
|
|
@@ -38871,7 +39160,7 @@ function matchingReceipt(candidate, manifestSha256) {
|
|
|
38871
39160
|
}
|
|
38872
39161
|
function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
38873
39162
|
const file = receiptPath(candidate.commonDir, manifestSha256, candidate.id);
|
|
38874
|
-
|
|
39163
|
+
import_node_fs61.default.mkdirSync(import_node_path73.default.dirname(file), { recursive: true });
|
|
38875
39164
|
writeFileAtomically(
|
|
38876
39165
|
file,
|
|
38877
39166
|
canonicalJson({
|
|
@@ -38889,7 +39178,7 @@ function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
|
38889
39178
|
);
|
|
38890
39179
|
}
|
|
38891
39180
|
function runVetoCommand(command, worktreePath) {
|
|
38892
|
-
const result = (0,
|
|
39181
|
+
const result = (0, import_node_child_process47.spawnSync)(command, [worktreePath], {
|
|
38893
39182
|
stdio: ["ignore", "ignore", "inherit"],
|
|
38894
39183
|
timeout: VETO_TIMEOUT_MS
|
|
38895
39184
|
});
|
|
@@ -38904,7 +39193,7 @@ function runVetoCommand(command, worktreePath) {
|
|
|
38904
39193
|
function assertVetoCommand(command) {
|
|
38905
39194
|
if (!import_node_path73.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
|
|
38906
39195
|
try {
|
|
38907
|
-
|
|
39196
|
+
import_node_fs61.default.accessSync(command, import_node_fs61.default.constants.X_OK);
|
|
38908
39197
|
} catch {
|
|
38909
39198
|
throw new Error(`--veto-command '${command}' is missing or not executable`);
|
|
38910
39199
|
}
|
|
@@ -38930,7 +39219,7 @@ function preflightManifestApply(options, action2, nowEpoch) {
|
|
|
38930
39219
|
return { manifest, manifestSha256, now };
|
|
38931
39220
|
}
|
|
38932
39221
|
function deleteBranchIfUnmoved(candidate, steps) {
|
|
38933
|
-
const exists2 = (0,
|
|
39222
|
+
const exists2 = (0, import_node_child_process47.spawnSync)(
|
|
38934
39223
|
"git",
|
|
38935
39224
|
["-C", candidate.repo, "show-ref", "--verify", "--quiet", candidate.branchRef],
|
|
38936
39225
|
{ encoding: "utf-8" }
|
|
@@ -38939,7 +39228,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38939
39228
|
if (exists2.status !== 0) {
|
|
38940
39229
|
throw new Error(`cannot read branch ${candidate.branch}: ${(exists2.stderr ?? "").trim()}`);
|
|
38941
39230
|
}
|
|
38942
|
-
const result = (0,
|
|
39231
|
+
const result = (0, import_node_child_process47.spawnSync)(
|
|
38943
39232
|
"git",
|
|
38944
39233
|
["-C", candidate.repo, "update-ref", "-d", candidate.branchRef, candidate.head],
|
|
38945
39234
|
{ encoding: "utf-8" }
|
|
@@ -38948,7 +39237,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38948
39237
|
return `branch ${candidate.branch} no longer points at the approved HEAD; it was kept for review`;
|
|
38949
39238
|
}
|
|
38950
39239
|
steps.push("branch-deleted");
|
|
38951
|
-
(0,
|
|
39240
|
+
(0, import_node_child_process47.spawnSync)(
|
|
38952
39241
|
"git",
|
|
38953
39242
|
["-C", candidate.repo, "config", "--remove-section", `branch.${candidate.branch}`],
|
|
38954
39243
|
{ encoding: "utf-8" }
|
|
@@ -38986,7 +39275,7 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38986
39275
|
outcome.status = "not-attempted";
|
|
38987
39276
|
continue;
|
|
38988
39277
|
}
|
|
38989
|
-
if (!
|
|
39278
|
+
if (!import_node_fs61.default.existsSync(candidate.path) && matchingReceipt(candidate, manifestSha256)) {
|
|
38990
39279
|
outcome.status = "already-done";
|
|
38991
39280
|
continue;
|
|
38992
39281
|
}
|
|
@@ -39055,13 +39344,13 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
39055
39344
|
}
|
|
39056
39345
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
39057
39346
|
}
|
|
39058
|
-
var
|
|
39347
|
+
var import_node_child_process47, import_node_crypto43, import_node_fs61, import_node_path73, MANIFEST_KIND, LEGACY_MANIFEST_KIND, RECEIPT_KIND, SCHEMA_VERSION, HEX_SHA, HEX_ID, VETO_TIMEOUT_MS, FUTURE_TOLERANCE_SECONDS, ROOT_KEYS, SESSION_ROOT_KEYS, LEGACY_ROOT_KEYS, CANDIDATE_KEYS, SESSION_CANDIDATE_KEYS, OPTIONAL_CANDIDATE_KEYS, ReclaimSkip;
|
|
39059
39348
|
var init_worktree_reclaim = __esm({
|
|
39060
39349
|
"src/core/worktree-reclaim.ts"() {
|
|
39061
39350
|
"use strict";
|
|
39062
|
-
|
|
39063
|
-
|
|
39064
|
-
|
|
39351
|
+
import_node_child_process47 = require("child_process");
|
|
39352
|
+
import_node_crypto43 = require("crypto");
|
|
39353
|
+
import_node_fs61 = __toESM(require("fs"));
|
|
39065
39354
|
import_node_path73 = __toESM(require("path"));
|
|
39066
39355
|
init_atomic_file();
|
|
39067
39356
|
init_workspace();
|
|
@@ -39326,14 +39615,14 @@ function readLeftoverContext(repoPath) {
|
|
|
39326
39615
|
registriesReadable: snapshots.unavailable.length === 0,
|
|
39327
39616
|
realpath: (file) => {
|
|
39328
39617
|
try {
|
|
39329
|
-
return
|
|
39618
|
+
return import_node_fs62.default.realpathSync.native(file);
|
|
39330
39619
|
} catch {
|
|
39331
39620
|
return void 0;
|
|
39332
39621
|
}
|
|
39333
39622
|
},
|
|
39334
39623
|
exists: (file) => {
|
|
39335
39624
|
try {
|
|
39336
|
-
|
|
39625
|
+
import_node_fs62.default.lstatSync(file);
|
|
39337
39626
|
return true;
|
|
39338
39627
|
} catch (error) {
|
|
39339
39628
|
return error.code !== "ENOENT";
|
|
@@ -39457,7 +39746,7 @@ function validateLeftoverManifest(value) {
|
|
|
39457
39746
|
return root;
|
|
39458
39747
|
}
|
|
39459
39748
|
function readLeftoverManifest(file) {
|
|
39460
|
-
const raw =
|
|
39749
|
+
const raw = import_node_fs62.default.readFileSync(file);
|
|
39461
39750
|
let parsed;
|
|
39462
39751
|
try {
|
|
39463
39752
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -39471,7 +39760,7 @@ function readLeftoverManifest(file) {
|
|
|
39471
39760
|
return { raw, manifest };
|
|
39472
39761
|
}
|
|
39473
39762
|
function gitCommonDir(repo) {
|
|
39474
|
-
const result = (0,
|
|
39763
|
+
const result = (0, import_node_child_process48.spawnSync)(
|
|
39475
39764
|
"git",
|
|
39476
39765
|
["-C", repo, "rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
39477
39766
|
{ encoding: "utf-8" }
|
|
@@ -39643,7 +39932,7 @@ function leftoverReceiptPath(commonDir, manifestSha256, id5) {
|
|
|
39643
39932
|
}
|
|
39644
39933
|
function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEpoch) {
|
|
39645
39934
|
const file = leftoverReceiptPath(commonDir, manifestSha256, candidate.id);
|
|
39646
|
-
|
|
39935
|
+
import_node_fs62.default.mkdirSync(import_node_path74.default.dirname(file), { recursive: true });
|
|
39647
39936
|
writeFileAtomically(
|
|
39648
39937
|
file,
|
|
39649
39938
|
canonicalJson({
|
|
@@ -39659,12 +39948,12 @@ function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEp
|
|
|
39659
39948
|
})
|
|
39660
39949
|
);
|
|
39661
39950
|
}
|
|
39662
|
-
var
|
|
39951
|
+
var import_node_child_process48, import_node_fs62, import_node_path74, LEFTOVER_MANIFEST_KIND, LEFTOVER_RECEIPT_KIND, SCHEMA_VERSION2, MAX_DOCKER_OBJECTS, FUTURE_TOLERANCE_SECONDS2, PROJECT_LABEL, WORKING_DIR_LABEL, PROVIDER_LABEL, STOPPED_STATES, HEX_ID2, DockerListingBoundError, defaultDockerRunner, LeftoverSkip, defaultWithLocks;
|
|
39663
39952
|
var init_docker_leftovers = __esm({
|
|
39664
39953
|
"src/core/docker-leftovers.ts"() {
|
|
39665
39954
|
"use strict";
|
|
39666
|
-
|
|
39667
|
-
|
|
39955
|
+
import_node_child_process48 = require("child_process");
|
|
39956
|
+
import_node_fs62 = __toESM(require("fs"));
|
|
39668
39957
|
import_node_path74 = __toESM(require("path"));
|
|
39669
39958
|
init_atomic_file();
|
|
39670
39959
|
init_devpod_mutation();
|
|
@@ -39686,7 +39975,7 @@ var init_docker_leftovers = __esm({
|
|
|
39686
39975
|
DockerListingBoundError = class extends Error {
|
|
39687
39976
|
};
|
|
39688
39977
|
defaultDockerRunner = (args) => {
|
|
39689
|
-
const result = (0,
|
|
39978
|
+
const result = (0, import_node_child_process48.spawnSync)("docker", args, {
|
|
39690
39979
|
encoding: "utf-8",
|
|
39691
39980
|
timeout: 6e4,
|
|
39692
39981
|
maxBuffer: 256 * 1024 * 1024
|
|
@@ -39717,13 +40006,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39717
40006
|
const startedAt = Date.now();
|
|
39718
40007
|
let rootStat;
|
|
39719
40008
|
try {
|
|
39720
|
-
rootStat =
|
|
40009
|
+
rootStat = import_node_fs63.default.lstatSync(worktreePath);
|
|
39721
40010
|
} catch (error) {
|
|
39722
40011
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39723
40012
|
}
|
|
39724
40013
|
let rootEntries;
|
|
39725
40014
|
try {
|
|
39726
|
-
rootEntries =
|
|
40015
|
+
rootEntries = import_node_fs63.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
39727
40016
|
} catch (error) {
|
|
39728
40017
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39729
40018
|
}
|
|
@@ -39752,7 +40041,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39752
40041
|
const entryPath = import_node_path75.default.join(dirPath, entry.name);
|
|
39753
40042
|
let entryStat;
|
|
39754
40043
|
try {
|
|
39755
|
-
entryStat =
|
|
40044
|
+
entryStat = import_node_fs63.default.lstatSync(entryPath);
|
|
39756
40045
|
} catch (error) {
|
|
39757
40046
|
if (error?.code === "ENOENT") continue;
|
|
39758
40047
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -39762,7 +40051,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39762
40051
|
if (!entryStat.isDirectory()) continue;
|
|
39763
40052
|
let childEntries;
|
|
39764
40053
|
try {
|
|
39765
|
-
childEntries =
|
|
40054
|
+
childEntries = import_node_fs63.default.readdirSync(entryPath, { withFileTypes: true });
|
|
39766
40055
|
} catch (error) {
|
|
39767
40056
|
unreadableReason = describeIncompleteWalk(error);
|
|
39768
40057
|
break;
|
|
@@ -39826,11 +40115,11 @@ function describeError(error, worktreePath) {
|
|
|
39826
40115
|
}
|
|
39827
40116
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
39828
40117
|
}
|
|
39829
|
-
var
|
|
40118
|
+
var import_node_fs63, import_node_path75, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
39830
40119
|
var init_workspace_consumption = __esm({
|
|
39831
40120
|
"src/core/workspace-consumption.ts"() {
|
|
39832
40121
|
"use strict";
|
|
39833
|
-
|
|
40122
|
+
import_node_fs63 = __toESM(require("fs"));
|
|
39834
40123
|
import_node_path75 = __toESM(require("path"));
|
|
39835
40124
|
init_devpod_environment();
|
|
39836
40125
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
@@ -39917,7 +40206,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
39917
40206
|
}
|
|
39918
40207
|
function readGitSnapshot(worktree, commandRunner) {
|
|
39919
40208
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
39920
|
-
if (worktree.prunable || !
|
|
40209
|
+
if (worktree.prunable || !import_node_fs64.default.existsSync(comparablePath)) {
|
|
39921
40210
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
39922
40211
|
}
|
|
39923
40212
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -40549,7 +40838,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40549
40838
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40550
40839
|
);
|
|
40551
40840
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40552
|
-
const disposable =
|
|
40841
|
+
const disposable = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40553
40842
|
const [primary, ...linked] = worktrees;
|
|
40554
40843
|
const safetyFor = (worktree, worktreePath, evidence) => toSafety(
|
|
40555
40844
|
classify({
|
|
@@ -40557,7 +40846,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40557
40846
|
branch: worktree?.branch,
|
|
40558
40847
|
primary: primary !== void 0 && sameWorkspacePath(primary.path, worktreePath),
|
|
40559
40848
|
locked: worktree?.locked ?? false,
|
|
40560
|
-
missing: !worktree || worktree.prunable || !
|
|
40849
|
+
missing: !worktree || worktree.prunable || !import_node_fs64.default.existsSync(worktreePath),
|
|
40561
40850
|
runtimeEvidence: evidence,
|
|
40562
40851
|
forge,
|
|
40563
40852
|
extraDisposablePatterns: disposable
|
|
@@ -40618,7 +40907,7 @@ function readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies) {
|
|
|
40618
40907
|
}
|
|
40619
40908
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40620
40909
|
const cutoffEpoch = Math.floor(Date.now() / 1e3) - parseInactiveFor(inactiveFor).seconds;
|
|
40621
|
-
const gitDir = (0,
|
|
40910
|
+
const gitDir = (0, import_node_child_process49.spawnSync)(
|
|
40622
40911
|
"git",
|
|
40623
40912
|
["-C", worktreePath, "rev-parse", "--path-format=absolute", "--git-dir"],
|
|
40624
40913
|
{ encoding: "utf-8", env: READ_ONLY_GIT_ENV2 }
|
|
@@ -40638,7 +40927,7 @@ function classifyExactPath(repoPath, worktreePath, evidence, forge, extraDisposa
|
|
|
40638
40927
|
branch: worktree?.branch,
|
|
40639
40928
|
primary: worktrees[0] !== void 0 && sameWorkspacePath(worktrees[0].path, worktreePath),
|
|
40640
40929
|
locked: worktree?.locked ?? false,
|
|
40641
|
-
missing: !worktree || worktree.prunable || !
|
|
40930
|
+
missing: !worktree || worktree.prunable || !import_node_fs64.default.existsSync(worktreePath),
|
|
40642
40931
|
runtimeEvidence: evidence.runtimeEvidence,
|
|
40643
40932
|
forge,
|
|
40644
40933
|
extraDisposablePatterns
|
|
@@ -40664,7 +40953,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40664
40953
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40665
40954
|
);
|
|
40666
40955
|
const forge = evidence.status === "not-checked" ? { status: "unavailable", reason: "forge not checked" } : evidence;
|
|
40667
|
-
const disposable =
|
|
40956
|
+
const disposable = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40668
40957
|
const paths = evidenceCache(
|
|
40669
40958
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
40670
40959
|
);
|
|
@@ -40683,7 +40972,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40683
40972
|
}
|
|
40684
40973
|
function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
40685
40974
|
const repoPath = resolveRepoPath(repo);
|
|
40686
|
-
const configured =
|
|
40975
|
+
const configured = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
40687
40976
|
const patterns = configured?.trim ?? [];
|
|
40688
40977
|
const paths = evidenceCache(
|
|
40689
40978
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
@@ -40708,12 +40997,12 @@ function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
|
40708
40997
|
isActive: (worktreePath) => paths.last(worktreePath).active
|
|
40709
40998
|
};
|
|
40710
40999
|
}
|
|
40711
|
-
var
|
|
41000
|
+
var import_node_child_process49, import_node_fs64, import_node_path76, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
40712
41001
|
var init_workspace_cleanup = __esm({
|
|
40713
41002
|
"src/core/workspace-cleanup.ts"() {
|
|
40714
41003
|
"use strict";
|
|
40715
|
-
|
|
40716
|
-
|
|
41004
|
+
import_node_child_process49 = require("child_process");
|
|
41005
|
+
import_node_fs64 = __toESM(require("fs"));
|
|
40717
41006
|
import_node_path76 = __toESM(require("path"));
|
|
40718
41007
|
init_devpod_workspaces();
|
|
40719
41008
|
init_docker_leftovers();
|
|
@@ -40737,7 +41026,7 @@ var init_workspace_cleanup = __esm({
|
|
|
40737
41026
|
];
|
|
40738
41027
|
defaultCommandRunner = (command, args, input2) => {
|
|
40739
41028
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
40740
|
-
const result = (0,
|
|
41029
|
+
const result = (0, import_node_child_process49.spawnSync)(command, args, {
|
|
40741
41030
|
encoding: "utf-8",
|
|
40742
41031
|
env: environment,
|
|
40743
41032
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -40862,7 +41151,7 @@ function journalVetoes(record6) {
|
|
|
40862
41151
|
}
|
|
40863
41152
|
function readTraefikWindow(cutoffMs) {
|
|
40864
41153
|
const since = String(Math.floor(cutoffMs / 1e3));
|
|
40865
|
-
const run = (args, maxBuffer) => (0,
|
|
41154
|
+
const run = (args, maxBuffer) => (0, import_node_child_process50.spawnSync)("docker", ["logs", "--timestamps", ...args, ROUTER_CONTAINER_NAME], {
|
|
40866
41155
|
encoding: "utf-8",
|
|
40867
41156
|
maxBuffer,
|
|
40868
41157
|
...networkDockerOptions()
|
|
@@ -41031,12 +41320,12 @@ function setIdlePin(repoPath, pinned) {
|
|
|
41031
41320
|
}
|
|
41032
41321
|
);
|
|
41033
41322
|
}
|
|
41034
|
-
var
|
|
41323
|
+
var import_node_child_process50, import_node_fs65, import_node_path77, DEFAULT_IDLE_FOR, ACTIVITY_FILES, IdleStopSkipped, defaultDependencies;
|
|
41035
41324
|
var init_workspace_idle = __esm({
|
|
41036
41325
|
"src/core/workspace-idle.ts"() {
|
|
41037
41326
|
"use strict";
|
|
41038
|
-
|
|
41039
|
-
|
|
41327
|
+
import_node_child_process50 = require("child_process");
|
|
41328
|
+
import_node_fs65 = __toESM(require("fs"));
|
|
41040
41329
|
import_node_path77 = __toESM(require("path"));
|
|
41041
41330
|
init_devpod_environment();
|
|
41042
41331
|
init_devpod_workspaces();
|
|
@@ -41058,7 +41347,7 @@ var init_workspace_idle = __esm({
|
|
|
41058
41347
|
readJournals: () => listReliabilityOperations(),
|
|
41059
41348
|
journalModifiedMs: (record6) => {
|
|
41060
41349
|
try {
|
|
41061
|
-
return
|
|
41350
|
+
return import_node_fs65.default.statSync(reliabilityOperationPath(record6.identity)).mtimeMs;
|
|
41062
41351
|
} catch {
|
|
41063
41352
|
return void 0;
|
|
41064
41353
|
}
|
|
@@ -41066,7 +41355,7 @@ var init_workspace_idle = __esm({
|
|
|
41066
41355
|
registryPaths: () => listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
41067
41356
|
inspectContainers: () => inspectWorkspaceContainers(),
|
|
41068
41357
|
statActivity: (containerId) => {
|
|
41069
|
-
const result = (0,
|
|
41358
|
+
const result = (0, import_node_child_process50.spawnSync)(
|
|
41070
41359
|
"docker",
|
|
41071
41360
|
["exec", containerId, "stat", "-c", "%Y", ...ACTIVITY_FILES],
|
|
41072
41361
|
{
|
|
@@ -41081,7 +41370,7 @@ var init_workspace_idle = __esm({
|
|
|
41081
41370
|
};
|
|
41082
41371
|
},
|
|
41083
41372
|
readTraefik: readTraefikWindow,
|
|
41084
|
-
isConfiguredCheckout: (repoPath) =>
|
|
41373
|
+
isConfiguredCheckout: (repoPath) => import_node_fs65.default.existsSync(import_node_path77.default.join(repoPath, ".devrouter.yml")),
|
|
41085
41374
|
gitCommonDir: (repoPath) => {
|
|
41086
41375
|
try {
|
|
41087
41376
|
return resolveGitCommonDir(repoPath);
|
|
@@ -41175,7 +41464,7 @@ function defaultWorktreePath(mainRepo, ws) {
|
|
|
41175
41464
|
return import_node_path78.default.join(mainRepo, "trees", ws);
|
|
41176
41465
|
}
|
|
41177
41466
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
41178
|
-
const ignored = (0,
|
|
41467
|
+
const ignored = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
41179
41468
|
encoding: "utf-8"
|
|
41180
41469
|
});
|
|
41181
41470
|
if (ignored.status !== 0) {
|
|
@@ -41297,7 +41586,7 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
41297
41586
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
41298
41587
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
41299
41588
|
}
|
|
41300
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
41589
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs66.default.existsSync(target.worktreePath)) return;
|
|
41301
41590
|
if (target.worktree.locked) {
|
|
41302
41591
|
throw new Error(
|
|
41303
41592
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
@@ -41329,7 +41618,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41329
41618
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
41330
41619
|
);
|
|
41331
41620
|
const generatedPath = candidatePaths.find(
|
|
41332
|
-
(candidate) => !
|
|
41621
|
+
(candidate) => !import_node_fs66.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
41333
41622
|
);
|
|
41334
41623
|
const selectedPath = opts.path ? import_node_path78.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
41335
41624
|
if (!selectedPath) {
|
|
@@ -41340,7 +41629,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41340
41629
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
41341
41630
|
);
|
|
41342
41631
|
}
|
|
41343
|
-
if (
|
|
41632
|
+
if (import_node_fs66.default.existsSync(selectedPath)) {
|
|
41344
41633
|
const registered = worktrees.find(
|
|
41345
41634
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
41346
41635
|
);
|
|
@@ -41359,11 +41648,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41359
41648
|
return selectedPath;
|
|
41360
41649
|
}
|
|
41361
41650
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
41362
|
-
const add2 = (0,
|
|
41651
|
+
const add2 = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
41363
41652
|
encoding: "utf-8"
|
|
41364
41653
|
});
|
|
41365
41654
|
if (add2.status !== 0) {
|
|
41366
|
-
const addNew = (0,
|
|
41655
|
+
const addNew = (0, import_node_child_process51.spawnSync)(
|
|
41367
41656
|
"git",
|
|
41368
41657
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
41369
41658
|
{ encoding: "utf-8" }
|
|
@@ -41503,8 +41792,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41503
41792
|
}
|
|
41504
41793
|
const result = await mutateWorkspaceRuntime("delete", resolved2, worktrees, opts.quiet);
|
|
41505
41794
|
if (removeWorktree) {
|
|
41506
|
-
if (resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41507
|
-
const rm = (0,
|
|
41795
|
+
if (resolved2.worktree && !resolved2.worktree.prunable && import_node_fs66.default.existsSync(resolved2.worktreePath)) {
|
|
41796
|
+
const rm = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved2.worktreePath], {
|
|
41508
41797
|
encoding: "utf-8"
|
|
41509
41798
|
});
|
|
41510
41799
|
if (rm.status !== 0) {
|
|
@@ -41522,7 +41811,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41522
41811
|
}
|
|
41523
41812
|
return result;
|
|
41524
41813
|
};
|
|
41525
|
-
return resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41814
|
+
return resolved2.worktree && !resolved2.worktree.prunable && import_node_fs66.default.existsSync(resolved2.worktreePath) ? withLifecycleOperationLock(resolved2.worktreePath, operation) : operation();
|
|
41526
41815
|
}
|
|
41527
41816
|
async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRemove, steps) {
|
|
41528
41817
|
await withLifecycleOperationLock(worktreePath, async () => {
|
|
@@ -41548,7 +41837,7 @@ async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRem
|
|
|
41548
41837
|
);
|
|
41549
41838
|
steps.push("runtime-deleted");
|
|
41550
41839
|
}
|
|
41551
|
-
const rm = (0,
|
|
41840
|
+
const rm = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", worktreePath], {
|
|
41552
41841
|
encoding: "utf-8"
|
|
41553
41842
|
});
|
|
41554
41843
|
if (rm.status !== 0) {
|
|
@@ -41569,12 +41858,12 @@ async function workspaceStop(target, opts = {}) {
|
|
|
41569
41858
|
async function workspaceDown(target, opts = {}) {
|
|
41570
41859
|
return runWorkspaceLifecycle("down", target, opts);
|
|
41571
41860
|
}
|
|
41572
|
-
var
|
|
41861
|
+
var import_node_child_process51, import_node_fs66, import_node_path78, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
41573
41862
|
var init_workspace_lifecycle = __esm({
|
|
41574
41863
|
"src/core/workspace-lifecycle.ts"() {
|
|
41575
41864
|
"use strict";
|
|
41576
|
-
|
|
41577
|
-
|
|
41865
|
+
import_node_child_process51 = require("child_process");
|
|
41866
|
+
import_node_fs66 = __toESM(require("fs"));
|
|
41578
41867
|
import_node_path78 = __toESM(require("path"));
|
|
41579
41868
|
init_devpod_mutation();
|
|
41580
41869
|
init_devpod_workspaces();
|
|
@@ -41594,7 +41883,7 @@ var init_workspace_lifecycle = __esm({
|
|
|
41594
41883
|
|
|
41595
41884
|
// src/core/worktree-trim.ts
|
|
41596
41885
|
function listIgnoredPaths(worktreePath) {
|
|
41597
|
-
const result = (0,
|
|
41886
|
+
const result = (0, import_node_child_process52.spawnSync)(
|
|
41598
41887
|
"git",
|
|
41599
41888
|
[
|
|
41600
41889
|
"-C",
|
|
@@ -41683,14 +41972,14 @@ function isInside(parent, child) {
|
|
|
41683
41972
|
}
|
|
41684
41973
|
function exists(file) {
|
|
41685
41974
|
try {
|
|
41686
|
-
|
|
41975
|
+
import_node_fs67.default.lstatSync(file);
|
|
41687
41976
|
return true;
|
|
41688
41977
|
} catch {
|
|
41689
41978
|
return false;
|
|
41690
41979
|
}
|
|
41691
41980
|
}
|
|
41692
41981
|
function hasTrackedFiles(worktreePath, relative2) {
|
|
41693
|
-
const result = (0,
|
|
41982
|
+
const result = (0, import_node_child_process52.spawnSync)(
|
|
41694
41983
|
"git",
|
|
41695
41984
|
["-C", worktreePath, "--literal-pathspecs", "ls-files", "-z", "--", relative2],
|
|
41696
41985
|
{ encoding: "utf-8", env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" } }
|
|
@@ -41701,7 +41990,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41701
41990
|
const target = import_node_path79.default.join(candidate.path, relative2);
|
|
41702
41991
|
let stat;
|
|
41703
41992
|
try {
|
|
41704
|
-
stat =
|
|
41993
|
+
stat = import_node_fs67.default.lstatSync(target);
|
|
41705
41994
|
} catch (error) {
|
|
41706
41995
|
if (error.code === "ENOENT") {
|
|
41707
41996
|
steps.push(`gone:${relative2}`);
|
|
@@ -41713,7 +42002,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41713
42002
|
steps.push(`skipped-symlink:${relative2}`);
|
|
41714
42003
|
return;
|
|
41715
42004
|
}
|
|
41716
|
-
if (!isInside(
|
|
42005
|
+
if (!isInside(import_node_fs67.default.realpathSync.native(candidate.path), import_node_fs67.default.realpathSync.native(target))) {
|
|
41717
42006
|
steps.push(`skipped-outside:${relative2}`);
|
|
41718
42007
|
return;
|
|
41719
42008
|
}
|
|
@@ -41726,7 +42015,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41726
42015
|
return;
|
|
41727
42016
|
}
|
|
41728
42017
|
try {
|
|
41729
|
-
|
|
42018
|
+
import_node_fs67.default.rmSync(target, { recursive: true, force: true });
|
|
41730
42019
|
} catch (error) {
|
|
41731
42020
|
steps.push(`partial:${relative2}`);
|
|
41732
42021
|
throw error;
|
|
@@ -41827,12 +42116,12 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41827
42116
|
}
|
|
41828
42117
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
41829
42118
|
}
|
|
41830
|
-
var
|
|
42119
|
+
var import_node_child_process52, import_node_fs67, import_node_path79;
|
|
41831
42120
|
var init_worktree_trim = __esm({
|
|
41832
42121
|
"src/core/worktree-trim.ts"() {
|
|
41833
42122
|
"use strict";
|
|
41834
|
-
|
|
41835
|
-
|
|
42123
|
+
import_node_child_process52 = require("child_process");
|
|
42124
|
+
import_node_fs67 = __toESM(require("fs"));
|
|
41836
42125
|
import_node_path79 = __toESM(require("path"));
|
|
41837
42126
|
init_reliability_lifecycle();
|
|
41838
42127
|
init_worktree_reclaim();
|
|
@@ -41901,7 +42190,7 @@ function runWorkspaceLsCommand(options) {
|
|
|
41901
42190
|
}
|
|
41902
42191
|
function writeManifestOutput(manifest, output2) {
|
|
41903
42192
|
if (output2) {
|
|
41904
|
-
|
|
42193
|
+
import_node_fs68.default.writeFileSync(output2, manifest, { flag: "wx" });
|
|
41905
42194
|
process.stdout.write(`${sha256Hex(manifest)} ${output2}
|
|
41906
42195
|
`);
|
|
41907
42196
|
} else {
|
|
@@ -41931,7 +42220,7 @@ function runWorkspaceCleanupCommand(options) {
|
|
|
41931
42220
|
throw new Error("--manifest requires --all-worktrees and --check-merged.");
|
|
41932
42221
|
}
|
|
41933
42222
|
const createdAtEpoch = Math.floor(Date.now() / 1e3);
|
|
41934
|
-
const worktrees =
|
|
42223
|
+
const worktrees = import_node_fs68.default.existsSync(import_node_path80.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
41935
42224
|
const manifest = action2 === "trim" ? buildTrimManifest(
|
|
41936
42225
|
report,
|
|
41937
42226
|
{ trim: worktrees?.trim ?? [], disposable: worktrees?.disposable },
|
|
@@ -41969,7 +42258,7 @@ async function runWorkspaceIdleCommand(options) {
|
|
|
41969
42258
|
if (options.stop) {
|
|
41970
42259
|
const paths = idleSweepPaths();
|
|
41971
42260
|
if (!process.stderr.isTTY) muteLifecycleProgressHeartbeat();
|
|
41972
|
-
|
|
42261
|
+
import_node_fs68.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
41973
42262
|
const result = await withFileLock(paths.lock, { activity: "idle sweep" }, async () => {
|
|
41974
42263
|
try {
|
|
41975
42264
|
const swept = await stopIdleEnvironments(
|
|
@@ -42071,7 +42360,7 @@ async function runWorkspaceJournalSettleCommand(options) {
|
|
|
42071
42360
|
function runWorkspaceManifestHashCommand(file) {
|
|
42072
42361
|
let leftover = false;
|
|
42073
42362
|
try {
|
|
42074
|
-
leftover = isLeftoverManifest(JSON.parse(
|
|
42363
|
+
leftover = isLeftoverManifest(JSON.parse(import_node_fs68.default.readFileSync(file, "utf-8")));
|
|
42075
42364
|
} catch {
|
|
42076
42365
|
}
|
|
42077
42366
|
const { raw } = leftover ? readLeftoverManifest(file) : readManifest(file);
|
|
@@ -42168,11 +42457,11 @@ async function runWorkspaceTrimCommand(options) {
|
|
|
42168
42457
|
process.exitCode = 1;
|
|
42169
42458
|
}
|
|
42170
42459
|
}
|
|
42171
|
-
var
|
|
42460
|
+
var import_node_fs68, import_node_path80;
|
|
42172
42461
|
var init_workspace2 = __esm({
|
|
42173
42462
|
"src/commands/workspace.ts"() {
|
|
42174
42463
|
"use strict";
|
|
42175
|
-
|
|
42464
|
+
import_node_fs68 = __toESM(require("fs"));
|
|
42176
42465
|
import_node_path80 = __toESM(require("path"));
|
|
42177
42466
|
init_docker_leftovers();
|
|
42178
42467
|
init_file_lock();
|
|
@@ -42231,7 +42520,7 @@ var init_version = __esm({
|
|
|
42231
42520
|
|
|
42232
42521
|
// src/cli.ts
|
|
42233
42522
|
var import_commander = require("commander");
|
|
42234
|
-
var CLI_VERSION = true ? "0.6.
|
|
42523
|
+
var CLI_VERSION = true ? "0.6.5" : "0.0.0-dev";
|
|
42235
42524
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
42236
42525
|
function withErrorHandling(action2) {
|
|
42237
42526
|
return async (...args) => {
|
|
@@ -42325,7 +42614,7 @@ program.command("up").description("Ensure devnet and start shared Traefik (reser
|
|
|
42325
42614
|
await runUpCommand2();
|
|
42326
42615
|
})
|
|
42327
42616
|
);
|
|
42328
|
-
program.command("ensure").description("Start and prove a primary or linked checkout's environment and routes").argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42617
|
+
program.command("ensure").description("Start and prove a primary or linked checkout's environment and routes").argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--replace-app", "Replace one proved stopped managed app; discard its writable layer").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42329
42618
|
withErrorHandling(async (repoPath, _options, command) => {
|
|
42330
42619
|
const options = command.opts();
|
|
42331
42620
|
const { runEnsureCommand: runEnsureCommand2 } = await Promise.resolve().then(() => (init_ensure(), ensure_exports));
|
|
@@ -42335,6 +42624,7 @@ program.command("ensure").description("Start and prove a primary or linked check
|
|
|
42335
42624
|
variant: options.variant,
|
|
42336
42625
|
repair: options.repair,
|
|
42337
42626
|
initializeNew: options.initializeNew,
|
|
42627
|
+
replaceApp: options.replaceApp,
|
|
42338
42628
|
open: Boolean(options.open),
|
|
42339
42629
|
json: Boolean(options.json)
|
|
42340
42630
|
});
|
|
@@ -42599,7 +42889,7 @@ workspaceCommand2.command("up").description(
|
|
|
42599
42889
|
);
|
|
42600
42890
|
workspaceCommand2.command("ensure").description(
|
|
42601
42891
|
"Start and prove a primary or linked checkout's workspace runtime, upstreams, and routes"
|
|
42602
|
-
).argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42892
|
+
).argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--replace-app", "Replace one proved stopped managed app; discard its writable layer").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42603
42893
|
withErrorHandling(
|
|
42604
42894
|
async (worktreePath, _options, command) => {
|
|
42605
42895
|
const options = command.opts();
|
|
@@ -42610,6 +42900,7 @@ workspaceCommand2.command("ensure").description(
|
|
|
42610
42900
|
variant: options.variant,
|
|
42611
42901
|
repair: options.repair,
|
|
42612
42902
|
initializeNew: options.initializeNew,
|
|
42903
|
+
replaceApp: options.replaceApp,
|
|
42613
42904
|
open: Boolean(options.open),
|
|
42614
42905
|
json: Boolean(options.json)
|
|
42615
42906
|
});
|