@devrouter/cli 0.6.2 → 0.6.4
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 +8643 -8161
- package/dist/devrouter.js +1218 -928
- package/package.json +1 -1
- package/upgrade-prompts/0.6.3.md +51 -0
- package/upgrade-prompts/0.6.4.md +67 -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.4" : "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.4" : "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";
|
|
@@ -17631,7 +17882,11 @@ function reliabilityRecovery(reason2, repoPath, variant) {
|
|
|
17631
17882
|
switch (reason2) {
|
|
17632
17883
|
case "stop-incomplete":
|
|
17633
17884
|
case "operation-unknown":
|
|
17634
|
-
return [
|
|
17885
|
+
return [
|
|
17886
|
+
`Run: devrouter stop ${checkout}`,
|
|
17887
|
+
"Verify the repository startup hooks preserve retained data and startup is authorized before continuing.",
|
|
17888
|
+
`Run: devrouter ensure ${checkout}${variantOption}`
|
|
17889
|
+
];
|
|
17635
17890
|
case "start-refused":
|
|
17636
17891
|
return [
|
|
17637
17892
|
`Run: devrouter doctor --repo ${checkout} to read the refused fixed host-port claim and its holder`,
|
|
@@ -18171,7 +18426,7 @@ function readDocker(endpoint, args, timeoutMs) {
|
|
|
18171
18426
|
const env = { ...process.env };
|
|
18172
18427
|
delete env.DOCKER_CONTEXT;
|
|
18173
18428
|
delete env.DOCKER_HOST;
|
|
18174
|
-
const result = (0,
|
|
18429
|
+
const result = (0, import_node_child_process30.spawnSync)("docker", ["--host", endpoint, ...args], {
|
|
18175
18430
|
env,
|
|
18176
18431
|
encoding: "utf-8",
|
|
18177
18432
|
timeout: timeoutMs,
|
|
@@ -18333,11 +18588,11 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
|
|
|
18333
18588
|
}
|
|
18334
18589
|
return result;
|
|
18335
18590
|
}
|
|
18336
|
-
var
|
|
18591
|
+
var import_node_child_process30, NetworkInventoryError, MAX_IDS, MAX_OUTPUT_BYTES, FULL_ID, NETWORK_TEMPLATE, CONTAINER_TEMPLATE;
|
|
18337
18592
|
var init_network_inventory = __esm({
|
|
18338
18593
|
"src/core/network-inventory.ts"() {
|
|
18339
18594
|
"use strict";
|
|
18340
|
-
|
|
18595
|
+
import_node_child_process30 = require("child_process");
|
|
18341
18596
|
init_devpod_environment();
|
|
18342
18597
|
NetworkInventoryError = class extends Error {
|
|
18343
18598
|
};
|
|
@@ -18665,26 +18920,26 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18665
18920
|
try {
|
|
18666
18921
|
if (!endpoint.startsWith("unix:///")) return false;
|
|
18667
18922
|
const socket = endpoint.slice("unix://".length);
|
|
18668
|
-
const table =
|
|
18923
|
+
const table = import_node_fs38.default.readFileSync(import_node_path45.default.join(procRoot, "net/unix"), "utf8");
|
|
18669
18924
|
if (Buffer.byteLength(table) > 1024 * 1024) return false;
|
|
18670
18925
|
const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
|
|
18671
18926
|
if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
|
|
18672
18927
|
const inode = `socket:[${rows2[0][6]}]`;
|
|
18673
|
-
const ownNamespace =
|
|
18674
|
-
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));
|
|
18675
18930
|
if (pids.length > 4096) return false;
|
|
18676
18931
|
for (const pid of pids) {
|
|
18677
18932
|
if (Date.now() > deadline) return false;
|
|
18678
18933
|
try {
|
|
18679
18934
|
const root = import_node_path45.default.join(procRoot, pid);
|
|
18680
|
-
if (import_node_path45.default.basename(
|
|
18681
|
-
if (
|
|
18682
|
-
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"));
|
|
18683
18938
|
if (descriptors.length > 4096) continue;
|
|
18684
18939
|
if (descriptors.some((fd) => {
|
|
18685
18940
|
if (Date.now() > deadline) return false;
|
|
18686
18941
|
try {
|
|
18687
|
-
return
|
|
18942
|
+
return import_node_fs38.default.readlinkSync(import_node_path45.default.join(root, "fd", fd)) === inode;
|
|
18688
18943
|
} catch {
|
|
18689
18944
|
return false;
|
|
18690
18945
|
}
|
|
@@ -18698,11 +18953,11 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18698
18953
|
}
|
|
18699
18954
|
return false;
|
|
18700
18955
|
}
|
|
18701
|
-
var
|
|
18956
|
+
var import_node_fs38, import_node_path45;
|
|
18702
18957
|
var init_network_local_daemon = __esm({
|
|
18703
18958
|
"src/core/network-local-daemon.ts"() {
|
|
18704
18959
|
"use strict";
|
|
18705
|
-
|
|
18960
|
+
import_node_fs38 = __toESM(require("fs"));
|
|
18706
18961
|
import_node_path45 = __toESM(require("path"));
|
|
18707
18962
|
}
|
|
18708
18963
|
});
|
|
@@ -18731,7 +18986,7 @@ function parseLinuxNetworkRoutes(output2) {
|
|
|
18731
18986
|
function collectNetworkRoutes(options) {
|
|
18732
18987
|
if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
|
|
18733
18988
|
return { status: "unknown", routes: [] };
|
|
18734
|
-
const result = (0,
|
|
18989
|
+
const result = (0, import_node_child_process31.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
|
|
18735
18990
|
encoding: "utf8",
|
|
18736
18991
|
timeout: 5e3,
|
|
18737
18992
|
maxBuffer: 1024 * 1024
|
|
@@ -18739,11 +18994,11 @@ function collectNetworkRoutes(options) {
|
|
|
18739
18994
|
if (result.error || result.status !== 0) return { status: "unknown", routes: [] };
|
|
18740
18995
|
return parseLinuxNetworkRoutes(result.stdout);
|
|
18741
18996
|
}
|
|
18742
|
-
var
|
|
18997
|
+
var import_node_child_process31, import_node_net3;
|
|
18743
18998
|
var init_network_routes = __esm({
|
|
18744
18999
|
"src/core/network-routes.ts"() {
|
|
18745
19000
|
"use strict";
|
|
18746
|
-
|
|
19001
|
+
import_node_child_process31 = require("child_process");
|
|
18747
19002
|
import_node_net3 = require("net");
|
|
18748
19003
|
init_network_capacity();
|
|
18749
19004
|
init_network_local_daemon();
|
|
@@ -18911,11 +19166,11 @@ function extendDockerComposeFile(nativeConfig, overlayPath) {
|
|
|
18911
19166
|
const config = { ...nativeConfig, dockerComposeFile };
|
|
18912
19167
|
return { status: "ready", config, reasons: [] };
|
|
18913
19168
|
}
|
|
18914
|
-
var
|
|
19169
|
+
var import_node_crypto24;
|
|
18915
19170
|
var init_network_compose = __esm({
|
|
18916
19171
|
"src/core/network-compose.ts"() {
|
|
18917
19172
|
"use strict";
|
|
18918
|
-
|
|
19173
|
+
import_node_crypto24 = require("crypto");
|
|
18919
19174
|
}
|
|
18920
19175
|
});
|
|
18921
19176
|
|
|
@@ -18924,7 +19179,7 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18924
19179
|
const overlay = deriveComposeNetworkOverlay(subnet);
|
|
18925
19180
|
if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
|
|
18926
19181
|
const overlayPath = import_node_path46.default.join(plan.composeDirectory, OVERLAY);
|
|
18927
|
-
const ignored = (0,
|
|
19182
|
+
const ignored = (0, import_node_child_process32.spawnSync)("git", [
|
|
18928
19183
|
"-C",
|
|
18929
19184
|
plan.composeDirectory,
|
|
18930
19185
|
"check-ignore",
|
|
@@ -18938,9 +19193,9 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18938
19193
|
const bytes2 = `${MARKER}
|
|
18939
19194
|
${import_yaml5.default.stringify(overlay.overlay)}`;
|
|
18940
19195
|
const assertOwnership = () => {
|
|
18941
|
-
if (!
|
|
18942
|
-
const stat =
|
|
18943
|
-
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)
|
|
18944
19199
|
throw new Error("Retained network overlay changed; repair is required.");
|
|
18945
19200
|
};
|
|
18946
19201
|
assertOwnership();
|
|
@@ -18954,7 +19209,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18954
19209
|
...plan,
|
|
18955
19210
|
contents,
|
|
18956
19211
|
composeFiles: [...plan.composeFiles, overlayPath],
|
|
18957
|
-
effectiveConfigSha256: (0,
|
|
19212
|
+
effectiveConfigSha256: (0, import_node_crypto25.createHash)("sha256").update(contents).digest("hex")
|
|
18958
19213
|
};
|
|
18959
19214
|
return {
|
|
18960
19215
|
plan: result,
|
|
@@ -18964,13 +19219,13 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18964
19219
|
}
|
|
18965
19220
|
};
|
|
18966
19221
|
}
|
|
18967
|
-
var
|
|
19222
|
+
var import_node_child_process32, import_node_crypto25, import_node_fs39, import_node_path46, import_yaml5, OVERLAY, MARKER, MAX_BYTES3;
|
|
18968
19223
|
var init_network_compose_files = __esm({
|
|
18969
19224
|
"src/core/network-compose-files.ts"() {
|
|
18970
19225
|
"use strict";
|
|
18971
|
-
|
|
18972
|
-
|
|
18973
|
-
|
|
19226
|
+
import_node_child_process32 = require("child_process");
|
|
19227
|
+
import_node_crypto25 = require("crypto");
|
|
19228
|
+
import_node_fs39 = __toESM(require("fs"));
|
|
18974
19229
|
import_node_path46 = __toESM(require("path"));
|
|
18975
19230
|
import_yaml5 = __toESM(require("yaml"));
|
|
18976
19231
|
init_atomic_file();
|
|
@@ -18983,11 +19238,11 @@ var init_network_compose_files = __esm({
|
|
|
18983
19238
|
});
|
|
18984
19239
|
|
|
18985
19240
|
// src/core/network-connected-route.ts
|
|
18986
|
-
var
|
|
19241
|
+
var import_node_child_process33;
|
|
18987
19242
|
var init_network_connected_route = __esm({
|
|
18988
19243
|
"src/core/network-connected-route.ts"() {
|
|
18989
19244
|
"use strict";
|
|
18990
|
-
|
|
19245
|
+
import_node_child_process33 = require("child_process");
|
|
18991
19246
|
init_network_capacity();
|
|
18992
19247
|
}
|
|
18993
19248
|
});
|
|
@@ -19003,11 +19258,11 @@ var init_network_lifecycle = __esm({
|
|
|
19003
19258
|
});
|
|
19004
19259
|
|
|
19005
19260
|
// src/core/network-managed.ts
|
|
19006
|
-
var
|
|
19261
|
+
var import_node_crypto26;
|
|
19007
19262
|
var init_network_managed = __esm({
|
|
19008
19263
|
"src/core/network-managed.ts"() {
|
|
19009
19264
|
"use strict";
|
|
19010
|
-
|
|
19265
|
+
import_node_crypto26 = require("crypto");
|
|
19011
19266
|
init_devpod_environment();
|
|
19012
19267
|
init_network_capacity();
|
|
19013
19268
|
init_network_claim_lookup();
|
|
@@ -19077,12 +19332,12 @@ function resolveLinkedTarget(repoPath) {
|
|
|
19077
19332
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
19078
19333
|
};
|
|
19079
19334
|
}
|
|
19080
|
-
var
|
|
19335
|
+
var import_node_child_process34, import_node_fs40, import_node_path47;
|
|
19081
19336
|
var init_workspace_ensure = __esm({
|
|
19082
19337
|
"src/core/workspace-ensure.ts"() {
|
|
19083
19338
|
"use strict";
|
|
19084
|
-
|
|
19085
|
-
|
|
19339
|
+
import_node_child_process34 = require("child_process");
|
|
19340
|
+
import_node_fs40 = __toESM(require("fs"));
|
|
19086
19341
|
import_node_path47 = __toESM(require("path"));
|
|
19087
19342
|
init_devcontainer_profile();
|
|
19088
19343
|
init_devpod_environment();
|
|
@@ -19106,6 +19361,7 @@ var init_workspace_ensure = __esm({
|
|
|
19106
19361
|
init_network_managed();
|
|
19107
19362
|
init_network_recovery();
|
|
19108
19363
|
init_reliability_lifecycle();
|
|
19364
|
+
init_reliability_operation_store();
|
|
19109
19365
|
init_repo_config();
|
|
19110
19366
|
init_route_publication();
|
|
19111
19367
|
init_router();
|
|
@@ -19195,6 +19451,29 @@ function preflightRuntimeVariant(repoPath, options) {
|
|
|
19195
19451
|
}
|
|
19196
19452
|
return variant;
|
|
19197
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
|
+
}
|
|
19198
19477
|
function prepareManagedLifecycleOperation(input2) {
|
|
19199
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)
|
|
19200
19479
|
throw new Error("Invalid managed operation command.");
|
|
@@ -19616,6 +19895,9 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19616
19895
|
provider: resolveWorkspaceRuntimeOrDefault(repoPath)
|
|
19617
19896
|
};
|
|
19618
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);
|
|
19619
19901
|
const copiedOptions = { ...options };
|
|
19620
19902
|
if (kind === "ensure") assertFreshBootstrapRequest(identity2, options);
|
|
19621
19903
|
const copiedCommand = command ? [...command] : void 0;
|
|
@@ -19741,6 +20023,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19741
20023
|
...ids2,
|
|
19742
20024
|
fence: { ...expectedFence },
|
|
19743
20025
|
options: copiedOptions,
|
|
20026
|
+
...replacement ? { replacement } : {},
|
|
19744
20027
|
...copiedCommand ? { command: copiedCommand } : {},
|
|
19745
20028
|
...retainedExecProof ? { retainedExecProof } : {},
|
|
19746
20029
|
admission: {
|
|
@@ -19901,7 +20184,7 @@ async function superviseThroughController(input2) {
|
|
|
19901
20184
|
try {
|
|
19902
20185
|
const bind = () => observeControllerBinding(directory, {
|
|
19903
20186
|
path: input2.repoPath,
|
|
19904
|
-
session: (0,
|
|
20187
|
+
session: (0, import_node_crypto27.randomUUID)(),
|
|
19905
20188
|
profile: input2.profile ?? "full",
|
|
19906
20189
|
// The protocol requires at least one readiness selector, and every
|
|
19907
20190
|
// supervised operation depends on runtime readiness; "runtime" is the
|
|
@@ -20057,11 +20340,11 @@ function bindLifecycleCapacity(request2, binding, directory = import_node_path48
|
|
|
20057
20340
|
stepRecord(record6, { ...request2.fence, type: "admission", result: "admitted" });
|
|
20058
20341
|
});
|
|
20059
20342
|
}
|
|
20060
|
-
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;
|
|
20061
20344
|
var init_reliability_lifecycle = __esm({
|
|
20062
20345
|
"src/core/reliability-lifecycle.ts"() {
|
|
20063
20346
|
"use strict";
|
|
20064
|
-
|
|
20347
|
+
import_node_crypto27 = require("crypto");
|
|
20065
20348
|
import_node_path48 = __toESM(require("path"));
|
|
20066
20349
|
import_node_util13 = require("util");
|
|
20067
20350
|
init_capacity_accounting();
|
|
@@ -20083,6 +20366,7 @@ var init_reliability_lifecycle = __esm({
|
|
|
20083
20366
|
init_managed_post_start();
|
|
20084
20367
|
init_managed_runtime_state();
|
|
20085
20368
|
init_managed_stop_recovery();
|
|
20369
|
+
init_network_claim_lookup();
|
|
20086
20370
|
init_recovery_budget();
|
|
20087
20371
|
init_reliability_context();
|
|
20088
20372
|
init_reliability_contract();
|
|
@@ -20444,7 +20728,7 @@ var init_capacity_startup_witness = __esm({
|
|
|
20444
20728
|
function readHostWakeEpoch(platform = process.platform) {
|
|
20445
20729
|
if (platform !== "darwin") return void 0;
|
|
20446
20730
|
try {
|
|
20447
|
-
const result = (0,
|
|
20731
|
+
const result = (0, import_node_child_process35.spawnSync)("/usr/sbin/sysctl", ["-n", "kern.wake_abs_time"], {
|
|
20448
20732
|
encoding: "utf8",
|
|
20449
20733
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20450
20734
|
timeout: 250,
|
|
@@ -20459,11 +20743,11 @@ function readHostWakeEpoch(platform = process.platform) {
|
|
|
20459
20743
|
return null;
|
|
20460
20744
|
}
|
|
20461
20745
|
}
|
|
20462
|
-
var
|
|
20746
|
+
var import_node_child_process35;
|
|
20463
20747
|
var init_host_wake = __esm({
|
|
20464
20748
|
"src/core/host-wake.ts"() {
|
|
20465
20749
|
"use strict";
|
|
20466
|
-
|
|
20750
|
+
import_node_child_process35 = require("child_process");
|
|
20467
20751
|
}
|
|
20468
20752
|
});
|
|
20469
20753
|
|
|
@@ -20689,7 +20973,7 @@ function createCapacityController(options) {
|
|
|
20689
20973
|
controller,
|
|
20690
20974
|
policyRevision: policy.revision
|
|
20691
20975
|
});
|
|
20692
|
-
const payloadKey = (0,
|
|
20976
|
+
const payloadKey = (0, import_node_crypto28.randomBytes)(32);
|
|
20693
20977
|
const acceptedPayloads = /* @__PURE__ */ new Map();
|
|
20694
20978
|
const settlePreparations = () => {
|
|
20695
20979
|
if (lifetime.signal.aborted) return;
|
|
@@ -20853,7 +21137,7 @@ function createCapacityController(options) {
|
|
|
20853
21137
|
{
|
|
20854
21138
|
...charge,
|
|
20855
21139
|
operationId: prepared.operationId,
|
|
20856
|
-
reservationId: (0,
|
|
21140
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
20857
21141
|
policyRevision: target.current.revision
|
|
20858
21142
|
},
|
|
20859
21143
|
{
|
|
@@ -20957,7 +21241,7 @@ function createCapacityController(options) {
|
|
|
20957
21241
|
throw error;
|
|
20958
21242
|
}
|
|
20959
21243
|
}
|
|
20960
|
-
const signature = (0,
|
|
21244
|
+
const signature = (0, import_node_crypto28.createHmac)("sha256", payloadKey).update(
|
|
20961
21245
|
JSON.stringify({
|
|
20962
21246
|
repoPath: identity2.repoPath,
|
|
20963
21247
|
profile: environment.profile,
|
|
@@ -20978,7 +21262,7 @@ function createCapacityController(options) {
|
|
|
20978
21262
|
{
|
|
20979
21263
|
...charge,
|
|
20980
21264
|
operationId: prepared.operationId,
|
|
20981
|
-
reservationId: (0,
|
|
21265
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
20982
21266
|
policyRevision: current.revision
|
|
20983
21267
|
},
|
|
20984
21268
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -21113,7 +21397,7 @@ function createCapacityController(options) {
|
|
|
21113
21397
|
// the budget module then falls back to the conservative wall duration.
|
|
21114
21398
|
activeElapsedMs: null,
|
|
21115
21399
|
profile: environment.profile,
|
|
21116
|
-
incidentId: `incident-${(0,
|
|
21400
|
+
incidentId: `incident-${(0, import_node_crypto28.randomUUID)()}`
|
|
21117
21401
|
});
|
|
21118
21402
|
} catch {
|
|
21119
21403
|
return;
|
|
@@ -21131,7 +21415,7 @@ function createCapacityController(options) {
|
|
|
21131
21415
|
{
|
|
21132
21416
|
...charge,
|
|
21133
21417
|
operationId: prepared.operationId,
|
|
21134
|
-
reservationId: (0,
|
|
21418
|
+
reservationId: (0, import_node_crypto28.randomUUID)(),
|
|
21135
21419
|
policyRevision: current.revision
|
|
21136
21420
|
},
|
|
21137
21421
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -21151,11 +21435,11 @@ function createCapacityController(options) {
|
|
|
21151
21435
|
}
|
|
21152
21436
|
};
|
|
21153
21437
|
}
|
|
21154
|
-
var
|
|
21438
|
+
var import_node_crypto28, import_node_path49, import_node_util15;
|
|
21155
21439
|
var init_capacity_controller = __esm({
|
|
21156
21440
|
"src/core/capacity-controller.ts"() {
|
|
21157
21441
|
"use strict";
|
|
21158
|
-
|
|
21442
|
+
import_node_crypto28 = require("crypto");
|
|
21159
21443
|
import_node_path49 = __toESM(require("path"));
|
|
21160
21444
|
import_node_util15 = require("util");
|
|
21161
21445
|
init_capacity_accounting();
|
|
@@ -21253,7 +21537,7 @@ printf '%s %s %s\n' "$pid" "$birth" "$fingerprint"
|
|
|
21253
21537
|
|
|
21254
21538
|
// src/core/controller-observation.ts
|
|
21255
21539
|
function digest2(value) {
|
|
21256
|
-
return (0,
|
|
21540
|
+
return (0, import_node_crypto29.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
21257
21541
|
}
|
|
21258
21542
|
function readRoutes() {
|
|
21259
21543
|
return readHostRouteStateReadOnly((file) => readControllerEvidence(file, 1048576));
|
|
@@ -21337,7 +21621,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21337
21621
|
() => persisted.contents[3]
|
|
21338
21622
|
);
|
|
21339
21623
|
const source = parseDevcontainerConfig(persisted.contents[4], sourcePath);
|
|
21340
|
-
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)
|
|
21341
21625
|
throw new ControllerObservationBindingChanged("Observation retained configuration changed.");
|
|
21342
21626
|
const identity2 = {
|
|
21343
21627
|
repoPath: environment.repoPath,
|
|
@@ -21512,11 +21796,11 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21512
21796
|
};
|
|
21513
21797
|
};
|
|
21514
21798
|
}
|
|
21515
|
-
var
|
|
21799
|
+
var import_node_crypto29, import_node_path50, OBSERVATION_INSPECT_TEMPLATE;
|
|
21516
21800
|
var init_controller_observation = __esm({
|
|
21517
21801
|
"src/core/controller-observation.ts"() {
|
|
21518
21802
|
"use strict";
|
|
21519
|
-
|
|
21803
|
+
import_node_crypto29 = require("crypto");
|
|
21520
21804
|
import_node_path50 = __toESM(require("path"));
|
|
21521
21805
|
init_controller_binding();
|
|
21522
21806
|
init_controller_monitor();
|
|
@@ -21541,11 +21825,11 @@ var init_controller_observation = __esm({
|
|
|
21541
21825
|
});
|
|
21542
21826
|
|
|
21543
21827
|
// src/core/controller-sessions.ts
|
|
21544
|
-
var
|
|
21828
|
+
var import_node_crypto30, import_node_util16, ControllerSessions;
|
|
21545
21829
|
var init_controller_sessions = __esm({
|
|
21546
21830
|
"src/core/controller-sessions.ts"() {
|
|
21547
21831
|
"use strict";
|
|
21548
|
-
|
|
21832
|
+
import_node_crypto30 = require("crypto");
|
|
21549
21833
|
import_node_util16 = require("util");
|
|
21550
21834
|
ControllerSessions = class {
|
|
21551
21835
|
constructor(store, readWakeEpoch = () => void 0) {
|
|
@@ -21739,7 +22023,7 @@ var init_controller_sessions = __esm({
|
|
|
21739
22023
|
const session = {
|
|
21740
22024
|
id: id5,
|
|
21741
22025
|
environmentId: environment.id,
|
|
21742
|
-
generation: (0,
|
|
22026
|
+
generation: (0, import_node_crypto30.randomUUID)(),
|
|
21743
22027
|
requirements: required,
|
|
21744
22028
|
renewedAtMs: wall,
|
|
21745
22029
|
parkingConsent: "protected",
|
|
@@ -21767,7 +22051,7 @@ var init_controller_sessions = __esm({
|
|
|
21767
22051
|
const session = {
|
|
21768
22052
|
id: previous.session,
|
|
21769
22053
|
environmentId: environment.id,
|
|
21770
|
-
generation: (0,
|
|
22054
|
+
generation: (0, import_node_crypto30.randomUUID)(),
|
|
21771
22055
|
requirements: required,
|
|
21772
22056
|
renewedAtMs: wall,
|
|
21773
22057
|
parkingConsent: "protected",
|
|
@@ -21932,21 +22216,21 @@ function privateDirectory2(directory) {
|
|
|
21932
22216
|
for (const part of absolute2.slice(current.length).split(import_node_path51.default.sep)) {
|
|
21933
22217
|
current = import_node_path51.default.join(current, part);
|
|
21934
22218
|
try {
|
|
21935
|
-
const stat2 =
|
|
22219
|
+
const stat2 = import_node_fs41.default.lstatSync(current);
|
|
21936
22220
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
21937
22221
|
throw new Error("Unsafe controller directory.");
|
|
21938
22222
|
} catch (error) {
|
|
21939
22223
|
if (error.code !== "ENOENT") throw error;
|
|
21940
|
-
|
|
22224
|
+
import_node_fs41.default.mkdirSync(current, { mode: 448 });
|
|
21941
22225
|
}
|
|
21942
22226
|
}
|
|
21943
|
-
const stat =
|
|
22227
|
+
const stat = import_node_fs41.default.lstatSync(absolute2);
|
|
21944
22228
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
21945
22229
|
throw new Error("Controller directory is not private.");
|
|
21946
22230
|
}
|
|
21947
22231
|
function validateOwnedFile(file, socket) {
|
|
21948
22232
|
try {
|
|
21949
|
-
const stat =
|
|
22233
|
+
const stat = import_node_fs41.default.lstatSync(file);
|
|
21950
22234
|
if (stat.uid !== process.getuid?.() || (socket ? !stat.isSocket() : !stat.isFile()) || (stat.mode & 63) !== 0)
|
|
21951
22235
|
throw new Error("Unsafe controller artifact.");
|
|
21952
22236
|
return true;
|
|
@@ -21971,7 +22255,7 @@ async function runController(options) {
|
|
|
21971
22255
|
privateDirectory2(options.directory);
|
|
21972
22256
|
const lockPath = import_node_path51.default.join(options.directory, "owner.lock");
|
|
21973
22257
|
try {
|
|
21974
|
-
const stat =
|
|
22258
|
+
const stat = import_node_fs41.default.lstatSync(lockPath);
|
|
21975
22259
|
if (!stat.isFile() || stat.uid !== process.getuid?.())
|
|
21976
22260
|
throw new Error("Unsafe controller owner lock.");
|
|
21977
22261
|
} catch (error) {
|
|
@@ -21982,7 +22266,7 @@ async function runController(options) {
|
|
|
21982
22266
|
await withFileLock(lockPath, { activity: "controller ownership", waitMs: 0 }, async () => {
|
|
21983
22267
|
const staleSocket = validateOwnedFile(socketPath, true);
|
|
21984
22268
|
const sessions = new ControllerSessions(store, options.wakeEpoch ?? readHostWakeEpoch);
|
|
21985
|
-
if (staleSocket)
|
|
22269
|
+
if (staleSocket) import_node_fs41.default.unlinkSync(socketPath);
|
|
21986
22270
|
const incarnation = sessions.read();
|
|
21987
22271
|
const { resolve, collect } = options.createBindings?.(store.bindingFingerprint()) ?? {
|
|
21988
22272
|
resolve: options.resolve,
|
|
@@ -22528,7 +22812,7 @@ async function runController(options) {
|
|
|
22528
22812
|
resolve2();
|
|
22529
22813
|
});
|
|
22530
22814
|
});
|
|
22531
|
-
|
|
22815
|
+
import_node_fs41.default.chmodSync(socketPath, 384);
|
|
22532
22816
|
await new Promise((resolve2) => {
|
|
22533
22817
|
finish = resolve2;
|
|
22534
22818
|
options.signal.addEventListener("abort", shutdown, { once: true });
|
|
@@ -22547,11 +22831,11 @@ async function runController(options) {
|
|
|
22547
22831
|
}
|
|
22548
22832
|
});
|
|
22549
22833
|
}
|
|
22550
|
-
var
|
|
22834
|
+
var import_node_fs41, import_node_net4, import_node_path51, FRAME_BYTES;
|
|
22551
22835
|
var init_controller_server = __esm({
|
|
22552
22836
|
"src/core/controller-server.ts"() {
|
|
22553
22837
|
"use strict";
|
|
22554
|
-
|
|
22838
|
+
import_node_fs41 = __toESM(require("fs"));
|
|
22555
22839
|
import_node_net4 = __toESM(require("net"));
|
|
22556
22840
|
import_node_path51 = __toESM(require("path"));
|
|
22557
22841
|
init_controller_monitor();
|
|
@@ -22838,27 +23122,27 @@ function replaceDevrouterSection(content) {
|
|
|
22838
23122
|
}
|
|
22839
23123
|
function writeRepoFile(repoPath, relPath, content) {
|
|
22840
23124
|
const absolutePath = (0, import_node_path54.join)(repoPath, relPath);
|
|
22841
|
-
(0,
|
|
22842
|
-
(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");
|
|
22843
23127
|
return absolutePath;
|
|
22844
23128
|
}
|
|
22845
23129
|
function ensureAgentsMdSection(repoPath) {
|
|
22846
23130
|
const filePath = (0, import_node_path54.join)(repoPath, AGENTS_MD);
|
|
22847
|
-
if ((0,
|
|
22848
|
-
const content = (0,
|
|
23131
|
+
if ((0, import_node_fs42.existsSync)(filePath)) {
|
|
23132
|
+
const content = (0, import_node_fs42.readFileSync)(filePath, "utf-8");
|
|
22849
23133
|
if (content.includes(DEVROUTER_SENTINEL)) {
|
|
22850
23134
|
const updated = replaceDevrouterSection(content);
|
|
22851
23135
|
if (updated === void 0 || updated === content) return { path: filePath, written: false };
|
|
22852
|
-
(0,
|
|
23136
|
+
(0, import_node_fs42.writeFileSync)(filePath, updated, "utf-8");
|
|
22853
23137
|
return { path: filePath, written: true };
|
|
22854
23138
|
}
|
|
22855
|
-
(0,
|
|
23139
|
+
(0, import_node_fs42.writeFileSync)(filePath, `${content.trimEnd()}
|
|
22856
23140
|
|
|
22857
23141
|
${buildDevrouterSection()}
|
|
22858
23142
|
`, "utf-8");
|
|
22859
23143
|
return { path: filePath, written: true };
|
|
22860
23144
|
}
|
|
22861
|
-
(0,
|
|
23145
|
+
(0, import_node_fs42.writeFileSync)(filePath, `# AGENTS.md
|
|
22862
23146
|
|
|
22863
23147
|
${buildDevrouterSection()}
|
|
22864
23148
|
`, "utf-8");
|
|
@@ -22868,11 +23152,11 @@ function ensureSkillFile(repoPath) {
|
|
|
22868
23152
|
const filePath = writeRepoFile(repoPath, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT);
|
|
22869
23153
|
return { path: filePath, written: true };
|
|
22870
23154
|
}
|
|
22871
|
-
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;
|
|
22872
23156
|
var init_agents_md = __esm({
|
|
22873
23157
|
"src/core/agents-md.ts"() {
|
|
22874
23158
|
"use strict";
|
|
22875
|
-
|
|
23159
|
+
import_node_fs42 = require("fs");
|
|
22876
23160
|
import_node_path54 = require("path");
|
|
22877
23161
|
DEVROUTER_SENTINEL = "<!-- devrouter -->";
|
|
22878
23162
|
DEVROUTER_END_SENTINEL = "<!-- /devrouter -->";
|
|
@@ -23495,7 +23779,9 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
23495
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.",
|
|
23496
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.",
|
|
23497
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.",
|
|
23498
|
-
"- Explicit
|
|
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.",
|
|
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.",
|
|
23499
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.",
|
|
23500
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.",
|
|
23501
23787
|
"- `devrouter workspace cleanup --repo . --inactive-for 30d --check-merged --json` is report-only and never mutates the workspace runtime, routes, ownership, Git, Docker, applications, worktrees, or branches. It reports ownership, workspace runtime registration, runtime state (`running|stopped|busy|not-found|absent|unknown`), checkout, advisory activity, route, and integration evidence. Local DevPod/Devsy list/status checks always run; `--check-merged` alone enables read-only origin and matching GitHub/GitLab checks. Treat `not-found` as stale runtime after Docker pruning; busy, unavailable, or conflicting evidence suppresses destructive suggestions. Explicit `gc`/`down` can remove exact stale registration only after expected-ID `NotFound` proof and ownership revalidation. Runtime `lastUsed` remains advisory.",
|
|
@@ -23665,7 +23951,7 @@ var init_ai_prompt = __esm({
|
|
|
23665
23951
|
purpose: "Write/update devrouter section in the repo's AGENTS.md and install the devrouter skill."
|
|
23666
23952
|
},
|
|
23667
23953
|
{
|
|
23668
|
-
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]",
|
|
23669
23955
|
purpose: "Canonical startup and proof for an exact primary or linked checkout; atomically publishes routes after readiness."
|
|
23670
23956
|
},
|
|
23671
23957
|
{
|
|
@@ -24383,11 +24669,11 @@ function extractCurrentVersionFromRepoConfig(repoPath) {
|
|
|
24383
24669
|
};
|
|
24384
24670
|
}
|
|
24385
24671
|
function readPromptDirectory(promptDirPath) {
|
|
24386
|
-
if (!
|
|
24672
|
+
if (!import_node_fs43.default.existsSync(promptDirPath)) {
|
|
24387
24673
|
throw new Error(`Missing ${UPGRADE_PROMPTS_DIR} directory at ${promptDirPath}.`);
|
|
24388
24674
|
}
|
|
24389
24675
|
const releases = [];
|
|
24390
|
-
const files =
|
|
24676
|
+
const files = import_node_fs43.default.readdirSync(promptDirPath, { withFileTypes: true });
|
|
24391
24677
|
for (const file of files) {
|
|
24392
24678
|
if (!file.isFile() || !file.name.endsWith(".md")) {
|
|
24393
24679
|
continue;
|
|
@@ -24398,7 +24684,7 @@ function readPromptDirectory(promptDirPath) {
|
|
|
24398
24684
|
}
|
|
24399
24685
|
const version = normalizeVersion(basename);
|
|
24400
24686
|
const promptPath = import_node_path55.default.join(promptDirPath, file.name);
|
|
24401
|
-
const prompt =
|
|
24687
|
+
const prompt = import_node_fs43.default.readFileSync(promptPath, "utf-8").trim();
|
|
24402
24688
|
releases.push({ version, prompt, promptPath });
|
|
24403
24689
|
}
|
|
24404
24690
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -24423,7 +24709,7 @@ function resolvePromptDirectory(explicitPath) {
|
|
|
24423
24709
|
}
|
|
24424
24710
|
const entryFile = process.argv[1] ? import_node_path55.default.resolve(process.argv[1]) : __filename;
|
|
24425
24711
|
const entryDir = import_node_path55.default.dirname(entryFile);
|
|
24426
|
-
const resolvedEntryDir =
|
|
24712
|
+
const resolvedEntryDir = import_node_fs43.default.existsSync(entryFile) ? import_node_path55.default.dirname(import_node_fs43.default.realpathSync(entryFile)) : entryDir;
|
|
24427
24713
|
const candidates = [
|
|
24428
24714
|
import_node_path55.default.resolve(resolvedEntryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24429
24715
|
import_node_path55.default.resolve(entryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
@@ -24431,7 +24717,7 @@ function resolvePromptDirectory(explicitPath) {
|
|
|
24431
24717
|
import_node_path55.default.resolve(__dirname, "..", "..", UPGRADE_PROMPTS_DIR),
|
|
24432
24718
|
import_node_path55.default.resolve(process.cwd(), UPGRADE_PROMPTS_DIR)
|
|
24433
24719
|
];
|
|
24434
|
-
const existing = candidates.find((candidate) =>
|
|
24720
|
+
const existing = candidates.find((candidate) => import_node_fs43.default.existsSync(candidate));
|
|
24435
24721
|
return existing ?? candidates[0];
|
|
24436
24722
|
}
|
|
24437
24723
|
function loadUpgradeCatalog(options = {}) {
|
|
@@ -24447,11 +24733,11 @@ function loadUpgradeCatalog(options = {}) {
|
|
|
24447
24733
|
releases
|
|
24448
24734
|
};
|
|
24449
24735
|
}
|
|
24450
|
-
var
|
|
24736
|
+
var import_node_fs43, import_node_path55, SEMVER_RE, UPGRADE_PROMPTS_DIR;
|
|
24451
24737
|
var init_upgrade = __esm({
|
|
24452
24738
|
"src/core/upgrade.ts"() {
|
|
24453
24739
|
"use strict";
|
|
24454
|
-
|
|
24740
|
+
import_node_fs43 = __toESM(require("fs"));
|
|
24455
24741
|
import_node_path55 = __toESM(require("path"));
|
|
24456
24742
|
init_repo_config();
|
|
24457
24743
|
SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)$/;
|
|
@@ -24605,7 +24891,7 @@ function isLoopbackHost(host) {
|
|
|
24605
24891
|
return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
|
|
24606
24892
|
}
|
|
24607
24893
|
function inspectCompose(composeFile, _workspace) {
|
|
24608
|
-
if (!
|
|
24894
|
+
if (!import_node_fs44.default.existsSync(composeFile)) {
|
|
24609
24895
|
return {
|
|
24610
24896
|
aliases: [],
|
|
24611
24897
|
publishedPorts: [],
|
|
@@ -24614,7 +24900,7 @@ function inspectCompose(composeFile, _workspace) {
|
|
|
24614
24900
|
};
|
|
24615
24901
|
}
|
|
24616
24902
|
try {
|
|
24617
|
-
const raw =
|
|
24903
|
+
const raw = import_node_fs44.default.readFileSync(composeFile, "utf-8");
|
|
24618
24904
|
const parsed = import_yaml6.default.parse(raw);
|
|
24619
24905
|
const root = asRecord(parsed);
|
|
24620
24906
|
const services = asRecord(root?.services);
|
|
@@ -24712,7 +24998,7 @@ function buildHostPortClaimsCheck(repoPath, workspace) {
|
|
|
24712
24998
|
}
|
|
24713
24999
|
function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
24714
25000
|
const devcontainerDir = import_node_path56.default.join(repoPath, ".devcontainer");
|
|
24715
|
-
if (!
|
|
25001
|
+
if (!import_node_fs44.default.existsSync(devcontainerDir)) {
|
|
24716
25002
|
return [];
|
|
24717
25003
|
}
|
|
24718
25004
|
const compose = inspectCompose(import_node_path56.default.join(devcontainerDir, "docker-compose.yml"), workspace);
|
|
@@ -24743,8 +25029,8 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24743
25029
|
suggestion: compose.parseError || compose.publishedPorts.length > 0 ? "Remove published ports and route services through devnet aliases with devrouter proxy apps." : void 0
|
|
24744
25030
|
});
|
|
24745
25031
|
const dockerfilePath = import_node_path56.default.join(devcontainerDir, "Dockerfile");
|
|
24746
|
-
const dockerfileExists =
|
|
24747
|
-
const dockerfile = dockerfileExists ?
|
|
25032
|
+
const dockerfileExists = import_node_fs44.default.existsSync(dockerfilePath);
|
|
25033
|
+
const dockerfile = dockerfileExists ? import_node_fs44.default.readFileSync(dockerfilePath, "utf-8") : "";
|
|
24748
25034
|
const devrouterArtifacts = ["@devrouter/cli", "devrouter-process"].filter(
|
|
24749
25035
|
(artifact) => dockerfile.includes(artifact)
|
|
24750
25036
|
);
|
|
@@ -24802,11 +25088,11 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24802
25088
|
});
|
|
24803
25089
|
return checks;
|
|
24804
25090
|
}
|
|
24805
|
-
var
|
|
25091
|
+
var import_node_fs44, import_node_path56, import_yaml6;
|
|
24806
25092
|
var init_devcontainer_diagnostics = __esm({
|
|
24807
25093
|
"src/core/devcontainer-diagnostics.ts"() {
|
|
24808
25094
|
"use strict";
|
|
24809
|
-
|
|
25095
|
+
import_node_fs44 = __toESM(require("fs"));
|
|
24810
25096
|
import_node_path56 = __toESM(require("path"));
|
|
24811
25097
|
import_yaml6 = __toESM(require("yaml"));
|
|
24812
25098
|
init_devcontainer_profile();
|
|
@@ -24903,11 +25189,11 @@ function reconcileRouteRunConflict(repoPath, app) {
|
|
|
24903
25189
|
}
|
|
24904
25190
|
}
|
|
24905
25191
|
}
|
|
24906
|
-
var
|
|
25192
|
+
var import_node_fs45;
|
|
24907
25193
|
var init_route_state = __esm({
|
|
24908
25194
|
"src/core/route-state.ts"() {
|
|
24909
25195
|
"use strict";
|
|
24910
|
-
|
|
25196
|
+
import_node_fs45 = __toESM(require("fs"));
|
|
24911
25197
|
init_host_routes();
|
|
24912
25198
|
init_workspace();
|
|
24913
25199
|
}
|
|
@@ -25082,7 +25368,7 @@ function toRepoStatus(repoPath) {
|
|
|
25082
25368
|
const resolvedRepoPath = resolveRepoPath(repoPath);
|
|
25083
25369
|
const configPath = getRepoConfigPath(resolvedRepoPath);
|
|
25084
25370
|
const explicitRepo = typeof repoPath === "string" && repoPath.trim().length > 0;
|
|
25085
|
-
const configExists =
|
|
25371
|
+
const configExists = import_node_fs46.default.existsSync(configPath);
|
|
25086
25372
|
if (!explicitRepo && !configExists) {
|
|
25087
25373
|
return void 0;
|
|
25088
25374
|
}
|
|
@@ -25235,11 +25521,11 @@ async function collectRouterStatus(repoPath) {
|
|
|
25235
25521
|
}
|
|
25236
25522
|
};
|
|
25237
25523
|
}
|
|
25238
|
-
var
|
|
25524
|
+
var import_node_fs46;
|
|
25239
25525
|
var init_status = __esm({
|
|
25240
25526
|
"src/core/status.ts"() {
|
|
25241
25527
|
"use strict";
|
|
25242
|
-
|
|
25528
|
+
import_node_fs46 = __toESM(require("fs"));
|
|
25243
25529
|
init_docker();
|
|
25244
25530
|
init_managed_runtime_state();
|
|
25245
25531
|
init_managed_runtime_status();
|
|
@@ -25301,14 +25587,14 @@ ${env}
|
|
|
25301
25587
|
function readInstalledIdleFor(plistPath) {
|
|
25302
25588
|
let contents;
|
|
25303
25589
|
try {
|
|
25304
|
-
contents =
|
|
25590
|
+
contents = import_node_fs47.default.readFileSync(plistPath, "utf-8");
|
|
25305
25591
|
} catch {
|
|
25306
25592
|
return void 0;
|
|
25307
25593
|
}
|
|
25308
25594
|
return /<string>--idle-for<\/string>\s*<string>([^<]+)<\/string>/.exec(contents)?.[1] ?? "unknown";
|
|
25309
25595
|
}
|
|
25310
25596
|
function locateTool(name) {
|
|
25311
|
-
const result = (0,
|
|
25597
|
+
const result = (0, import_node_child_process36.spawnSync)("/bin/sh", ["-c", `command -v ${name}`], { encoding: "utf-8" });
|
|
25312
25598
|
const found = result.status === 0 ? result.stdout.trim() : "";
|
|
25313
25599
|
return found.startsWith("/") ? found : void 0;
|
|
25314
25600
|
}
|
|
@@ -25334,9 +25620,9 @@ function installIdleSweep(input2) {
|
|
|
25334
25620
|
throw new Error("The idle sweep uses launchd and is only available on macOS.");
|
|
25335
25621
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25336
25622
|
const launchctl = input2.launchctl ?? defaultLaunchctl;
|
|
25337
|
-
const entryPath = input2.entryPath ??
|
|
25338
|
-
|
|
25339
|
-
|
|
25623
|
+
const entryPath = input2.entryPath ?? import_node_fs47.default.realpathSync(process.argv[1]);
|
|
25624
|
+
import_node_fs47.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25625
|
+
import_node_fs47.default.mkdirSync(import_node_path57.default.dirname(paths.plist), { recursive: true });
|
|
25340
25626
|
const contents = renderIdleSweepPlist({
|
|
25341
25627
|
nodePath: process.execPath,
|
|
25342
25628
|
entryPath,
|
|
@@ -25345,7 +25631,7 @@ function installIdleSweep(input2) {
|
|
|
25345
25631
|
logPath: paths.log
|
|
25346
25632
|
});
|
|
25347
25633
|
launchctl(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25348
|
-
|
|
25634
|
+
import_node_fs47.default.writeFileSync(paths.plist, contents, { mode: 420 });
|
|
25349
25635
|
const loaded = launchctl(["bootstrap", launchDomain(), paths.plist]);
|
|
25350
25636
|
if (loaded.status !== 0)
|
|
25351
25637
|
throw new Error(
|
|
@@ -25355,9 +25641,9 @@ function installIdleSweep(input2) {
|
|
|
25355
25641
|
}
|
|
25356
25642
|
function removeIdleSweep(input2 = {}) {
|
|
25357
25643
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25358
|
-
if (!
|
|
25644
|
+
if (!import_node_fs47.default.existsSync(paths.plist)) return false;
|
|
25359
25645
|
(input2.launchctl ?? defaultLaunchctl)(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25360
|
-
|
|
25646
|
+
import_node_fs47.default.rmSync(paths.plist, { force: true });
|
|
25361
25647
|
return true;
|
|
25362
25648
|
}
|
|
25363
25649
|
function summarizeSweep(idleFor, stops, error) {
|
|
@@ -25372,13 +25658,13 @@ function summarizeSweep(idleFor, stops, error) {
|
|
|
25372
25658
|
};
|
|
25373
25659
|
}
|
|
25374
25660
|
function writeLastSweep(record6, paths = idleSweepPaths()) {
|
|
25375
|
-
|
|
25376
|
-
|
|
25661
|
+
import_node_fs47.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25662
|
+
import_node_fs47.default.writeFileSync(paths.lastSweep, `${JSON.stringify(record6, null, 2)}
|
|
25377
25663
|
`, { mode: 384 });
|
|
25378
25664
|
}
|
|
25379
25665
|
function readLastSweep(paths) {
|
|
25380
25666
|
try {
|
|
25381
|
-
return JSON.parse(
|
|
25667
|
+
return JSON.parse(import_node_fs47.default.readFileSync(paths.lastSweep, "utf-8"));
|
|
25382
25668
|
} catch {
|
|
25383
25669
|
return void 0;
|
|
25384
25670
|
}
|
|
@@ -25423,12 +25709,12 @@ function idleSweepCheck(paths = idleSweepPaths(), nowMs = Date.now()) {
|
|
|
25423
25709
|
...stale || last.failed > 0 ? { suggestion: `Inspect: ${paths.log}` } : {}
|
|
25424
25710
|
};
|
|
25425
25711
|
}
|
|
25426
|
-
var
|
|
25712
|
+
var import_node_child_process36, import_node_fs47, import_node_os7, import_node_path57, IDLE_SWEEP_LABEL, SWEEP_INTERVAL_SECONDS, SYSTEM_PATH, defaultLaunchctl;
|
|
25427
25713
|
var init_idle_sweep = __esm({
|
|
25428
25714
|
"src/core/idle-sweep.ts"() {
|
|
25429
25715
|
"use strict";
|
|
25430
|
-
|
|
25431
|
-
|
|
25716
|
+
import_node_child_process36 = require("child_process");
|
|
25717
|
+
import_node_fs47 = __toESM(require("fs"));
|
|
25432
25718
|
import_node_os7 = __toESM(require("os"));
|
|
25433
25719
|
import_node_path57 = __toESM(require("path"));
|
|
25434
25720
|
init_router();
|
|
@@ -25436,7 +25722,7 @@ var init_idle_sweep = __esm({
|
|
|
25436
25722
|
SWEEP_INTERVAL_SECONDS = 300;
|
|
25437
25723
|
SYSTEM_PATH = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
25438
25724
|
defaultLaunchctl = (args) => {
|
|
25439
|
-
const result = (0,
|
|
25725
|
+
const result = (0, import_node_child_process36.spawnSync)("launchctl", args, { encoding: "utf-8" });
|
|
25440
25726
|
return { status: result.status, stderr: result.stderr || result.error?.message || "" };
|
|
25441
25727
|
};
|
|
25442
25728
|
}
|
|
@@ -25450,7 +25736,7 @@ function outputFromResult(result) {
|
|
|
25450
25736
|
return output2.length > 0 ? output2 : void 0;
|
|
25451
25737
|
}
|
|
25452
25738
|
function runTool(command, args = []) {
|
|
25453
|
-
const result = (0,
|
|
25739
|
+
const result = (0, import_node_child_process37.spawnSync)(command, args, {
|
|
25454
25740
|
encoding: "utf-8"
|
|
25455
25741
|
});
|
|
25456
25742
|
if (result.error) {
|
|
@@ -25508,11 +25794,11 @@ function parseMinimumNodeMajor(value) {
|
|
|
25508
25794
|
}
|
|
25509
25795
|
function readPackageJson(repoPath) {
|
|
25510
25796
|
const packagePath = import_node_path58.default.join(repoPath, "package.json");
|
|
25511
|
-
if (!
|
|
25797
|
+
if (!import_node_fs48.default.existsSync(packagePath)) {
|
|
25512
25798
|
return void 0;
|
|
25513
25799
|
}
|
|
25514
25800
|
try {
|
|
25515
|
-
return JSON.parse(
|
|
25801
|
+
return JSON.parse(import_node_fs48.default.readFileSync(packagePath, "utf-8"));
|
|
25516
25802
|
} catch {
|
|
25517
25803
|
return void 0;
|
|
25518
25804
|
}
|
|
@@ -25617,17 +25903,17 @@ function realpathOrUndefined(value) {
|
|
|
25617
25903
|
return void 0;
|
|
25618
25904
|
}
|
|
25619
25905
|
try {
|
|
25620
|
-
return
|
|
25906
|
+
return import_node_fs48.default.realpathSync(value);
|
|
25621
25907
|
} catch {
|
|
25622
25908
|
return void 0;
|
|
25623
25909
|
}
|
|
25624
25910
|
}
|
|
25625
25911
|
function isExecutableFile(filePath) {
|
|
25626
25912
|
try {
|
|
25627
|
-
if (!
|
|
25913
|
+
if (!import_node_fs48.default.statSync(filePath).isFile()) {
|
|
25628
25914
|
return false;
|
|
25629
25915
|
}
|
|
25630
|
-
|
|
25916
|
+
import_node_fs48.default.accessSync(filePath, import_node_fs48.default.constants.X_OK);
|
|
25631
25917
|
return true;
|
|
25632
25918
|
} catch {
|
|
25633
25919
|
return false;
|
|
@@ -25641,7 +25927,7 @@ function displayPath(filePath) {
|
|
|
25641
25927
|
return `~${filePath.slice(home.length)}`;
|
|
25642
25928
|
}
|
|
25643
25929
|
function probeInstalledCliVersion(executable) {
|
|
25644
|
-
const result = (0,
|
|
25930
|
+
const result = (0, import_node_child_process37.spawnSync)(executable, ["-V"], {
|
|
25645
25931
|
encoding: "utf-8",
|
|
25646
25932
|
timeout: CLI_PATH_PROBE_TIMEOUT_MS
|
|
25647
25933
|
});
|
|
@@ -25652,7 +25938,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
25652
25938
|
}
|
|
25653
25939
|
function buildCliPathCheck(options = {}) {
|
|
25654
25940
|
const id5 = "global.cli-path";
|
|
25655
|
-
const runningVersion = options.runningVersion ?? (true ? "0.6.
|
|
25941
|
+
const runningVersion = options.runningVersion ?? (true ? "0.6.4" : "0.0.0-dev");
|
|
25656
25942
|
if (runningVersion === "0.0.0-dev") {
|
|
25657
25943
|
return {
|
|
25658
25944
|
id: id5,
|
|
@@ -25826,12 +26112,12 @@ function buildGlobalToolChecksWithoutTelemetry(repoPath) {
|
|
|
25826
26112
|
checks.push(nodeToolchainCheck(repoPath));
|
|
25827
26113
|
return checks;
|
|
25828
26114
|
}
|
|
25829
|
-
var
|
|
26115
|
+
var import_node_child_process37, import_node_fs48, import_node_path58, DEVSY_DISABLE_TELEMETRY, CLI_PATH_PROBE_TIMEOUT_MS, INSTALLED_CLI_VERSION_RE;
|
|
25830
26116
|
var init_tool_diagnostics = __esm({
|
|
25831
26117
|
"src/core/tool-diagnostics.ts"() {
|
|
25832
26118
|
"use strict";
|
|
25833
|
-
|
|
25834
|
-
|
|
26119
|
+
import_node_child_process37 = require("child_process");
|
|
26120
|
+
import_node_fs48 = __toESM(require("fs"));
|
|
25835
26121
|
import_node_path58 = __toESM(require("path"));
|
|
25836
26122
|
init_devsy_agent();
|
|
25837
26123
|
init_idle_sweep();
|
|
@@ -26182,11 +26468,11 @@ function inspectPostgresCredentials(repoPath, config) {
|
|
|
26182
26468
|
parseErrors.push(`${app.name}: ${composeFile} (${message})`);
|
|
26183
26469
|
continue;
|
|
26184
26470
|
}
|
|
26185
|
-
if (!
|
|
26471
|
+
if (!import_node_fs49.default.existsSync(absolutePath)) {
|
|
26186
26472
|
continue;
|
|
26187
26473
|
}
|
|
26188
26474
|
try {
|
|
26189
|
-
const raw =
|
|
26475
|
+
const raw = import_node_fs49.default.readFileSync(absolutePath, "utf-8");
|
|
26190
26476
|
const parsed = import_yaml7.default.parse(raw);
|
|
26191
26477
|
const root = asRecord2(parsed);
|
|
26192
26478
|
const services = asRecord2(root?.services);
|
|
@@ -26550,7 +26836,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26550
26836
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
26551
26837
|
});
|
|
26552
26838
|
}
|
|
26553
|
-
const cliVersion = true ? "0.6.
|
|
26839
|
+
const cliVersion = true ? "0.6.4" : "0.0.0-dev";
|
|
26554
26840
|
const configVersion = config.devrouter?.version;
|
|
26555
26841
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
26556
26842
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -26588,7 +26874,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26588
26874
|
filePath,
|
|
26589
26875
|
absolutePath: import_node_path60.default.resolve(repo.path, filePath)
|
|
26590
26876
|
}))
|
|
26591
|
-
).filter((entry) => !
|
|
26877
|
+
).filter((entry) => !import_node_fs49.default.existsSync(entry.absolutePath));
|
|
26592
26878
|
addCheck(checks, {
|
|
26593
26879
|
id: "repo.compose-files",
|
|
26594
26880
|
level: missingComposeFiles.length === 0 ? "ok" : "error",
|
|
@@ -26632,7 +26918,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26632
26918
|
app: app.name,
|
|
26633
26919
|
cwd: app.hostRun.cwd,
|
|
26634
26920
|
absolutePath: import_node_path60.default.resolve(repo.path, app.hostRun.cwd)
|
|
26635
|
-
})).filter((entry) => !
|
|
26921
|
+
})).filter((entry) => !import_node_fs49.default.existsSync(entry.absolutePath));
|
|
26636
26922
|
addCheck(checks, {
|
|
26637
26923
|
id: "repo.host-cwd",
|
|
26638
26924
|
level: missingHostCwds.length === 0 ? "ok" : "error",
|
|
@@ -26776,11 +27062,11 @@ async function buildDoctorReport(options = {}) {
|
|
|
26776
27062
|
nextSteps
|
|
26777
27063
|
};
|
|
26778
27064
|
}
|
|
26779
|
-
var
|
|
27065
|
+
var import_node_fs49, import_node_path60, import_yaml7, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
|
|
26780
27066
|
var init_doctor = __esm({
|
|
26781
27067
|
"src/core/doctor.ts"() {
|
|
26782
27068
|
"use strict";
|
|
26783
|
-
|
|
27069
|
+
import_node_fs49 = __toESM(require("fs"));
|
|
26784
27070
|
import_node_path60 = __toESM(require("path"));
|
|
26785
27071
|
import_yaml7 = __toESM(require("yaml"));
|
|
26786
27072
|
init_capacity_store();
|
|
@@ -26810,6 +27096,7 @@ var init_doctor = __esm({
|
|
|
26810
27096
|
"journal-directory-unsafe": "Restore private ownership and mode 0700 on the reliability journal directory, then retry.",
|
|
26811
27097
|
"journal-directory-unreadable": "Restore read access to the reliability journal directory, then retry.",
|
|
26812
27098
|
"journal-invalid": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
27099
|
+
"journal-writer-newer": "Use the devrouter CLI that wrote the named journal or a newer version before retrying admission; preserve the journal.",
|
|
26813
27100
|
"journal-unreadable": "Preserve the named journal entry and restore verified history before retrying admission.",
|
|
26814
27101
|
"journal-entry-unsafe": "Restore private ownership, mode 0600 and a bounded size on the named journal entry, then retry."
|
|
26815
27102
|
};
|
|
@@ -27177,12 +27464,12 @@ function parseSsPortListeners(stdout, port) {
|
|
|
27177
27464
|
return listeners;
|
|
27178
27465
|
}
|
|
27179
27466
|
function findPortListeners(port) {
|
|
27180
|
-
const result = (0,
|
|
27467
|
+
const result = (0, import_node_child_process38.spawnSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
|
|
27181
27468
|
encoding: "utf-8"
|
|
27182
27469
|
});
|
|
27183
27470
|
if (result.error && result.error.code === "ENOENT") {
|
|
27184
27471
|
if (process.platform === "linux") {
|
|
27185
|
-
const ssResult = (0,
|
|
27472
|
+
const ssResult = (0, import_node_child_process38.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
27186
27473
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
27187
27474
|
return parseSsPortListeners(ssResult.stdout, port);
|
|
27188
27475
|
}
|
|
@@ -27211,11 +27498,11 @@ function findPortListeners(port) {
|
|
|
27211
27498
|
};
|
|
27212
27499
|
});
|
|
27213
27500
|
}
|
|
27214
|
-
var
|
|
27501
|
+
var import_node_child_process38;
|
|
27215
27502
|
var init_ports = __esm({
|
|
27216
27503
|
"src/util/ports.ts"() {
|
|
27217
27504
|
"use strict";
|
|
27218
|
-
|
|
27505
|
+
import_node_child_process38 = require("child_process");
|
|
27219
27506
|
}
|
|
27220
27507
|
});
|
|
27221
27508
|
|
|
@@ -27302,6 +27589,7 @@ async function runEnsureCommand(options) {
|
|
|
27302
27589
|
profile: options.profile,
|
|
27303
27590
|
...options.repair ? { repair: true } : {},
|
|
27304
27591
|
...options.initializeNew ? { initializeNew: true } : {},
|
|
27592
|
+
...options.replaceApp ? { replaceApp: true } : {},
|
|
27305
27593
|
...options.variant !== void 0 ? { variant: options.variant } : {}
|
|
27306
27594
|
};
|
|
27307
27595
|
const result = await superviseLifecycle(
|
|
@@ -27549,7 +27837,7 @@ function buildHostEnvReport(input2) {
|
|
|
27549
27837
|
};
|
|
27550
27838
|
}
|
|
27551
27839
|
function listDevcontainerContainers(repoPath) {
|
|
27552
|
-
const listed = (0,
|
|
27840
|
+
const listed = (0, import_node_child_process39.spawnSync)(
|
|
27553
27841
|
"docker",
|
|
27554
27842
|
[
|
|
27555
27843
|
"ps",
|
|
@@ -27570,7 +27858,7 @@ function listDevcontainerContainers(repoPath) {
|
|
|
27570
27858
|
}
|
|
27571
27859
|
}
|
|
27572
27860
|
function dockerPortBindings(containerId, port) {
|
|
27573
|
-
const result = (0,
|
|
27861
|
+
const result = (0, import_node_child_process39.spawnSync)("docker", ["port", containerId, `${port}/tcp`], {
|
|
27574
27862
|
encoding: "utf-8",
|
|
27575
27863
|
...networkDockerOptions()
|
|
27576
27864
|
});
|
|
@@ -27685,11 +27973,11 @@ function hostEnvVariables(report, processEnv) {
|
|
|
27685
27973
|
}
|
|
27686
27974
|
return variables;
|
|
27687
27975
|
}
|
|
27688
|
-
var
|
|
27976
|
+
var import_node_child_process39, import_node_path61, LOOPBACK_UPSTREAM_HOSTS, ROUTED_TCP_PARAMS;
|
|
27689
27977
|
var init_host_env = __esm({
|
|
27690
27978
|
"src/core/host-env.ts"() {
|
|
27691
27979
|
"use strict";
|
|
27692
|
-
|
|
27980
|
+
import_node_child_process39 = require("child_process");
|
|
27693
27981
|
import_node_path61 = __toESM(require("path"));
|
|
27694
27982
|
init_devcontainer_profile();
|
|
27695
27983
|
init_devpod_environment();
|
|
@@ -27787,7 +28075,7 @@ function hostCommandEnvironment(report, processEnv) {
|
|
|
27787
28075
|
}
|
|
27788
28076
|
function runHostCommand(command, env) {
|
|
27789
28077
|
return new Promise((resolve) => {
|
|
27790
|
-
const child = (0,
|
|
28078
|
+
const child = (0, import_node_child_process40.spawn)(command[0], command.slice(1), { env, stdio: "inherit" });
|
|
27791
28079
|
const forward = (signal) => () => child.kill(signal);
|
|
27792
28080
|
const handlers = [
|
|
27793
28081
|
["SIGINT", forward("SIGINT")],
|
|
@@ -27827,11 +28115,11 @@ async function runEnvCommand(invocation) {
|
|
|
27827
28115
|
}
|
|
27828
28116
|
process.stdout.write(formatEnvReport(report));
|
|
27829
28117
|
}
|
|
27830
|
-
var
|
|
28118
|
+
var import_node_child_process40, import_node_os8, HOST_PORT_ENV_PREFIX;
|
|
27831
28119
|
var init_env = __esm({
|
|
27832
28120
|
"src/commands/env.ts"() {
|
|
27833
28121
|
"use strict";
|
|
27834
|
-
|
|
28122
|
+
import_node_child_process40 = require("child_process");
|
|
27835
28123
|
import_node_os8 = require("os");
|
|
27836
28124
|
init_host_env();
|
|
27837
28125
|
init_managed_host_ports();
|
|
@@ -27881,7 +28169,7 @@ var init_status2 = __esm({
|
|
|
27881
28169
|
|
|
27882
28170
|
// src/core/harness-continuation.ts
|
|
27883
28171
|
function harnessContinuationPath(repoRoot) {
|
|
27884
|
-
const key = (0,
|
|
28172
|
+
const key = (0, import_node_crypto31.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
|
|
27885
28173
|
return import_node_path62.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
|
|
27886
28174
|
}
|
|
27887
28175
|
function counter4(value) {
|
|
@@ -27895,7 +28183,7 @@ function validEntry(value) {
|
|
|
27895
28183
|
function readLedgerSync(file, nowMs) {
|
|
27896
28184
|
let stat;
|
|
27897
28185
|
try {
|
|
27898
|
-
stat =
|
|
28186
|
+
stat = import_node_fs50.default.lstatSync(file);
|
|
27899
28187
|
} catch {
|
|
27900
28188
|
return [];
|
|
27901
28189
|
}
|
|
@@ -27903,7 +28191,7 @@ function readLedgerSync(file, nowMs) {
|
|
|
27903
28191
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0) return [];
|
|
27904
28192
|
let parsed;
|
|
27905
28193
|
try {
|
|
27906
|
-
parsed = JSON.parse(
|
|
28194
|
+
parsed = JSON.parse(import_node_fs50.default.readFileSync(file, "utf-8"));
|
|
27907
28195
|
} catch {
|
|
27908
28196
|
return [];
|
|
27909
28197
|
}
|
|
@@ -27923,7 +28211,7 @@ function claimHarnessContinuation(repoRoot, claim2) {
|
|
|
27923
28211
|
const nowMs = claim2.nowMs ?? Date.now();
|
|
27924
28212
|
try {
|
|
27925
28213
|
const file = harnessContinuationPath(repoRoot);
|
|
27926
|
-
|
|
28214
|
+
import_node_fs50.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27927
28215
|
return withFileLockSync(
|
|
27928
28216
|
`${file}.lock`,
|
|
27929
28217
|
{ activity: "harness continuation claim", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27955,7 +28243,7 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27955
28243
|
const nowMs = settlement.nowMs ?? Date.now();
|
|
27956
28244
|
try {
|
|
27957
28245
|
const file = harnessContinuationPath(repoRoot);
|
|
27958
|
-
|
|
28246
|
+
import_node_fs50.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27959
28247
|
withFileLockSync(
|
|
27960
28248
|
`${file}.lock`,
|
|
27961
28249
|
{ activity: "harness continuation settlement", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27979,12 +28267,12 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27979
28267
|
} catch {
|
|
27980
28268
|
}
|
|
27981
28269
|
}
|
|
27982
|
-
var
|
|
28270
|
+
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;
|
|
27983
28271
|
var init_harness_continuation = __esm({
|
|
27984
28272
|
"src/core/harness-continuation.ts"() {
|
|
27985
28273
|
"use strict";
|
|
27986
|
-
|
|
27987
|
-
|
|
28274
|
+
import_node_crypto31 = require("crypto");
|
|
28275
|
+
import_node_fs50 = __toESM(require("fs"));
|
|
27988
28276
|
import_node_path62 = __toESM(require("path"));
|
|
27989
28277
|
init_atomic_file();
|
|
27990
28278
|
init_file_lock();
|
|
@@ -28006,7 +28294,7 @@ function isTransitionalHarnessPhase(phase) {
|
|
|
28006
28294
|
function findHarnessGateRepoRoot(cwd) {
|
|
28007
28295
|
let current = import_node_path63.default.resolve(cwd);
|
|
28008
28296
|
for (let depth = 0; depth < REPO_ROOT_MAX_DEPTH; depth += 1) {
|
|
28009
|
-
if (
|
|
28297
|
+
if (import_node_fs51.default.existsSync(import_node_path63.default.join(current, ".devrouter.yml"))) {
|
|
28010
28298
|
return current;
|
|
28011
28299
|
}
|
|
28012
28300
|
const parent = import_node_path63.default.dirname(current);
|
|
@@ -28101,11 +28389,11 @@ function parseHarnessGateBudget(value) {
|
|
|
28101
28389
|
}
|
|
28102
28390
|
return Math.min(Math.trunc(parsed), HARNESS_GATE_MAX_BUDGET_MS);
|
|
28103
28391
|
}
|
|
28104
|
-
var
|
|
28392
|
+
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;
|
|
28105
28393
|
var init_harness_gate = __esm({
|
|
28106
28394
|
"src/core/harness-gate.ts"() {
|
|
28107
28395
|
"use strict";
|
|
28108
|
-
|
|
28396
|
+
import_node_fs51 = __toESM(require("fs"));
|
|
28109
28397
|
import_node_path63 = __toESM(require("path"));
|
|
28110
28398
|
init_reliability_operation_store();
|
|
28111
28399
|
init_workspace();
|
|
@@ -28365,7 +28653,7 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28365
28653
|
}
|
|
28366
28654
|
const budgetMs = parseHarnessGateBudget(options.waitBudgetMs);
|
|
28367
28655
|
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;
|
|
28368
|
-
const payloadSha256 = (0,
|
|
28656
|
+
const payloadSha256 = (0, import_node_crypto32.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
|
|
28369
28657
|
const claim2 = dependencies.claim ?? ((root, input2) => {
|
|
28370
28658
|
const outcome = claimHarnessContinuation(root, input2);
|
|
28371
28659
|
if (outcome.kind === "claimed") {
|
|
@@ -28473,11 +28761,11 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28473
28761
|
`
|
|
28474
28762
|
);
|
|
28475
28763
|
}
|
|
28476
|
-
var
|
|
28764
|
+
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;
|
|
28477
28765
|
var init_harness = __esm({
|
|
28478
28766
|
"src/commands/harness.ts"() {
|
|
28479
28767
|
"use strict";
|
|
28480
|
-
|
|
28768
|
+
import_node_crypto32 = require("crypto");
|
|
28481
28769
|
init_harness_continuation();
|
|
28482
28770
|
init_harness_gate();
|
|
28483
28771
|
MAX_HOOK_PAYLOAD_BYTES = 256 * 1024;
|
|
@@ -28593,7 +28881,7 @@ async function runOpenCommand(name) {
|
|
|
28593
28881
|
);
|
|
28594
28882
|
return;
|
|
28595
28883
|
}
|
|
28596
|
-
const result = (0,
|
|
28884
|
+
const result = (0, import_node_child_process41.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
28597
28885
|
if (result.status !== 0) {
|
|
28598
28886
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
28599
28887
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -28601,11 +28889,11 @@ async function runOpenCommand(name) {
|
|
|
28601
28889
|
process.stdout.write(`Opened ${url}
|
|
28602
28890
|
`);
|
|
28603
28891
|
}
|
|
28604
|
-
var
|
|
28892
|
+
var import_node_child_process41;
|
|
28605
28893
|
var init_open = __esm({
|
|
28606
28894
|
"src/commands/open.ts"() {
|
|
28607
28895
|
"use strict";
|
|
28608
|
-
|
|
28896
|
+
import_node_child_process41 = require("child_process");
|
|
28609
28897
|
init_docker();
|
|
28610
28898
|
init_host_routes();
|
|
28611
28899
|
init_repo_config();
|
|
@@ -28649,7 +28937,7 @@ async function runLogsCommand(options) {
|
|
|
28649
28937
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
28650
28938
|
if (options.follow) {
|
|
28651
28939
|
args.splice(1, 0, "-f");
|
|
28652
|
-
const child = (0,
|
|
28940
|
+
const child = (0, import_node_child_process42.spawn)("docker", args, { stdio: "inherit" });
|
|
28653
28941
|
const onSignal = () => {
|
|
28654
28942
|
child.kill("SIGTERM");
|
|
28655
28943
|
};
|
|
@@ -28663,17 +28951,17 @@ async function runLogsCommand(options) {
|
|
|
28663
28951
|
});
|
|
28664
28952
|
});
|
|
28665
28953
|
} else {
|
|
28666
|
-
const result = (0,
|
|
28954
|
+
const result = (0, import_node_child_process42.spawnSync)("docker", args, { stdio: "inherit" });
|
|
28667
28955
|
if (result.status !== 0) {
|
|
28668
28956
|
throw new Error("Failed to retrieve router logs.");
|
|
28669
28957
|
}
|
|
28670
28958
|
}
|
|
28671
28959
|
}
|
|
28672
|
-
var
|
|
28960
|
+
var import_node_child_process42;
|
|
28673
28961
|
var init_logs = __esm({
|
|
28674
28962
|
"src/commands/logs.ts"() {
|
|
28675
28963
|
"use strict";
|
|
28676
|
-
|
|
28964
|
+
import_node_child_process42 = require("child_process");
|
|
28677
28965
|
init_docker();
|
|
28678
28966
|
init_lifecycle_diagnostics();
|
|
28679
28967
|
init_router();
|
|
@@ -28717,11 +29005,11 @@ function asRecord3(value) {
|
|
|
28717
29005
|
return value;
|
|
28718
29006
|
}
|
|
28719
29007
|
function readJson(filePath) {
|
|
28720
|
-
if (!
|
|
29008
|
+
if (!import_node_fs52.default.existsSync(filePath)) {
|
|
28721
29009
|
return void 0;
|
|
28722
29010
|
}
|
|
28723
29011
|
try {
|
|
28724
|
-
return JSON.parse(
|
|
29012
|
+
return JSON.parse(import_node_fs52.default.readFileSync(filePath, "utf-8"));
|
|
28725
29013
|
} catch {
|
|
28726
29014
|
return void 0;
|
|
28727
29015
|
}
|
|
@@ -28768,7 +29056,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
28768
29056
|
["bun.lock", "bun"]
|
|
28769
29057
|
];
|
|
28770
29058
|
for (const [fileName, name] of lockfiles) {
|
|
28771
|
-
if (
|
|
29059
|
+
if (import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28772
29060
|
return { name, source: fileName };
|
|
28773
29061
|
}
|
|
28774
29062
|
}
|
|
@@ -28784,8 +29072,8 @@ function inspectNode(repoPath, pkg) {
|
|
|
28784
29072
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
28785
29073
|
}
|
|
28786
29074
|
const nvmrc = import_node_path64.default.join(repoPath, ".nvmrc");
|
|
28787
|
-
if (
|
|
28788
|
-
const version =
|
|
29075
|
+
if (import_node_fs52.default.existsSync(nvmrc)) {
|
|
29076
|
+
const version = import_node_fs52.default.readFileSync(nvmrc, "utf-8").trim();
|
|
28789
29077
|
return { version, source: ".nvmrc" };
|
|
28790
29078
|
}
|
|
28791
29079
|
return void 0;
|
|
@@ -28864,7 +29152,7 @@ function composeFiles(repoPath) {
|
|
|
28864
29152
|
...configuredComposeFiles(repoPath)
|
|
28865
29153
|
];
|
|
28866
29154
|
return Array.from(new Set(candidates)).filter(
|
|
28867
|
-
(fileName) =>
|
|
29155
|
+
(fileName) => import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))
|
|
28868
29156
|
);
|
|
28869
29157
|
}
|
|
28870
29158
|
function stringArray2(value) {
|
|
@@ -28902,7 +29190,7 @@ function inspectServices(repoPath) {
|
|
|
28902
29190
|
const services = [];
|
|
28903
29191
|
for (const fileName of composeFiles(repoPath)) {
|
|
28904
29192
|
try {
|
|
28905
|
-
const parsed = import_yaml8.default.parse(
|
|
29193
|
+
const parsed = import_yaml8.default.parse(import_node_fs52.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8"));
|
|
28906
29194
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
28907
29195
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
28908
29196
|
const service = asRecord3(value);
|
|
@@ -28937,8 +29225,8 @@ function inspectServices(repoPath) {
|
|
|
28937
29225
|
return services;
|
|
28938
29226
|
}
|
|
28939
29227
|
function inspectEnvFiles(repoPath) {
|
|
28940
|
-
const files =
|
|
28941
|
-
const content =
|
|
29228
|
+
const files = import_node_fs52.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
29229
|
+
const content = import_node_fs52.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8");
|
|
28942
29230
|
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();
|
|
28943
29231
|
return { path: fileName, names };
|
|
28944
29232
|
});
|
|
@@ -28953,17 +29241,17 @@ function inspectEnvFiles(repoPath) {
|
|
|
28953
29241
|
}
|
|
28954
29242
|
function inspectDevcontainer(repoPath) {
|
|
28955
29243
|
const dir = import_node_path64.default.join(repoPath, ".devcontainer");
|
|
28956
|
-
if (!
|
|
29244
|
+
if (!import_node_fs52.default.existsSync(dir)) {
|
|
28957
29245
|
return { exists: false, files: [] };
|
|
28958
29246
|
}
|
|
28959
29247
|
return {
|
|
28960
29248
|
exists: true,
|
|
28961
|
-
files:
|
|
29249
|
+
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}`)
|
|
28962
29250
|
};
|
|
28963
29251
|
}
|
|
28964
29252
|
function inspectDevrouter(repoPath) {
|
|
28965
29253
|
const configPath = getRepoConfigPath(repoPath);
|
|
28966
|
-
if (!
|
|
29254
|
+
if (!import_node_fs52.default.existsSync(configPath)) {
|
|
28967
29255
|
return {
|
|
28968
29256
|
exists: false,
|
|
28969
29257
|
configPath,
|
|
@@ -29007,15 +29295,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
29007
29295
|
["AGENTS.md", "agents"],
|
|
29008
29296
|
["CLAUDE.md", "claude"]
|
|
29009
29297
|
]) {
|
|
29010
|
-
if (
|
|
29298
|
+
if (import_node_fs52.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
29011
29299
|
results.push({ path: fileName, kind });
|
|
29012
29300
|
}
|
|
29013
29301
|
}
|
|
29014
29302
|
const skillsDir = import_node_path64.default.join(repoPath, ".agents", "skills");
|
|
29015
|
-
if (
|
|
29016
|
-
for (const name of
|
|
29303
|
+
if (import_node_fs52.default.existsSync(skillsDir)) {
|
|
29304
|
+
for (const name of import_node_fs52.default.readdirSync(skillsDir).sort()) {
|
|
29017
29305
|
const skillPath = import_node_path64.default.join(skillsDir, name, "SKILL.md");
|
|
29018
|
-
if (
|
|
29306
|
+
if (import_node_fs52.default.existsSync(skillPath)) {
|
|
29019
29307
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
29020
29308
|
}
|
|
29021
29309
|
}
|
|
@@ -29077,11 +29365,11 @@ function inspectRepo(options = {}) {
|
|
|
29077
29365
|
issues: buildIssues(reportWithoutIssues)
|
|
29078
29366
|
};
|
|
29079
29367
|
}
|
|
29080
|
-
var
|
|
29368
|
+
var import_node_fs52, import_node_path64, import_yaml8;
|
|
29081
29369
|
var init_repo_inspect = __esm({
|
|
29082
29370
|
"src/core/repo-inspect.ts"() {
|
|
29083
29371
|
"use strict";
|
|
29084
|
-
|
|
29372
|
+
import_node_fs52 = __toESM(require("fs"));
|
|
29085
29373
|
import_node_path64 = __toESM(require("path"));
|
|
29086
29374
|
import_yaml8 = __toESM(require("yaml"));
|
|
29087
29375
|
init_repo_config();
|
|
@@ -29187,7 +29475,7 @@ function requiredFileChecks(repoPath) {
|
|
|
29187
29475
|
".devcontainer/docker-compose.yml",
|
|
29188
29476
|
".devrouter.yml"
|
|
29189
29477
|
];
|
|
29190
|
-
const missing = required.filter((fileName) => !
|
|
29478
|
+
const missing = required.filter((fileName) => !import_node_fs53.default.existsSync(import_node_path65.default.join(repoPath, fileName)));
|
|
29191
29479
|
return {
|
|
29192
29480
|
id: "repo.devcontainer.verify-files",
|
|
29193
29481
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -29412,11 +29700,11 @@ async function verifyDevcontainer(options = {}) {
|
|
|
29412
29700
|
nextSteps: collectNextSteps3(checks)
|
|
29413
29701
|
};
|
|
29414
29702
|
}
|
|
29415
|
-
var
|
|
29703
|
+
var import_node_fs53, import_node_path65;
|
|
29416
29704
|
var init_devcontainer_verify = __esm({
|
|
29417
29705
|
"src/core/devcontainer-verify.ts"() {
|
|
29418
29706
|
"use strict";
|
|
29419
|
-
|
|
29707
|
+
import_node_fs53 = __toESM(require("fs"));
|
|
29420
29708
|
import_node_path65 = __toESM(require("path"));
|
|
29421
29709
|
init_capabilities();
|
|
29422
29710
|
init_doctor();
|
|
@@ -29760,7 +30048,7 @@ function plannedFiles(repoPath, version) {
|
|
|
29760
30048
|
}
|
|
29761
30049
|
function classifyFile(repoPath, file) {
|
|
29762
30050
|
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29763
|
-
if (!
|
|
30051
|
+
if (!import_node_fs54.default.existsSync(absolutePath)) {
|
|
29764
30052
|
return {
|
|
29765
30053
|
path: file.relativePath,
|
|
29766
30054
|
action: "create",
|
|
@@ -29768,7 +30056,7 @@ function classifyFile(repoPath, file) {
|
|
|
29768
30056
|
bytes: Buffer.byteLength(file.content)
|
|
29769
30057
|
};
|
|
29770
30058
|
}
|
|
29771
|
-
const current =
|
|
30059
|
+
const current = import_node_fs54.default.readFileSync(absolutePath, "utf-8");
|
|
29772
30060
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
29773
30061
|
return {
|
|
29774
30062
|
path: file.relativePath,
|
|
@@ -29826,10 +30114,10 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
29826
30114
|
}
|
|
29827
30115
|
function writeFile(repoPath, file) {
|
|
29828
30116
|
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29829
|
-
|
|
29830
|
-
|
|
30117
|
+
import_node_fs54.default.mkdirSync(import_node_path66.default.dirname(absolutePath), { recursive: true });
|
|
30118
|
+
import_node_fs54.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
29831
30119
|
if (file.executable) {
|
|
29832
|
-
|
|
30120
|
+
import_node_fs54.default.chmodSync(absolutePath, 493);
|
|
29833
30121
|
}
|
|
29834
30122
|
}
|
|
29835
30123
|
function writeDevcontainer(options = {}) {
|
|
@@ -29867,11 +30155,11 @@ function writeDevcontainer(options = {}) {
|
|
|
29867
30155
|
nextSteps: postWriteNextSteps(repoPath)
|
|
29868
30156
|
};
|
|
29869
30157
|
}
|
|
29870
|
-
var
|
|
30158
|
+
var import_node_fs54, import_node_path66, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
29871
30159
|
var init_devcontainer_write = __esm({
|
|
29872
30160
|
"src/core/devcontainer-write.ts"() {
|
|
29873
30161
|
"use strict";
|
|
29874
|
-
|
|
30162
|
+
import_node_fs54 = __toESM(require("fs"));
|
|
29875
30163
|
import_node_path66 = __toESM(require("path"));
|
|
29876
30164
|
init_repo_config();
|
|
29877
30165
|
init_repo_inspect();
|
|
@@ -30212,7 +30500,7 @@ function loadContract(repoPath, contractPath) {
|
|
|
30212
30500
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
30213
30501
|
let metadata;
|
|
30214
30502
|
try {
|
|
30215
|
-
metadata =
|
|
30503
|
+
metadata = import_node_fs55.default.lstatSync(absolutePath);
|
|
30216
30504
|
} catch (error) {
|
|
30217
30505
|
fail3(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
30218
30506
|
}
|
|
@@ -30222,10 +30510,10 @@ function loadContract(repoPath, contractPath) {
|
|
|
30222
30510
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
30223
30511
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30224
30512
|
}
|
|
30225
|
-
const realRepo =
|
|
30226
|
-
const realContract =
|
|
30513
|
+
const realRepo = import_node_fs55.default.realpathSync(repoPath);
|
|
30514
|
+
const realContract = import_node_fs55.default.realpathSync(absolutePath);
|
|
30227
30515
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
30228
|
-
const source =
|
|
30516
|
+
const source = import_node_fs55.default.readFileSync(absolutePath, "utf-8");
|
|
30229
30517
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
30230
30518
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30231
30519
|
}
|
|
@@ -30245,11 +30533,11 @@ function resolveProfilePlan(options) {
|
|
|
30245
30533
|
contractPath: loaded.contractPath
|
|
30246
30534
|
});
|
|
30247
30535
|
}
|
|
30248
|
-
var
|
|
30536
|
+
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;
|
|
30249
30537
|
var init_profile_plan = __esm({
|
|
30250
30538
|
"src/core/profile-plan.ts"() {
|
|
30251
30539
|
"use strict";
|
|
30252
|
-
|
|
30540
|
+
import_node_fs55 = __toESM(require("fs"));
|
|
30253
30541
|
import_node_path67 = __toESM(require("path"));
|
|
30254
30542
|
import_yaml9 = require("yaml");
|
|
30255
30543
|
init_paths();
|
|
@@ -30723,7 +31011,7 @@ function loadPreviewManifest(repoPath) {
|
|
|
30723
31011
|
const manifestPath = assertPathWithinRepo(MANIFEST_FILE_NAME, resolvedRepo, "Preview manifest");
|
|
30724
31012
|
let metadata;
|
|
30725
31013
|
try {
|
|
30726
|
-
metadata =
|
|
31014
|
+
metadata = import_node_fs56.default.lstatSync(manifestPath);
|
|
30727
31015
|
} catch (error) {
|
|
30728
31016
|
fail4(`could not inspect preview manifest '${MANIFEST_FILE_NAME}': ${error.message}`);
|
|
30729
31017
|
}
|
|
@@ -30733,24 +31021,24 @@ function loadPreviewManifest(repoPath) {
|
|
|
30733
31021
|
if (metadata.size > MAX_MANIFEST_BYTES) {
|
|
30734
31022
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30735
31023
|
}
|
|
30736
|
-
const realRepo =
|
|
30737
|
-
const realManifest =
|
|
31024
|
+
const realRepo = import_node_fs56.default.realpathSync(resolvedRepo);
|
|
31025
|
+
const realManifest = import_node_fs56.default.realpathSync(manifestPath);
|
|
30738
31026
|
assertPathWithinRepo(realManifest, realRepo, "Preview manifest");
|
|
30739
|
-
const source =
|
|
31027
|
+
const source = import_node_fs56.default.readFileSync(manifestPath, "utf-8");
|
|
30740
31028
|
if (Buffer.byteLength(source, "utf-8") > MAX_MANIFEST_BYTES) {
|
|
30741
31029
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30742
31030
|
}
|
|
30743
31031
|
return {
|
|
30744
31032
|
manifest: parsePreviewManifest(source),
|
|
30745
|
-
digest: (0,
|
|
31033
|
+
digest: (0, import_node_crypto33.createHash)("sha256").update(source, "utf-8").digest("hex")
|
|
30746
31034
|
};
|
|
30747
31035
|
}
|
|
30748
|
-
var
|
|
31036
|
+
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;
|
|
30749
31037
|
var init_manifest = __esm({
|
|
30750
31038
|
"src/core/preview/manifest.ts"() {
|
|
30751
31039
|
"use strict";
|
|
30752
|
-
|
|
30753
|
-
|
|
31040
|
+
import_node_crypto33 = require("crypto");
|
|
31041
|
+
import_node_fs56 = __toESM(require("fs"));
|
|
30754
31042
|
import_node_path69 = __toESM(require("path"));
|
|
30755
31043
|
import_yaml10 = require("yaml");
|
|
30756
31044
|
init_paths();
|
|
@@ -31894,7 +32182,7 @@ var init_state = __esm({
|
|
|
31894
32182
|
function previewIdentityKey(identity2) {
|
|
31895
32183
|
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)
|
|
31896
32184
|
throw new Error("Invalid immutable preview identity.");
|
|
31897
|
-
return (0,
|
|
32185
|
+
return (0, import_node_crypto34.createHash)("sha256").update(JSON.stringify([identity2.forgeHost, identity2.projectId, identity2.change])).digest("hex");
|
|
31898
32186
|
}
|
|
31899
32187
|
function costs(pool) {
|
|
31900
32188
|
return Object.values(pool.sessions).reduce((total, entry) => total + entry.reservedCents, 0);
|
|
@@ -31950,11 +32238,11 @@ function sessionReady(entry, now, expiresAt) {
|
|
|
31950
32238
|
...expiresAt === void 0 ? {} : { expiresAt }
|
|
31951
32239
|
});
|
|
31952
32240
|
}
|
|
31953
|
-
var
|
|
32241
|
+
var import_node_crypto34, PreviewAdmissionSuperseded, PreviewEngine;
|
|
31954
32242
|
var init_engine = __esm({
|
|
31955
32243
|
"src/core/preview/engine.ts"() {
|
|
31956
32244
|
"use strict";
|
|
31957
|
-
|
|
32245
|
+
import_node_crypto34 = require("crypto");
|
|
31958
32246
|
init_command();
|
|
31959
32247
|
init_lifecycle();
|
|
31960
32248
|
init_state();
|
|
@@ -32088,7 +32376,7 @@ var init_engine = __esm({
|
|
|
32088
32376
|
} else {
|
|
32089
32377
|
if (current && current.session.status !== "stopped" && current.session.status !== "expired")
|
|
32090
32378
|
throw new Error("Previous generation cleanup is incomplete.");
|
|
32091
|
-
const generation = (0,
|
|
32379
|
+
const generation = (0, import_node_crypto34.createHash)("sha256").update(receipt).digest("hex").slice(0, 24);
|
|
32092
32380
|
pool2.sessions[id5] = {
|
|
32093
32381
|
identity: input2.identity,
|
|
32094
32382
|
session: createPreviewSession({
|
|
@@ -32744,11 +33032,11 @@ function decodeInbox(raw) {
|
|
|
32744
33032
|
}
|
|
32745
33033
|
return structuredClone(row);
|
|
32746
33034
|
}
|
|
32747
|
-
var
|
|
33035
|
+
var import_node_crypto35, PreviewController;
|
|
32748
33036
|
var init_controller2 = __esm({
|
|
32749
33037
|
"src/core/preview/controller.ts"() {
|
|
32750
33038
|
"use strict";
|
|
32751
|
-
|
|
33039
|
+
import_node_crypto35 = require("crypto");
|
|
32752
33040
|
init_command();
|
|
32753
33041
|
init_engine();
|
|
32754
33042
|
init_status3();
|
|
@@ -32955,7 +33243,7 @@ Command refused: ${inbox.refusal}. Post a new command when the condition is reso
|
|
|
32955
33243
|
Available profiles: ${this.options.aliases.map((alias) => `\`${alias}\``).join(", ")}.` : ""}
|
|
32956
33244
|
|
|
32957
33245
|
${marker}`;
|
|
32958
|
-
const fingerprint = (0,
|
|
33246
|
+
const fingerprint = (0, import_node_crypto35.createHash)("sha256").update(body).digest("hex"), now = this.options.now();
|
|
32959
33247
|
if (inbox.status?.bodyDigest === fingerprint) {
|
|
32960
33248
|
if (inbox.needsStatus) await this.update(change, (row) => ({ ...row, needsStatus: false }));
|
|
32961
33249
|
return;
|
|
@@ -32966,7 +33254,7 @@ ${marker}`;
|
|
|
32966
33254
|
let commentId = inbox.status?.commentId;
|
|
32967
33255
|
if (!commentId) commentId = await this.options.forge.findStatus(change, marker) ?? void 0;
|
|
32968
33256
|
let create = false;
|
|
32969
|
-
const intentId = (0,
|
|
33257
|
+
const intentId = (0, import_node_crypto35.randomUUID)();
|
|
32970
33258
|
if (!inbox.status)
|
|
32971
33259
|
inbox = await this.update(change, (row) => {
|
|
32972
33260
|
create = !row.status;
|
|
@@ -33716,7 +34004,7 @@ function canonicalizeImageConfiguration(configuration) {
|
|
|
33716
34004
|
return JSON.stringify(normalizeConfiguration(configuration, "image configuration"));
|
|
33717
34005
|
}
|
|
33718
34006
|
function imageConfigurationDigest(configuration) {
|
|
33719
|
-
return `sha256:${(0,
|
|
34007
|
+
return `sha256:${(0, import_node_crypto36.createHash)("sha256").update(canonicalizeImageConfiguration(configuration), "utf-8").digest("hex")}`;
|
|
33720
34008
|
}
|
|
33721
34009
|
function targetKey(target, configurationDigest) {
|
|
33722
34010
|
return `${target}\0${configurationDigest}`;
|
|
@@ -33971,11 +34259,11 @@ function resolvePreviewImages(plan, prepared, expectedProducer, value) {
|
|
|
33971
34259
|
images: Object.fromEntries(resourceReceipts)
|
|
33972
34260
|
};
|
|
33973
34261
|
}
|
|
33974
|
-
var
|
|
34262
|
+
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;
|
|
33975
34263
|
var init_images = __esm({
|
|
33976
34264
|
"src/core/preview/images.ts"() {
|
|
33977
34265
|
"use strict";
|
|
33978
|
-
|
|
34266
|
+
import_node_crypto36 = require("crypto");
|
|
33979
34267
|
MAX_COLLECTION_ENTRIES2 = 256;
|
|
33980
34268
|
MAX_CONFIGURATION_ENTRIES = 128;
|
|
33981
34269
|
MAX_CONFIGURATION_KEY_LENGTH = 128;
|
|
@@ -34009,8 +34297,8 @@ function commandImageBackend(options) {
|
|
|
34009
34297
|
throw new Error("Invalid installed image resolver command.");
|
|
34010
34298
|
const verify = () => {
|
|
34011
34299
|
for (const file of options.files) {
|
|
34012
|
-
const stat =
|
|
34013
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0,
|
|
34300
|
+
const stat = import_node_fs57.default.lstatSync(file.path);
|
|
34301
|
+
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)
|
|
34014
34302
|
throw new Error("Installed image resolver fingerprint differs.");
|
|
34015
34303
|
}
|
|
34016
34304
|
};
|
|
@@ -34022,7 +34310,7 @@ function commandImageBackend(options) {
|
|
|
34022
34310
|
platform: options.platform,
|
|
34023
34311
|
configurations: options.context(entry)
|
|
34024
34312
|
});
|
|
34025
|
-
const correlation = (0,
|
|
34313
|
+
const correlation = (0, import_node_crypto37.createHash)("sha256").update(
|
|
34026
34314
|
JSON.stringify([
|
|
34027
34315
|
entry.identity,
|
|
34028
34316
|
entry.session.generation,
|
|
@@ -34046,7 +34334,7 @@ function commandImageBackend(options) {
|
|
|
34046
34334
|
});
|
|
34047
34335
|
if (Buffer.byteLength(input2) > 1024 * 1024)
|
|
34048
34336
|
throw new Error("Image request exceeds its bound.");
|
|
34049
|
-
const result = (0,
|
|
34337
|
+
const result = (0, import_node_child_process43.spawnSync)(options.command[0], options.command.slice(1), {
|
|
34050
34338
|
shell: false,
|
|
34051
34339
|
cwd: options.cwd,
|
|
34052
34340
|
encoding: "utf8",
|
|
@@ -34084,13 +34372,13 @@ function commandImageBackend(options) {
|
|
|
34084
34372
|
}
|
|
34085
34373
|
};
|
|
34086
34374
|
}
|
|
34087
|
-
var
|
|
34375
|
+
var import_node_child_process43, import_node_crypto37, import_node_fs57;
|
|
34088
34376
|
var init_image_command = __esm({
|
|
34089
34377
|
"src/core/preview/image-command.ts"() {
|
|
34090
34378
|
"use strict";
|
|
34091
|
-
|
|
34092
|
-
|
|
34093
|
-
|
|
34379
|
+
import_node_child_process43 = require("child_process");
|
|
34380
|
+
import_node_crypto37 = require("crypto");
|
|
34381
|
+
import_node_fs57 = __toESM(require("fs"));
|
|
34094
34382
|
init_images();
|
|
34095
34383
|
init_state();
|
|
34096
34384
|
}
|
|
@@ -34783,9 +35071,9 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
34783
35071
|
const resource = resources.get(id5);
|
|
34784
35072
|
if (!resource?.ports?.some((item) => item.name === port && item.public))
|
|
34785
35073
|
throw new Error("Northflank origin binding requires a selected public port.");
|
|
34786
|
-
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0,
|
|
35074
|
+
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0, import_node_crypto38.createHash)("sha256").update(id5).digest("hex").slice(0, 6)}.${policy.baseDomain}`;
|
|
34787
35075
|
};
|
|
34788
|
-
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0,
|
|
35076
|
+
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0, import_node_crypto38.createHash)("sha256").update(id5).digest("hex").slice(0, 10)}`;
|
|
34789
35077
|
const suffix = (value) => {
|
|
34790
35078
|
if (value === void 0) return "";
|
|
34791
35079
|
if (typeof value !== "string" || value.length > 1024 || !value.startsWith("/") || value.startsWith("//") || value.includes("\\") || new RegExp("\\s|\\p{Cc}", "u").test(value))
|
|
@@ -35212,7 +35500,7 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35212
35500
|
]
|
|
35213
35501
|
}
|
|
35214
35502
|
};
|
|
35215
|
-
const digest5 = (0,
|
|
35503
|
+
const digest5 = (0, import_node_crypto38.createHash)("sha256").update(JSON.stringify({ spec, runtimeSecrets })).digest("hex");
|
|
35216
35504
|
return {
|
|
35217
35505
|
spec,
|
|
35218
35506
|
digest: digest5,
|
|
@@ -35223,11 +35511,11 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35223
35511
|
publicBuildEnvironment
|
|
35224
35512
|
};
|
|
35225
35513
|
}
|
|
35226
|
-
var
|
|
35514
|
+
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;
|
|
35227
35515
|
var init_northflank_graph = __esm({
|
|
35228
35516
|
"src/core/preview/providers/northflank-graph.ts"() {
|
|
35229
35517
|
"use strict";
|
|
35230
|
-
|
|
35518
|
+
import_node_crypto38 = require("crypto");
|
|
35231
35519
|
import_node_net5 = require("net");
|
|
35232
35520
|
ALLOCATION_PLAN = /^[a-zA-Z0-9-]{3,100}$/;
|
|
35233
35521
|
DATABASE_NAME = /^[a-z][a-z0-9_]{0,62}$/;
|
|
@@ -35331,7 +35619,7 @@ function specDigest(value) {
|
|
|
35331
35619
|
return digest3(definition(value));
|
|
35332
35620
|
}
|
|
35333
35621
|
function digest3(value) {
|
|
35334
|
-
return (0,
|
|
35622
|
+
return (0, import_node_crypto39.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
35335
35623
|
}
|
|
35336
35624
|
function bindings(owned) {
|
|
35337
35625
|
return {
|
|
@@ -35356,11 +35644,11 @@ function outputNames(graph) {
|
|
|
35356
35644
|
)
|
|
35357
35645
|
].sort();
|
|
35358
35646
|
}
|
|
35359
|
-
var
|
|
35647
|
+
var import_node_crypto39, resourceKinds, NorthflankOwnershipStore, northflankQualificationKeys, NorthflankFailure, NorthflankFenced, NorthflankPreviewProvider, nativeKinds, emptySpec;
|
|
35360
35648
|
var init_northflank = __esm({
|
|
35361
35649
|
"src/core/preview/providers/northflank.ts"() {
|
|
35362
35650
|
"use strict";
|
|
35363
|
-
|
|
35651
|
+
import_node_crypto39 = require("crypto");
|
|
35364
35652
|
init_command();
|
|
35365
35653
|
init_state();
|
|
35366
35654
|
init_northflank_api();
|
|
@@ -35993,7 +36281,7 @@ var init_northflank = __esm({
|
|
|
35993
36281
|
const settings = this.options.graph.generated?.[name];
|
|
35994
36282
|
if (!settings)
|
|
35995
36283
|
throw new NorthflankFailure("Northflank generated value is undeclared.");
|
|
35996
|
-
value = (0,
|
|
36284
|
+
value = (0, import_node_crypto39.randomBytes)(settings.bytes).toString(settings.encoding);
|
|
35997
36285
|
}
|
|
35998
36286
|
if (kind === "output" && value === void 0)
|
|
35999
36287
|
throw new NorthflankFailure("Northflank output has no verified recipient.");
|
|
@@ -36496,10 +36784,10 @@ __export(installation_exports, {
|
|
|
36496
36784
|
loadPreviewInstallation: () => loadPreviewInstallation
|
|
36497
36785
|
});
|
|
36498
36786
|
function readFile(file) {
|
|
36499
|
-
const stat =
|
|
36787
|
+
const stat = import_node_fs58.default.lstatSync(file);
|
|
36500
36788
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
|
|
36501
36789
|
throw new Error("Preview control files must be regular files of at most 1 MiB.");
|
|
36502
|
-
return
|
|
36790
|
+
return import_node_fs58.default.readFileSync(file, "utf8");
|
|
36503
36791
|
}
|
|
36504
36792
|
function text5(value, pattern) {
|
|
36505
36793
|
if (typeof value !== "string" || !pattern.test(value))
|
|
@@ -36512,7 +36800,7 @@ function integer2(value, min, max) {
|
|
|
36512
36800
|
return value;
|
|
36513
36801
|
}
|
|
36514
36802
|
function loadPreviewInstallation(filename, options = {}) {
|
|
36515
|
-
const root = import_node_path70.default.dirname(
|
|
36803
|
+
const root = import_node_path70.default.dirname(import_node_fs58.default.realpathSync(filename));
|
|
36516
36804
|
const raw = object5(JSON.parse(readFile(filename)), [
|
|
36517
36805
|
"version",
|
|
36518
36806
|
"installationId",
|
|
@@ -36595,7 +36883,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36595
36883
|
const control = (input3) => {
|
|
36596
36884
|
const ref2 = object5(input3, ["file", "sha256"]);
|
|
36597
36885
|
const filename2 = text5(ref2.file, /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/);
|
|
36598
|
-
const file =
|
|
36886
|
+
const file = import_node_fs58.default.realpathSync(import_node_path70.default.join(root, filename2));
|
|
36599
36887
|
if (!file.startsWith(`${root}${import_node_path70.default.sep}`))
|
|
36600
36888
|
throw new Error("Preview control file escapes installation directory.");
|
|
36601
36889
|
const source = readFile(file), expected = text5(ref2.sha256, /^[a-f0-9]{64}$/);
|
|
@@ -36658,7 +36946,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36658
36946
|
return credential(secrets[ref2])();
|
|
36659
36947
|
},
|
|
36660
36948
|
accept: async (entry, urls) => {
|
|
36661
|
-
const result = (0,
|
|
36949
|
+
const result = (0, import_node_child_process44.spawnSync)(command[0], command.slice(1), {
|
|
36662
36950
|
cwd: root,
|
|
36663
36951
|
shell: false,
|
|
36664
36952
|
timeout: 3e4,
|
|
@@ -36720,7 +37008,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36720
37008
|
const item = object5(input3, ["file", "sha256"]);
|
|
36721
37009
|
const verified = control(input3);
|
|
36722
37010
|
return {
|
|
36723
|
-
path:
|
|
37011
|
+
path: import_node_fs58.default.realpathSync(import_node_path70.default.join(root, item.file)),
|
|
36724
37012
|
sha256: verified.digest
|
|
36725
37013
|
};
|
|
36726
37014
|
}) : [];
|
|
@@ -36835,7 +37123,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36835
37123
|
}
|
|
36836
37124
|
},
|
|
36837
37125
|
now,
|
|
36838
|
-
workerId: (0,
|
|
37126
|
+
workerId: (0, import_node_crypto40.randomUUID)(),
|
|
36839
37127
|
policy: {
|
|
36840
37128
|
installationId,
|
|
36841
37129
|
maxActive,
|
|
@@ -36951,13 +37239,13 @@ async function initializePreviewInstallation(installationId, store) {
|
|
|
36951
37239
|
await store.compareAndSwap(witnessKey, null, { installationId });
|
|
36952
37240
|
await store.compareAndSwap(poolKey, null, createPreviewPool(installationId));
|
|
36953
37241
|
}
|
|
36954
|
-
var
|
|
37242
|
+
var import_node_child_process44, import_node_crypto40, import_node_fs58, import_node_path70, MAX_COMMAND_AGE_MS, digest4, envName;
|
|
36955
37243
|
var init_installation = __esm({
|
|
36956
37244
|
"src/core/preview/installation.ts"() {
|
|
36957
37245
|
"use strict";
|
|
36958
|
-
|
|
36959
|
-
|
|
36960
|
-
|
|
37246
|
+
import_node_child_process44 = require("child_process");
|
|
37247
|
+
import_node_crypto40 = require("crypto");
|
|
37248
|
+
import_node_fs58 = __toESM(require("fs"));
|
|
36961
37249
|
import_node_path70 = __toESM(require("path"));
|
|
36962
37250
|
init_repo_config();
|
|
36963
37251
|
init_command();
|
|
@@ -36975,7 +37263,7 @@ var init_installation = __esm({
|
|
|
36975
37263
|
init_state();
|
|
36976
37264
|
init_azure_blob();
|
|
36977
37265
|
MAX_COMMAND_AGE_MS = 15 * 6e4;
|
|
36978
|
-
digest4 = (source) => (0,
|
|
37266
|
+
digest4 = (source) => (0, import_node_crypto40.createHash)("sha256").update(source).digest("hex");
|
|
36979
37267
|
envName = (value) => {
|
|
36980
37268
|
if (typeof value !== "string" || !/^DEVROUTER_PREVIEW_[A-Z0-9_]+$/.test(value))
|
|
36981
37269
|
throw new Error("Preview credential references require scoped environment names.");
|
|
@@ -36994,14 +37282,14 @@ __export(preview_exports, {
|
|
|
36994
37282
|
function readSource(repoPath, filename) {
|
|
36995
37283
|
if (import_node_path71.default.isAbsolute(filename))
|
|
36996
37284
|
throw new Error("Preview source path must be repository-relative.");
|
|
36997
|
-
const root =
|
|
37285
|
+
const root = import_node_fs59.default.realpathSync(repoPath);
|
|
36998
37286
|
const file = assertPathWithinRepo(filename, root, "preview source");
|
|
36999
|
-
const stat =
|
|
37287
|
+
const stat = import_node_fs59.default.lstatSync(file);
|
|
37000
37288
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 1024 * 1024) {
|
|
37001
37289
|
throw new Error("Preview source must be a regular file of at most 1 MiB.");
|
|
37002
37290
|
}
|
|
37003
|
-
assertPathWithinRepo(
|
|
37004
|
-
return JSON.parse(
|
|
37291
|
+
assertPathWithinRepo(import_node_fs59.default.realpathSync(file), root, "preview source");
|
|
37292
|
+
return JSON.parse(import_node_fs59.default.readFileSync(file, "utf8"));
|
|
37005
37293
|
}
|
|
37006
37294
|
async function runPreviewPlanCommand(options) {
|
|
37007
37295
|
const repoPath = resolveRepoPath(options.repo);
|
|
@@ -37016,13 +37304,13 @@ async function runPreviewPlanCommand(options) {
|
|
|
37016
37304
|
`);
|
|
37017
37305
|
return;
|
|
37018
37306
|
}
|
|
37019
|
-
const localConfig =
|
|
37307
|
+
const localConfig = import_node_fs59.default.readFileSync(import_node_path71.default.join(repoPath, ".devrouter.yml"), "utf8");
|
|
37020
37308
|
const report = buildPreviewPlan({
|
|
37021
37309
|
repoPath,
|
|
37022
37310
|
config: loadRepoConfig(repoPath, () => localConfig),
|
|
37023
37311
|
manifest,
|
|
37024
37312
|
manifestDigest: digest5,
|
|
37025
|
-
localConfigDigest: (0,
|
|
37313
|
+
localConfigDigest: (0, import_node_crypto41.createHash)("sha256").update(localConfig).digest("hex"),
|
|
37026
37314
|
...options.alias === void 0 ? {} : { aliases: options.alias.split(",") },
|
|
37027
37315
|
...options.source === void 0 ? {} : { source: readSource(repoPath, options.source) }
|
|
37028
37316
|
});
|
|
@@ -37041,7 +37329,7 @@ async function runPreviewPlanCommand(options) {
|
|
|
37041
37329
|
}
|
|
37042
37330
|
}
|
|
37043
37331
|
async function runPreviewInitCommand(options) {
|
|
37044
|
-
const repoPath =
|
|
37332
|
+
const repoPath = import_node_fs59.default.realpathSync(resolveRepoPath(options.repo));
|
|
37045
37333
|
if (options.integration === "gitlab") return renderGitLabPreviewIntegration(repoPath, options);
|
|
37046
37334
|
if (options.integration) return renderPreviewIntegration(repoPath, options);
|
|
37047
37335
|
loadRepoConfig(repoPath);
|
|
@@ -37067,7 +37355,7 @@ async function runPreviewInitCommand(options) {
|
|
|
37067
37355
|
const content = (0, import_yaml12.stringify)(manifest);
|
|
37068
37356
|
if (options.write) {
|
|
37069
37357
|
const file = import_node_path71.default.join(repoPath, ".devrouter.preview.yml");
|
|
37070
|
-
|
|
37358
|
+
import_node_fs59.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37071
37359
|
}
|
|
37072
37360
|
if (options.json) {
|
|
37073
37361
|
printJSON({
|
|
@@ -37135,9 +37423,9 @@ function previewAsset(name) {
|
|
|
37135
37423
|
import_node_path71.default.resolve(__dirname, "..", "assets", "preview", name),
|
|
37136
37424
|
import_node_path71.default.resolve(__dirname, "..", "..", "assets", "preview", name)
|
|
37137
37425
|
];
|
|
37138
|
-
const file = candidates.find((file2) =>
|
|
37426
|
+
const file = candidates.find((file2) => import_node_fs59.default.existsSync(file2));
|
|
37139
37427
|
if (!file) throw new Error("Installed preview integration asset is missing.");
|
|
37140
|
-
return
|
|
37428
|
+
return import_node_fs59.default.readFileSync(file, "utf8");
|
|
37141
37429
|
}
|
|
37142
37430
|
function renderPreviewAsset(name, replacements) {
|
|
37143
37431
|
return previewAsset(name).replace(/__([A-Z_]+)__/g, (_match, key) => {
|
|
@@ -37172,9 +37460,9 @@ async function renderPreviewIntegration(repoPath, options) {
|
|
|
37172
37460
|
const filename = `.github/workflows/devrouter-preview${options.sweeper ? "-sweep" : ""}.yml`;
|
|
37173
37461
|
if (options.write) {
|
|
37174
37462
|
const file = assertPathWithinRepo(filename, repoPath, "preview workflow");
|
|
37175
|
-
|
|
37176
|
-
assertPathWithinRepo(
|
|
37177
|
-
|
|
37463
|
+
import_node_fs59.default.mkdirSync(import_node_path71.default.dirname(file), { recursive: true });
|
|
37464
|
+
assertPathWithinRepo(import_node_fs59.default.realpathSync(import_node_path71.default.dirname(file)), repoPath, "preview workflow parent");
|
|
37465
|
+
import_node_fs59.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37178
37466
|
}
|
|
37179
37467
|
if (options.json)
|
|
37180
37468
|
printJSON({
|
|
@@ -37192,7 +37480,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37192
37480
|
throw new Error(
|
|
37193
37481
|
"GitLab integration requires reviewed --controller-ref and --controller-image digest."
|
|
37194
37482
|
);
|
|
37195
|
-
const integrity = `sha256-${(0,
|
|
37483
|
+
const integrity = `sha256-${(0, import_node_crypto41.createHash)("sha256").update(previewAsset("gitlab-template.yml")).digest("base64")}`;
|
|
37196
37484
|
const replacements = {
|
|
37197
37485
|
CONTROLLER_REF: String(options.controllerRef),
|
|
37198
37486
|
CONTROLLER_IMAGE: String(options.controllerImage),
|
|
@@ -37201,7 +37489,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37201
37489
|
const content = renderPreviewAsset("gitlab.yml", replacements);
|
|
37202
37490
|
const filename = ".gitlab-ci.yml";
|
|
37203
37491
|
if (options.write)
|
|
37204
|
-
|
|
37492
|
+
import_node_fs59.default.writeFileSync(assertPathWithinRepo(filename, repoPath, "GitLab preview caller"), content, {
|
|
37205
37493
|
flag: "wx",
|
|
37206
37494
|
mode: 384
|
|
37207
37495
|
});
|
|
@@ -37216,12 +37504,12 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37216
37504
|
});
|
|
37217
37505
|
else process.stdout.write(content);
|
|
37218
37506
|
}
|
|
37219
|
-
var
|
|
37507
|
+
var import_node_crypto41, import_node_fs59, import_node_path71, import_yaml12;
|
|
37220
37508
|
var init_preview = __esm({
|
|
37221
37509
|
"src/commands/preview.ts"() {
|
|
37222
37510
|
"use strict";
|
|
37223
|
-
|
|
37224
|
-
|
|
37511
|
+
import_node_crypto41 = require("crypto");
|
|
37512
|
+
import_node_fs59 = __toESM(require("fs"));
|
|
37225
37513
|
import_node_path71 = __toESM(require("path"));
|
|
37226
37514
|
import_yaml12 = require("yaml");
|
|
37227
37515
|
init_output();
|
|
@@ -37514,7 +37802,7 @@ function sanitizeRouterId(value) {
|
|
|
37514
37802
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
37515
37803
|
}
|
|
37516
37804
|
function repoHash(repoPath) {
|
|
37517
|
-
return (0,
|
|
37805
|
+
return (0, import_node_crypto42.createHash)("sha1").update(import_node_path72.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
37518
37806
|
}
|
|
37519
37807
|
function asDockerApp(app) {
|
|
37520
37808
|
return app.runtime === "docker";
|
|
@@ -37594,10 +37882,10 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
37594
37882
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
37595
37883
|
}
|
|
37596
37884
|
const cachePath = import_node_path72.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
37597
|
-
|
|
37885
|
+
import_node_fs60.default.mkdirSync(cachePath, { recursive: true });
|
|
37598
37886
|
const overlayPath = import_node_path72.default.join(cachePath, "compose.devrouter.yml");
|
|
37599
37887
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
37600
|
-
|
|
37888
|
+
import_node_fs60.default.writeFileSync(overlayPath, import_yaml13.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
37601
37889
|
return {
|
|
37602
37890
|
overlayPath,
|
|
37603
37891
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -37611,7 +37899,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37611
37899
|
fileArgs.push("-f", resolved2);
|
|
37612
37900
|
}
|
|
37613
37901
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
37614
|
-
const result = (0,
|
|
37902
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37615
37903
|
encoding: "utf-8",
|
|
37616
37904
|
cwd: repoPath
|
|
37617
37905
|
});
|
|
@@ -37639,7 +37927,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
37639
37927
|
"--services",
|
|
37640
37928
|
...services
|
|
37641
37929
|
];
|
|
37642
|
-
const result = (0,
|
|
37930
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37643
37931
|
encoding: "utf-8",
|
|
37644
37932
|
cwd: repoPath
|
|
37645
37933
|
});
|
|
@@ -37665,7 +37953,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37665
37953
|
fileArgs.push("-f", resolved2);
|
|
37666
37954
|
}
|
|
37667
37955
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
37668
|
-
const result = (0,
|
|
37956
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37669
37957
|
encoding: "utf-8",
|
|
37670
37958
|
cwd: repoPath
|
|
37671
37959
|
});
|
|
@@ -37691,7 +37979,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
37691
37979
|
String(tail),
|
|
37692
37980
|
...services
|
|
37693
37981
|
];
|
|
37694
|
-
(0,
|
|
37982
|
+
(0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37695
37983
|
stdio: "inherit",
|
|
37696
37984
|
cwd: repoPath
|
|
37697
37985
|
});
|
|
@@ -37703,7 +37991,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37703
37991
|
fileArgs.push("-f", resolved2);
|
|
37704
37992
|
}
|
|
37705
37993
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
37706
|
-
const result = (0,
|
|
37994
|
+
const result = (0, import_node_child_process45.spawnSync)("docker", args, {
|
|
37707
37995
|
encoding: "utf-8",
|
|
37708
37996
|
cwd: repoPath
|
|
37709
37997
|
});
|
|
@@ -37717,13 +38005,13 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37717
38005
|
const port = Number(match[1]);
|
|
37718
38006
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
37719
38007
|
}
|
|
37720
|
-
var
|
|
38008
|
+
var import_node_child_process45, import_node_crypto42, import_node_fs60, import_node_path72, import_yaml13;
|
|
37721
38009
|
var init_docker_run = __esm({
|
|
37722
38010
|
"src/core/docker-run.ts"() {
|
|
37723
38011
|
"use strict";
|
|
37724
|
-
|
|
37725
|
-
|
|
37726
|
-
|
|
38012
|
+
import_node_child_process45 = require("child_process");
|
|
38013
|
+
import_node_crypto42 = require("crypto");
|
|
38014
|
+
import_node_fs60 = __toESM(require("fs"));
|
|
37727
38015
|
import_node_path72 = __toESM(require("path"));
|
|
37728
38016
|
import_yaml13 = __toESM(require("yaml"));
|
|
37729
38017
|
init_docker_error_guidance();
|
|
@@ -37814,7 +38102,7 @@ function isProcessRunning(pid) {
|
|
|
37814
38102
|
}
|
|
37815
38103
|
}
|
|
37816
38104
|
function readProcessTree(rootPid) {
|
|
37817
|
-
const result = (0,
|
|
38105
|
+
const result = (0, import_node_child_process46.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
37818
38106
|
if (result.status !== 0) {
|
|
37819
38107
|
return [rootPid];
|
|
37820
38108
|
}
|
|
@@ -37925,12 +38213,12 @@ function detectListeningPorts(pids) {
|
|
|
37925
38213
|
if (pids.length === 0) {
|
|
37926
38214
|
return [];
|
|
37927
38215
|
}
|
|
37928
|
-
const result = (0,
|
|
38216
|
+
const result = (0, import_node_child_process46.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
37929
38217
|
encoding: "utf-8"
|
|
37930
38218
|
});
|
|
37931
38219
|
if (result.error && result.error.code === "ENOENT") {
|
|
37932
38220
|
if (process.platform === "linux") {
|
|
37933
|
-
const ssResult = (0,
|
|
38221
|
+
const ssResult = (0, import_node_child_process46.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
37934
38222
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
37935
38223
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
37936
38224
|
}
|
|
@@ -37989,7 +38277,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
37989
38277
|
app.hostRun.command,
|
|
37990
38278
|
true
|
|
37991
38279
|
) : app.hostRun.command;
|
|
37992
|
-
const child = (0,
|
|
38280
|
+
const child = (0, import_node_child_process46.spawn)(spawnCommand, {
|
|
37993
38281
|
cwd: commandCwd,
|
|
37994
38282
|
stdio: "inherit",
|
|
37995
38283
|
shell: true,
|
|
@@ -38357,7 +38645,7 @@ async function execWithAppEnv(options) {
|
|
|
38357
38645
|
options.command[0],
|
|
38358
38646
|
true
|
|
38359
38647
|
);
|
|
38360
|
-
child = (0,
|
|
38648
|
+
child = (0, import_node_child_process46.spawn)(wrapped, {
|
|
38361
38649
|
cwd: deps.repoPath,
|
|
38362
38650
|
stdio: "inherit",
|
|
38363
38651
|
shell: true,
|
|
@@ -38371,7 +38659,7 @@ async function execWithAppEnv(options) {
|
|
|
38371
38659
|
false
|
|
38372
38660
|
);
|
|
38373
38661
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
38374
|
-
child = (0,
|
|
38662
|
+
child = (0, import_node_child_process46.spawn)(cmd, wrappedArgs, {
|
|
38375
38663
|
cwd: deps.repoPath,
|
|
38376
38664
|
stdio: "inherit",
|
|
38377
38665
|
shell: false,
|
|
@@ -38379,7 +38667,7 @@ async function execWithAppEnv(options) {
|
|
|
38379
38667
|
});
|
|
38380
38668
|
}
|
|
38381
38669
|
} else if (options.shell) {
|
|
38382
|
-
child = (0,
|
|
38670
|
+
child = (0, import_node_child_process46.spawn)(options.command[0], {
|
|
38383
38671
|
cwd: deps.repoPath,
|
|
38384
38672
|
stdio: "inherit",
|
|
38385
38673
|
shell: true,
|
|
@@ -38387,7 +38675,7 @@ async function execWithAppEnv(options) {
|
|
|
38387
38675
|
});
|
|
38388
38676
|
} else {
|
|
38389
38677
|
const [command, ...args] = options.command;
|
|
38390
|
-
child = (0,
|
|
38678
|
+
child = (0, import_node_child_process46.spawn)(command, args, {
|
|
38391
38679
|
cwd: deps.repoPath,
|
|
38392
38680
|
stdio: "inherit",
|
|
38393
38681
|
shell: false,
|
|
@@ -38408,11 +38696,11 @@ async function execWithAppEnv(options) {
|
|
|
38408
38696
|
deps.stopDeps();
|
|
38409
38697
|
}
|
|
38410
38698
|
}
|
|
38411
|
-
var
|
|
38699
|
+
var import_node_child_process46, import_node_net6, import_node_process, import_promises, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
|
|
38412
38700
|
var init_app_run = __esm({
|
|
38413
38701
|
"src/core/app-run.ts"() {
|
|
38414
38702
|
"use strict";
|
|
38415
|
-
|
|
38703
|
+
import_node_child_process46 = require("child_process");
|
|
38416
38704
|
import_node_net6 = __toESM(require("net"));
|
|
38417
38705
|
import_node_process = require("process");
|
|
38418
38706
|
import_promises = require("readline/promises");
|
|
@@ -38558,7 +38846,7 @@ function canonicalJson(value) {
|
|
|
38558
38846
|
`;
|
|
38559
38847
|
}
|
|
38560
38848
|
function sha256Hex(raw) {
|
|
38561
|
-
return (0,
|
|
38849
|
+
return (0, import_node_crypto43.createHash)("sha256").update(raw).digest("hex");
|
|
38562
38850
|
}
|
|
38563
38851
|
function candidateId(candidate) {
|
|
38564
38852
|
const identity2 = {
|
|
@@ -38726,7 +39014,7 @@ function validateManifest(value) {
|
|
|
38726
39014
|
return root;
|
|
38727
39015
|
}
|
|
38728
39016
|
function readManifest(file) {
|
|
38729
|
-
const raw =
|
|
39017
|
+
const raw = import_node_fs61.default.readFileSync(file);
|
|
38730
39018
|
let parsed;
|
|
38731
39019
|
try {
|
|
38732
39020
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -38765,7 +39053,7 @@ function selectManifest(file, expectedSha256, ids2) {
|
|
|
38765
39053
|
return canonicalJson(subset);
|
|
38766
39054
|
}
|
|
38767
39055
|
function gitLine(cwd, args) {
|
|
38768
|
-
const result = (0,
|
|
39056
|
+
const result = (0, import_node_child_process47.spawnSync)("git", ["-C", cwd, ...args], {
|
|
38769
39057
|
encoding: "utf-8",
|
|
38770
39058
|
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
38771
39059
|
});
|
|
@@ -38773,7 +39061,7 @@ function gitLine(cwd, args) {
|
|
|
38773
39061
|
return result.status === 0 && !result.error && output2 ? output2 : void 0;
|
|
38774
39062
|
}
|
|
38775
39063
|
function readWorktreeIdentity(worktreePath) {
|
|
38776
|
-
if (!
|
|
39064
|
+
if (!import_node_fs61.default.existsSync(worktreePath)) return void 0;
|
|
38777
39065
|
const real = comparableWorkspacePath(worktreePath);
|
|
38778
39066
|
const commonDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
38779
39067
|
const gitDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-dir"]);
|
|
@@ -38799,7 +39087,7 @@ function unmanagedActivityEpoch(worktreePath, gitDir) {
|
|
|
38799
39087
|
worktreePath
|
|
38800
39088
|
]) {
|
|
38801
39089
|
try {
|
|
38802
|
-
const seconds = Math.floor(
|
|
39090
|
+
const seconds = Math.floor(import_node_fs61.default.statSync(file).mtimeMs / 1e3);
|
|
38803
39091
|
latest = latest === void 0 ? seconds : Math.max(latest, seconds);
|
|
38804
39092
|
} catch {
|
|
38805
39093
|
}
|
|
@@ -38858,7 +39146,7 @@ function receiptPath(commonDir, manifestSha256, id5) {
|
|
|
38858
39146
|
function matchingReceipt(candidate, manifestSha256) {
|
|
38859
39147
|
try {
|
|
38860
39148
|
const receipt = JSON.parse(
|
|
38861
|
-
|
|
39149
|
+
import_node_fs61.default.readFileSync(receiptPath(candidate.commonDir, manifestSha256, candidate.id), "utf-8")
|
|
38862
39150
|
);
|
|
38863
39151
|
return receipt.kind === RECEIPT_KIND && receipt.schemaVersion === SCHEMA_VERSION && receipt.manifestSha256 === manifestSha256 && receipt.candidateId === candidate.id && receipt.path === candidate.path && receipt.head === candidate.head;
|
|
38864
39152
|
} catch {
|
|
@@ -38867,7 +39155,7 @@ function matchingReceipt(candidate, manifestSha256) {
|
|
|
38867
39155
|
}
|
|
38868
39156
|
function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
38869
39157
|
const file = receiptPath(candidate.commonDir, manifestSha256, candidate.id);
|
|
38870
|
-
|
|
39158
|
+
import_node_fs61.default.mkdirSync(import_node_path73.default.dirname(file), { recursive: true });
|
|
38871
39159
|
writeFileAtomically(
|
|
38872
39160
|
file,
|
|
38873
39161
|
canonicalJson({
|
|
@@ -38885,7 +39173,7 @@ function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
|
38885
39173
|
);
|
|
38886
39174
|
}
|
|
38887
39175
|
function runVetoCommand(command, worktreePath) {
|
|
38888
|
-
const result = (0,
|
|
39176
|
+
const result = (0, import_node_child_process47.spawnSync)(command, [worktreePath], {
|
|
38889
39177
|
stdio: ["ignore", "ignore", "inherit"],
|
|
38890
39178
|
timeout: VETO_TIMEOUT_MS
|
|
38891
39179
|
});
|
|
@@ -38900,7 +39188,7 @@ function runVetoCommand(command, worktreePath) {
|
|
|
38900
39188
|
function assertVetoCommand(command) {
|
|
38901
39189
|
if (!import_node_path73.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
|
|
38902
39190
|
try {
|
|
38903
|
-
|
|
39191
|
+
import_node_fs61.default.accessSync(command, import_node_fs61.default.constants.X_OK);
|
|
38904
39192
|
} catch {
|
|
38905
39193
|
throw new Error(`--veto-command '${command}' is missing or not executable`);
|
|
38906
39194
|
}
|
|
@@ -38926,7 +39214,7 @@ function preflightManifestApply(options, action2, nowEpoch) {
|
|
|
38926
39214
|
return { manifest, manifestSha256, now };
|
|
38927
39215
|
}
|
|
38928
39216
|
function deleteBranchIfUnmoved(candidate, steps) {
|
|
38929
|
-
const exists2 = (0,
|
|
39217
|
+
const exists2 = (0, import_node_child_process47.spawnSync)(
|
|
38930
39218
|
"git",
|
|
38931
39219
|
["-C", candidate.repo, "show-ref", "--verify", "--quiet", candidate.branchRef],
|
|
38932
39220
|
{ encoding: "utf-8" }
|
|
@@ -38935,7 +39223,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38935
39223
|
if (exists2.status !== 0) {
|
|
38936
39224
|
throw new Error(`cannot read branch ${candidate.branch}: ${(exists2.stderr ?? "").trim()}`);
|
|
38937
39225
|
}
|
|
38938
|
-
const result = (0,
|
|
39226
|
+
const result = (0, import_node_child_process47.spawnSync)(
|
|
38939
39227
|
"git",
|
|
38940
39228
|
["-C", candidate.repo, "update-ref", "-d", candidate.branchRef, candidate.head],
|
|
38941
39229
|
{ encoding: "utf-8" }
|
|
@@ -38944,7 +39232,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38944
39232
|
return `branch ${candidate.branch} no longer points at the approved HEAD; it was kept for review`;
|
|
38945
39233
|
}
|
|
38946
39234
|
steps.push("branch-deleted");
|
|
38947
|
-
(0,
|
|
39235
|
+
(0, import_node_child_process47.spawnSync)(
|
|
38948
39236
|
"git",
|
|
38949
39237
|
["-C", candidate.repo, "config", "--remove-section", `branch.${candidate.branch}`],
|
|
38950
39238
|
{ encoding: "utf-8" }
|
|
@@ -38982,7 +39270,7 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38982
39270
|
outcome.status = "not-attempted";
|
|
38983
39271
|
continue;
|
|
38984
39272
|
}
|
|
38985
|
-
if (!
|
|
39273
|
+
if (!import_node_fs61.default.existsSync(candidate.path) && matchingReceipt(candidate, manifestSha256)) {
|
|
38986
39274
|
outcome.status = "already-done";
|
|
38987
39275
|
continue;
|
|
38988
39276
|
}
|
|
@@ -39051,13 +39339,13 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
39051
39339
|
}
|
|
39052
39340
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
39053
39341
|
}
|
|
39054
|
-
var
|
|
39342
|
+
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;
|
|
39055
39343
|
var init_worktree_reclaim = __esm({
|
|
39056
39344
|
"src/core/worktree-reclaim.ts"() {
|
|
39057
39345
|
"use strict";
|
|
39058
|
-
|
|
39059
|
-
|
|
39060
|
-
|
|
39346
|
+
import_node_child_process47 = require("child_process");
|
|
39347
|
+
import_node_crypto43 = require("crypto");
|
|
39348
|
+
import_node_fs61 = __toESM(require("fs"));
|
|
39061
39349
|
import_node_path73 = __toESM(require("path"));
|
|
39062
39350
|
init_atomic_file();
|
|
39063
39351
|
init_workspace();
|
|
@@ -39322,14 +39610,14 @@ function readLeftoverContext(repoPath) {
|
|
|
39322
39610
|
registriesReadable: snapshots.unavailable.length === 0,
|
|
39323
39611
|
realpath: (file) => {
|
|
39324
39612
|
try {
|
|
39325
|
-
return
|
|
39613
|
+
return import_node_fs62.default.realpathSync.native(file);
|
|
39326
39614
|
} catch {
|
|
39327
39615
|
return void 0;
|
|
39328
39616
|
}
|
|
39329
39617
|
},
|
|
39330
39618
|
exists: (file) => {
|
|
39331
39619
|
try {
|
|
39332
|
-
|
|
39620
|
+
import_node_fs62.default.lstatSync(file);
|
|
39333
39621
|
return true;
|
|
39334
39622
|
} catch (error) {
|
|
39335
39623
|
return error.code !== "ENOENT";
|
|
@@ -39453,7 +39741,7 @@ function validateLeftoverManifest(value) {
|
|
|
39453
39741
|
return root;
|
|
39454
39742
|
}
|
|
39455
39743
|
function readLeftoverManifest(file) {
|
|
39456
|
-
const raw =
|
|
39744
|
+
const raw = import_node_fs62.default.readFileSync(file);
|
|
39457
39745
|
let parsed;
|
|
39458
39746
|
try {
|
|
39459
39747
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -39467,7 +39755,7 @@ function readLeftoverManifest(file) {
|
|
|
39467
39755
|
return { raw, manifest };
|
|
39468
39756
|
}
|
|
39469
39757
|
function gitCommonDir(repo) {
|
|
39470
|
-
const result = (0,
|
|
39758
|
+
const result = (0, import_node_child_process48.spawnSync)(
|
|
39471
39759
|
"git",
|
|
39472
39760
|
["-C", repo, "rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
39473
39761
|
{ encoding: "utf-8" }
|
|
@@ -39639,7 +39927,7 @@ function leftoverReceiptPath(commonDir, manifestSha256, id5) {
|
|
|
39639
39927
|
}
|
|
39640
39928
|
function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEpoch) {
|
|
39641
39929
|
const file = leftoverReceiptPath(commonDir, manifestSha256, candidate.id);
|
|
39642
|
-
|
|
39930
|
+
import_node_fs62.default.mkdirSync(import_node_path74.default.dirname(file), { recursive: true });
|
|
39643
39931
|
writeFileAtomically(
|
|
39644
39932
|
file,
|
|
39645
39933
|
canonicalJson({
|
|
@@ -39655,12 +39943,12 @@ function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEp
|
|
|
39655
39943
|
})
|
|
39656
39944
|
);
|
|
39657
39945
|
}
|
|
39658
|
-
var
|
|
39946
|
+
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;
|
|
39659
39947
|
var init_docker_leftovers = __esm({
|
|
39660
39948
|
"src/core/docker-leftovers.ts"() {
|
|
39661
39949
|
"use strict";
|
|
39662
|
-
|
|
39663
|
-
|
|
39950
|
+
import_node_child_process48 = require("child_process");
|
|
39951
|
+
import_node_fs62 = __toESM(require("fs"));
|
|
39664
39952
|
import_node_path74 = __toESM(require("path"));
|
|
39665
39953
|
init_atomic_file();
|
|
39666
39954
|
init_devpod_mutation();
|
|
@@ -39682,7 +39970,7 @@ var init_docker_leftovers = __esm({
|
|
|
39682
39970
|
DockerListingBoundError = class extends Error {
|
|
39683
39971
|
};
|
|
39684
39972
|
defaultDockerRunner = (args) => {
|
|
39685
|
-
const result = (0,
|
|
39973
|
+
const result = (0, import_node_child_process48.spawnSync)("docker", args, {
|
|
39686
39974
|
encoding: "utf-8",
|
|
39687
39975
|
timeout: 6e4,
|
|
39688
39976
|
maxBuffer: 256 * 1024 * 1024
|
|
@@ -39713,13 +40001,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39713
40001
|
const startedAt = Date.now();
|
|
39714
40002
|
let rootStat;
|
|
39715
40003
|
try {
|
|
39716
|
-
rootStat =
|
|
40004
|
+
rootStat = import_node_fs63.default.lstatSync(worktreePath);
|
|
39717
40005
|
} catch (error) {
|
|
39718
40006
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39719
40007
|
}
|
|
39720
40008
|
let rootEntries;
|
|
39721
40009
|
try {
|
|
39722
|
-
rootEntries =
|
|
40010
|
+
rootEntries = import_node_fs63.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
39723
40011
|
} catch (error) {
|
|
39724
40012
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39725
40013
|
}
|
|
@@ -39748,7 +40036,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39748
40036
|
const entryPath = import_node_path75.default.join(dirPath, entry.name);
|
|
39749
40037
|
let entryStat;
|
|
39750
40038
|
try {
|
|
39751
|
-
entryStat =
|
|
40039
|
+
entryStat = import_node_fs63.default.lstatSync(entryPath);
|
|
39752
40040
|
} catch (error) {
|
|
39753
40041
|
if (error?.code === "ENOENT") continue;
|
|
39754
40042
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -39758,7 +40046,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39758
40046
|
if (!entryStat.isDirectory()) continue;
|
|
39759
40047
|
let childEntries;
|
|
39760
40048
|
try {
|
|
39761
|
-
childEntries =
|
|
40049
|
+
childEntries = import_node_fs63.default.readdirSync(entryPath, { withFileTypes: true });
|
|
39762
40050
|
} catch (error) {
|
|
39763
40051
|
unreadableReason = describeIncompleteWalk(error);
|
|
39764
40052
|
break;
|
|
@@ -39822,11 +40110,11 @@ function describeError(error, worktreePath) {
|
|
|
39822
40110
|
}
|
|
39823
40111
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
39824
40112
|
}
|
|
39825
|
-
var
|
|
40113
|
+
var import_node_fs63, import_node_path75, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
39826
40114
|
var init_workspace_consumption = __esm({
|
|
39827
40115
|
"src/core/workspace-consumption.ts"() {
|
|
39828
40116
|
"use strict";
|
|
39829
|
-
|
|
40117
|
+
import_node_fs63 = __toESM(require("fs"));
|
|
39830
40118
|
import_node_path75 = __toESM(require("path"));
|
|
39831
40119
|
init_devpod_environment();
|
|
39832
40120
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
@@ -39913,7 +40201,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
39913
40201
|
}
|
|
39914
40202
|
function readGitSnapshot(worktree, commandRunner) {
|
|
39915
40203
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
39916
|
-
if (worktree.prunable || !
|
|
40204
|
+
if (worktree.prunable || !import_node_fs64.default.existsSync(comparablePath)) {
|
|
39917
40205
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
39918
40206
|
}
|
|
39919
40207
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -40545,7 +40833,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40545
40833
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40546
40834
|
);
|
|
40547
40835
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40548
|
-
const disposable =
|
|
40836
|
+
const disposable = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40549
40837
|
const [primary, ...linked] = worktrees;
|
|
40550
40838
|
const safetyFor = (worktree, worktreePath, evidence) => toSafety(
|
|
40551
40839
|
classify({
|
|
@@ -40553,7 +40841,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40553
40841
|
branch: worktree?.branch,
|
|
40554
40842
|
primary: primary !== void 0 && sameWorkspacePath(primary.path, worktreePath),
|
|
40555
40843
|
locked: worktree?.locked ?? false,
|
|
40556
|
-
missing: !worktree || worktree.prunable || !
|
|
40844
|
+
missing: !worktree || worktree.prunable || !import_node_fs64.default.existsSync(worktreePath),
|
|
40557
40845
|
runtimeEvidence: evidence,
|
|
40558
40846
|
forge,
|
|
40559
40847
|
extraDisposablePatterns: disposable
|
|
@@ -40614,7 +40902,7 @@ function readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies) {
|
|
|
40614
40902
|
}
|
|
40615
40903
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40616
40904
|
const cutoffEpoch = Math.floor(Date.now() / 1e3) - parseInactiveFor(inactiveFor).seconds;
|
|
40617
|
-
const gitDir = (0,
|
|
40905
|
+
const gitDir = (0, import_node_child_process49.spawnSync)(
|
|
40618
40906
|
"git",
|
|
40619
40907
|
["-C", worktreePath, "rev-parse", "--path-format=absolute", "--git-dir"],
|
|
40620
40908
|
{ encoding: "utf-8", env: READ_ONLY_GIT_ENV2 }
|
|
@@ -40634,7 +40922,7 @@ function classifyExactPath(repoPath, worktreePath, evidence, forge, extraDisposa
|
|
|
40634
40922
|
branch: worktree?.branch,
|
|
40635
40923
|
primary: worktrees[0] !== void 0 && sameWorkspacePath(worktrees[0].path, worktreePath),
|
|
40636
40924
|
locked: worktree?.locked ?? false,
|
|
40637
|
-
missing: !worktree || worktree.prunable || !
|
|
40925
|
+
missing: !worktree || worktree.prunable || !import_node_fs64.default.existsSync(worktreePath),
|
|
40638
40926
|
runtimeEvidence: evidence.runtimeEvidence,
|
|
40639
40927
|
forge,
|
|
40640
40928
|
extraDisposablePatterns
|
|
@@ -40660,7 +40948,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40660
40948
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40661
40949
|
);
|
|
40662
40950
|
const forge = evidence.status === "not-checked" ? { status: "unavailable", reason: "forge not checked" } : evidence;
|
|
40663
|
-
const disposable =
|
|
40951
|
+
const disposable = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40664
40952
|
const paths = evidenceCache(
|
|
40665
40953
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
40666
40954
|
);
|
|
@@ -40679,7 +40967,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40679
40967
|
}
|
|
40680
40968
|
function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
40681
40969
|
const repoPath = resolveRepoPath(repo);
|
|
40682
|
-
const configured =
|
|
40970
|
+
const configured = import_node_fs64.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
40683
40971
|
const patterns = configured?.trim ?? [];
|
|
40684
40972
|
const paths = evidenceCache(
|
|
40685
40973
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
@@ -40704,12 +40992,12 @@ function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
|
40704
40992
|
isActive: (worktreePath) => paths.last(worktreePath).active
|
|
40705
40993
|
};
|
|
40706
40994
|
}
|
|
40707
|
-
var
|
|
40995
|
+
var import_node_child_process49, import_node_fs64, import_node_path76, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
40708
40996
|
var init_workspace_cleanup = __esm({
|
|
40709
40997
|
"src/core/workspace-cleanup.ts"() {
|
|
40710
40998
|
"use strict";
|
|
40711
|
-
|
|
40712
|
-
|
|
40999
|
+
import_node_child_process49 = require("child_process");
|
|
41000
|
+
import_node_fs64 = __toESM(require("fs"));
|
|
40713
41001
|
import_node_path76 = __toESM(require("path"));
|
|
40714
41002
|
init_devpod_workspaces();
|
|
40715
41003
|
init_docker_leftovers();
|
|
@@ -40733,7 +41021,7 @@ var init_workspace_cleanup = __esm({
|
|
|
40733
41021
|
];
|
|
40734
41022
|
defaultCommandRunner = (command, args, input2) => {
|
|
40735
41023
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
40736
|
-
const result = (0,
|
|
41024
|
+
const result = (0, import_node_child_process49.spawnSync)(command, args, {
|
|
40737
41025
|
encoding: "utf-8",
|
|
40738
41026
|
env: environment,
|
|
40739
41027
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -40858,7 +41146,7 @@ function journalVetoes(record6) {
|
|
|
40858
41146
|
}
|
|
40859
41147
|
function readTraefikWindow(cutoffMs) {
|
|
40860
41148
|
const since = String(Math.floor(cutoffMs / 1e3));
|
|
40861
|
-
const run = (args, maxBuffer) => (0,
|
|
41149
|
+
const run = (args, maxBuffer) => (0, import_node_child_process50.spawnSync)("docker", ["logs", "--timestamps", ...args, ROUTER_CONTAINER_NAME], {
|
|
40862
41150
|
encoding: "utf-8",
|
|
40863
41151
|
maxBuffer,
|
|
40864
41152
|
...networkDockerOptions()
|
|
@@ -41027,12 +41315,12 @@ function setIdlePin(repoPath, pinned) {
|
|
|
41027
41315
|
}
|
|
41028
41316
|
);
|
|
41029
41317
|
}
|
|
41030
|
-
var
|
|
41318
|
+
var import_node_child_process50, import_node_fs65, import_node_path77, DEFAULT_IDLE_FOR, ACTIVITY_FILES, IdleStopSkipped, defaultDependencies;
|
|
41031
41319
|
var init_workspace_idle = __esm({
|
|
41032
41320
|
"src/core/workspace-idle.ts"() {
|
|
41033
41321
|
"use strict";
|
|
41034
|
-
|
|
41035
|
-
|
|
41322
|
+
import_node_child_process50 = require("child_process");
|
|
41323
|
+
import_node_fs65 = __toESM(require("fs"));
|
|
41036
41324
|
import_node_path77 = __toESM(require("path"));
|
|
41037
41325
|
init_devpod_environment();
|
|
41038
41326
|
init_devpod_workspaces();
|
|
@@ -41054,7 +41342,7 @@ var init_workspace_idle = __esm({
|
|
|
41054
41342
|
readJournals: () => listReliabilityOperations(),
|
|
41055
41343
|
journalModifiedMs: (record6) => {
|
|
41056
41344
|
try {
|
|
41057
|
-
return
|
|
41345
|
+
return import_node_fs65.default.statSync(reliabilityOperationPath(record6.identity)).mtimeMs;
|
|
41058
41346
|
} catch {
|
|
41059
41347
|
return void 0;
|
|
41060
41348
|
}
|
|
@@ -41062,7 +41350,7 @@ var init_workspace_idle = __esm({
|
|
|
41062
41350
|
registryPaths: () => listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
41063
41351
|
inspectContainers: () => inspectWorkspaceContainers(),
|
|
41064
41352
|
statActivity: (containerId) => {
|
|
41065
|
-
const result = (0,
|
|
41353
|
+
const result = (0, import_node_child_process50.spawnSync)(
|
|
41066
41354
|
"docker",
|
|
41067
41355
|
["exec", containerId, "stat", "-c", "%Y", ...ACTIVITY_FILES],
|
|
41068
41356
|
{
|
|
@@ -41077,7 +41365,7 @@ var init_workspace_idle = __esm({
|
|
|
41077
41365
|
};
|
|
41078
41366
|
},
|
|
41079
41367
|
readTraefik: readTraefikWindow,
|
|
41080
|
-
isConfiguredCheckout: (repoPath) =>
|
|
41368
|
+
isConfiguredCheckout: (repoPath) => import_node_fs65.default.existsSync(import_node_path77.default.join(repoPath, ".devrouter.yml")),
|
|
41081
41369
|
gitCommonDir: (repoPath) => {
|
|
41082
41370
|
try {
|
|
41083
41371
|
return resolveGitCommonDir(repoPath);
|
|
@@ -41171,7 +41459,7 @@ function defaultWorktreePath(mainRepo, ws) {
|
|
|
41171
41459
|
return import_node_path78.default.join(mainRepo, "trees", ws);
|
|
41172
41460
|
}
|
|
41173
41461
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
41174
|
-
const ignored = (0,
|
|
41462
|
+
const ignored = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
41175
41463
|
encoding: "utf-8"
|
|
41176
41464
|
});
|
|
41177
41465
|
if (ignored.status !== 0) {
|
|
@@ -41293,7 +41581,7 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
41293
41581
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
41294
41582
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
41295
41583
|
}
|
|
41296
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
41584
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs66.default.existsSync(target.worktreePath)) return;
|
|
41297
41585
|
if (target.worktree.locked) {
|
|
41298
41586
|
throw new Error(
|
|
41299
41587
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
@@ -41325,7 +41613,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41325
41613
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
41326
41614
|
);
|
|
41327
41615
|
const generatedPath = candidatePaths.find(
|
|
41328
|
-
(candidate) => !
|
|
41616
|
+
(candidate) => !import_node_fs66.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
41329
41617
|
);
|
|
41330
41618
|
const selectedPath = opts.path ? import_node_path78.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
41331
41619
|
if (!selectedPath) {
|
|
@@ -41336,7 +41624,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41336
41624
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
41337
41625
|
);
|
|
41338
41626
|
}
|
|
41339
|
-
if (
|
|
41627
|
+
if (import_node_fs66.default.existsSync(selectedPath)) {
|
|
41340
41628
|
const registered = worktrees.find(
|
|
41341
41629
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
41342
41630
|
);
|
|
@@ -41355,11 +41643,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41355
41643
|
return selectedPath;
|
|
41356
41644
|
}
|
|
41357
41645
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
41358
|
-
const add2 = (0,
|
|
41646
|
+
const add2 = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
41359
41647
|
encoding: "utf-8"
|
|
41360
41648
|
});
|
|
41361
41649
|
if (add2.status !== 0) {
|
|
41362
|
-
const addNew = (0,
|
|
41650
|
+
const addNew = (0, import_node_child_process51.spawnSync)(
|
|
41363
41651
|
"git",
|
|
41364
41652
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
41365
41653
|
{ encoding: "utf-8" }
|
|
@@ -41499,8 +41787,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41499
41787
|
}
|
|
41500
41788
|
const result = await mutateWorkspaceRuntime("delete", resolved2, worktrees, opts.quiet);
|
|
41501
41789
|
if (removeWorktree) {
|
|
41502
|
-
if (resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41503
|
-
const rm = (0,
|
|
41790
|
+
if (resolved2.worktree && !resolved2.worktree.prunable && import_node_fs66.default.existsSync(resolved2.worktreePath)) {
|
|
41791
|
+
const rm = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved2.worktreePath], {
|
|
41504
41792
|
encoding: "utf-8"
|
|
41505
41793
|
});
|
|
41506
41794
|
if (rm.status !== 0) {
|
|
@@ -41518,7 +41806,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41518
41806
|
}
|
|
41519
41807
|
return result;
|
|
41520
41808
|
};
|
|
41521
|
-
return resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41809
|
+
return resolved2.worktree && !resolved2.worktree.prunable && import_node_fs66.default.existsSync(resolved2.worktreePath) ? withLifecycleOperationLock(resolved2.worktreePath, operation) : operation();
|
|
41522
41810
|
}
|
|
41523
41811
|
async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRemove, steps) {
|
|
41524
41812
|
await withLifecycleOperationLock(worktreePath, async () => {
|
|
@@ -41544,7 +41832,7 @@ async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRem
|
|
|
41544
41832
|
);
|
|
41545
41833
|
steps.push("runtime-deleted");
|
|
41546
41834
|
}
|
|
41547
|
-
const rm = (0,
|
|
41835
|
+
const rm = (0, import_node_child_process51.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", worktreePath], {
|
|
41548
41836
|
encoding: "utf-8"
|
|
41549
41837
|
});
|
|
41550
41838
|
if (rm.status !== 0) {
|
|
@@ -41565,12 +41853,12 @@ async function workspaceStop(target, opts = {}) {
|
|
|
41565
41853
|
async function workspaceDown(target, opts = {}) {
|
|
41566
41854
|
return runWorkspaceLifecycle("down", target, opts);
|
|
41567
41855
|
}
|
|
41568
|
-
var
|
|
41856
|
+
var import_node_child_process51, import_node_fs66, import_node_path78, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
41569
41857
|
var init_workspace_lifecycle = __esm({
|
|
41570
41858
|
"src/core/workspace-lifecycle.ts"() {
|
|
41571
41859
|
"use strict";
|
|
41572
|
-
|
|
41573
|
-
|
|
41860
|
+
import_node_child_process51 = require("child_process");
|
|
41861
|
+
import_node_fs66 = __toESM(require("fs"));
|
|
41574
41862
|
import_node_path78 = __toESM(require("path"));
|
|
41575
41863
|
init_devpod_mutation();
|
|
41576
41864
|
init_devpod_workspaces();
|
|
@@ -41590,7 +41878,7 @@ var init_workspace_lifecycle = __esm({
|
|
|
41590
41878
|
|
|
41591
41879
|
// src/core/worktree-trim.ts
|
|
41592
41880
|
function listIgnoredPaths(worktreePath) {
|
|
41593
|
-
const result = (0,
|
|
41881
|
+
const result = (0, import_node_child_process52.spawnSync)(
|
|
41594
41882
|
"git",
|
|
41595
41883
|
[
|
|
41596
41884
|
"-C",
|
|
@@ -41679,14 +41967,14 @@ function isInside(parent, child) {
|
|
|
41679
41967
|
}
|
|
41680
41968
|
function exists(file) {
|
|
41681
41969
|
try {
|
|
41682
|
-
|
|
41970
|
+
import_node_fs67.default.lstatSync(file);
|
|
41683
41971
|
return true;
|
|
41684
41972
|
} catch {
|
|
41685
41973
|
return false;
|
|
41686
41974
|
}
|
|
41687
41975
|
}
|
|
41688
41976
|
function hasTrackedFiles(worktreePath, relative2) {
|
|
41689
|
-
const result = (0,
|
|
41977
|
+
const result = (0, import_node_child_process52.spawnSync)(
|
|
41690
41978
|
"git",
|
|
41691
41979
|
["-C", worktreePath, "--literal-pathspecs", "ls-files", "-z", "--", relative2],
|
|
41692
41980
|
{ encoding: "utf-8", env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" } }
|
|
@@ -41697,7 +41985,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41697
41985
|
const target = import_node_path79.default.join(candidate.path, relative2);
|
|
41698
41986
|
let stat;
|
|
41699
41987
|
try {
|
|
41700
|
-
stat =
|
|
41988
|
+
stat = import_node_fs67.default.lstatSync(target);
|
|
41701
41989
|
} catch (error) {
|
|
41702
41990
|
if (error.code === "ENOENT") {
|
|
41703
41991
|
steps.push(`gone:${relative2}`);
|
|
@@ -41709,7 +41997,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41709
41997
|
steps.push(`skipped-symlink:${relative2}`);
|
|
41710
41998
|
return;
|
|
41711
41999
|
}
|
|
41712
|
-
if (!isInside(
|
|
42000
|
+
if (!isInside(import_node_fs67.default.realpathSync.native(candidate.path), import_node_fs67.default.realpathSync.native(target))) {
|
|
41713
42001
|
steps.push(`skipped-outside:${relative2}`);
|
|
41714
42002
|
return;
|
|
41715
42003
|
}
|
|
@@ -41722,7 +42010,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41722
42010
|
return;
|
|
41723
42011
|
}
|
|
41724
42012
|
try {
|
|
41725
|
-
|
|
42013
|
+
import_node_fs67.default.rmSync(target, { recursive: true, force: true });
|
|
41726
42014
|
} catch (error) {
|
|
41727
42015
|
steps.push(`partial:${relative2}`);
|
|
41728
42016
|
throw error;
|
|
@@ -41823,12 +42111,12 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41823
42111
|
}
|
|
41824
42112
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
41825
42113
|
}
|
|
41826
|
-
var
|
|
42114
|
+
var import_node_child_process52, import_node_fs67, import_node_path79;
|
|
41827
42115
|
var init_worktree_trim = __esm({
|
|
41828
42116
|
"src/core/worktree-trim.ts"() {
|
|
41829
42117
|
"use strict";
|
|
41830
|
-
|
|
41831
|
-
|
|
42118
|
+
import_node_child_process52 = require("child_process");
|
|
42119
|
+
import_node_fs67 = __toESM(require("fs"));
|
|
41832
42120
|
import_node_path79 = __toESM(require("path"));
|
|
41833
42121
|
init_reliability_lifecycle();
|
|
41834
42122
|
init_worktree_reclaim();
|
|
@@ -41897,7 +42185,7 @@ function runWorkspaceLsCommand(options) {
|
|
|
41897
42185
|
}
|
|
41898
42186
|
function writeManifestOutput(manifest, output2) {
|
|
41899
42187
|
if (output2) {
|
|
41900
|
-
|
|
42188
|
+
import_node_fs68.default.writeFileSync(output2, manifest, { flag: "wx" });
|
|
41901
42189
|
process.stdout.write(`${sha256Hex(manifest)} ${output2}
|
|
41902
42190
|
`);
|
|
41903
42191
|
} else {
|
|
@@ -41927,7 +42215,7 @@ function runWorkspaceCleanupCommand(options) {
|
|
|
41927
42215
|
throw new Error("--manifest requires --all-worktrees and --check-merged.");
|
|
41928
42216
|
}
|
|
41929
42217
|
const createdAtEpoch = Math.floor(Date.now() / 1e3);
|
|
41930
|
-
const worktrees =
|
|
42218
|
+
const worktrees = import_node_fs68.default.existsSync(import_node_path80.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
41931
42219
|
const manifest = action2 === "trim" ? buildTrimManifest(
|
|
41932
42220
|
report,
|
|
41933
42221
|
{ trim: worktrees?.trim ?? [], disposable: worktrees?.disposable },
|
|
@@ -41965,7 +42253,7 @@ async function runWorkspaceIdleCommand(options) {
|
|
|
41965
42253
|
if (options.stop) {
|
|
41966
42254
|
const paths = idleSweepPaths();
|
|
41967
42255
|
if (!process.stderr.isTTY) muteLifecycleProgressHeartbeat();
|
|
41968
|
-
|
|
42256
|
+
import_node_fs68.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
41969
42257
|
const result = await withFileLock(paths.lock, { activity: "idle sweep" }, async () => {
|
|
41970
42258
|
try {
|
|
41971
42259
|
const swept = await stopIdleEnvironments(
|
|
@@ -42067,7 +42355,7 @@ async function runWorkspaceJournalSettleCommand(options) {
|
|
|
42067
42355
|
function runWorkspaceManifestHashCommand(file) {
|
|
42068
42356
|
let leftover = false;
|
|
42069
42357
|
try {
|
|
42070
|
-
leftover = isLeftoverManifest(JSON.parse(
|
|
42358
|
+
leftover = isLeftoverManifest(JSON.parse(import_node_fs68.default.readFileSync(file, "utf-8")));
|
|
42071
42359
|
} catch {
|
|
42072
42360
|
}
|
|
42073
42361
|
const { raw } = leftover ? readLeftoverManifest(file) : readManifest(file);
|
|
@@ -42164,11 +42452,11 @@ async function runWorkspaceTrimCommand(options) {
|
|
|
42164
42452
|
process.exitCode = 1;
|
|
42165
42453
|
}
|
|
42166
42454
|
}
|
|
42167
|
-
var
|
|
42455
|
+
var import_node_fs68, import_node_path80;
|
|
42168
42456
|
var init_workspace2 = __esm({
|
|
42169
42457
|
"src/commands/workspace.ts"() {
|
|
42170
42458
|
"use strict";
|
|
42171
|
-
|
|
42459
|
+
import_node_fs68 = __toESM(require("fs"));
|
|
42172
42460
|
import_node_path80 = __toESM(require("path"));
|
|
42173
42461
|
init_docker_leftovers();
|
|
42174
42462
|
init_file_lock();
|
|
@@ -42227,7 +42515,7 @@ var init_version = __esm({
|
|
|
42227
42515
|
|
|
42228
42516
|
// src/cli.ts
|
|
42229
42517
|
var import_commander = require("commander");
|
|
42230
|
-
var CLI_VERSION = true ? "0.6.
|
|
42518
|
+
var CLI_VERSION = true ? "0.6.4" : "0.0.0-dev";
|
|
42231
42519
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
42232
42520
|
function withErrorHandling(action2) {
|
|
42233
42521
|
return async (...args) => {
|
|
@@ -42321,7 +42609,7 @@ program.command("up").description("Ensure devnet and start shared Traefik (reser
|
|
|
42321
42609
|
await runUpCommand2();
|
|
42322
42610
|
})
|
|
42323
42611
|
);
|
|
42324
|
-
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(
|
|
42612
|
+
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(
|
|
42325
42613
|
withErrorHandling(async (repoPath, _options, command) => {
|
|
42326
42614
|
const options = command.opts();
|
|
42327
42615
|
const { runEnsureCommand: runEnsureCommand2 } = await Promise.resolve().then(() => (init_ensure(), ensure_exports));
|
|
@@ -42331,6 +42619,7 @@ program.command("ensure").description("Start and prove a primary or linked check
|
|
|
42331
42619
|
variant: options.variant,
|
|
42332
42620
|
repair: options.repair,
|
|
42333
42621
|
initializeNew: options.initializeNew,
|
|
42622
|
+
replaceApp: options.replaceApp,
|
|
42334
42623
|
open: Boolean(options.open),
|
|
42335
42624
|
json: Boolean(options.json)
|
|
42336
42625
|
});
|
|
@@ -42595,7 +42884,7 @@ workspaceCommand2.command("up").description(
|
|
|
42595
42884
|
);
|
|
42596
42885
|
workspaceCommand2.command("ensure").description(
|
|
42597
42886
|
"Start and prove a primary or linked checkout's workspace runtime, upstreams, and routes"
|
|
42598
|
-
).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(
|
|
42887
|
+
).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(
|
|
42599
42888
|
withErrorHandling(
|
|
42600
42889
|
async (worktreePath, _options, command) => {
|
|
42601
42890
|
const options = command.opts();
|
|
@@ -42606,6 +42895,7 @@ workspaceCommand2.command("ensure").description(
|
|
|
42606
42895
|
variant: options.variant,
|
|
42607
42896
|
repair: options.repair,
|
|
42608
42897
|
initializeNew: options.initializeNew,
|
|
42898
|
+
replaceApp: options.replaceApp,
|
|
42609
42899
|
open: Boolean(options.open),
|
|
42610
42900
|
json: Boolean(options.json)
|
|
42611
42901
|
});
|