@devrouter/cli 0.6.1 → 0.6.3
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 +829 -222
- package/dist/devrouter.js +931 -763
- package/package.json +1 -1
- package/upgrade-prompts/0.6.2.md +51 -0
- package/upgrade-prompts/0.6.3.md +51 -0
package/dist/devrouter.js
CHANGED
|
@@ -4033,7 +4033,7 @@ function parseManagedRuntime(value, configPath) {
|
|
|
4033
4033
|
);
|
|
4034
4034
|
ensureAllowedKeys2(
|
|
4035
4035
|
devcontainer,
|
|
4036
|
-
["baseServices", "profileServices", "prepareCommand", "hostPorts"],
|
|
4036
|
+
["baseServices", "profileServices", "prepareCommand", "hostPorts", "freshBootstrap"],
|
|
4037
4037
|
`${configPath}.managedRuntime.devcontainer`
|
|
4038
4038
|
);
|
|
4039
4039
|
const baseServices = parseRequiredUniqueStringArray(
|
|
@@ -4048,6 +4048,23 @@ function parseManagedRuntime(value, configPath) {
|
|
|
4048
4048
|
devcontainer.prepareCommand,
|
|
4049
4049
|
`${configPath}.managedRuntime.devcontainer.prepareCommand`
|
|
4050
4050
|
);
|
|
4051
|
+
let freshBootstrap;
|
|
4052
|
+
if (devcontainer.freshBootstrap !== void 0) {
|
|
4053
|
+
const label2 = `${configPath}.managedRuntime.devcontainer.freshBootstrap`;
|
|
4054
|
+
const raw = ensureObject2(devcontainer.freshBootstrap, label2);
|
|
4055
|
+
ensureAllowedKeys2(raw, ["command", "dataVolumes", "sharedCaches"], label2);
|
|
4056
|
+
const command = parsePrepareCommand(raw.command, `${label2}.command`);
|
|
4057
|
+
if (!command) throw new Error(`${label2}.command is required.`);
|
|
4058
|
+
const dataVolumes = parseRequiredUniqueStringArray(raw.dataVolumes, `${label2}.dataVolumes`);
|
|
4059
|
+
const sharedCaches = raw.sharedCaches === void 0 ? [] : parseRequiredUniqueStringArray(raw.sharedCaches, `${label2}.sharedCaches`);
|
|
4060
|
+
if (dataVolumes.length === 0 || dataVolumes.length + sharedCaches.length > 64)
|
|
4061
|
+
throw new Error(`${label2} requires data volumes and at most 64 volume bindings.`);
|
|
4062
|
+
if ([...dataVolumes, ...sharedCaches].some(
|
|
4063
|
+
(key) => !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(key)
|
|
4064
|
+
) || dataVolumes.some((key) => sharedCaches.includes(key)))
|
|
4065
|
+
throw new Error(`${label2} requires distinct exact data-volume and shared-cache keys.`);
|
|
4066
|
+
freshBootstrap = { command, dataVolumes, sharedCaches };
|
|
4067
|
+
}
|
|
4051
4068
|
const baseSet = new Set(baseServices);
|
|
4052
4069
|
const overlappingServices = profileServices.filter((service) => baseSet.has(service));
|
|
4053
4070
|
if (overlappingServices.length > 0) {
|
|
@@ -4109,7 +4126,8 @@ function parseManagedRuntime(value, configPath) {
|
|
|
4109
4126
|
baseServices,
|
|
4110
4127
|
profileServices,
|
|
4111
4128
|
...prepareCommand ? { prepareCommand } : {},
|
|
4112
|
-
...hostPorts !== void 0 ? { hostPorts } : {}
|
|
4129
|
+
...hostPorts !== void 0 ? { hostPorts } : {},
|
|
4130
|
+
...freshBootstrap ? { freshBootstrap } : {}
|
|
4113
4131
|
},
|
|
4114
4132
|
processes
|
|
4115
4133
|
};
|
|
@@ -4880,7 +4898,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs8.default.read
|
|
|
4880
4898
|
const config = parseRepoConfigSource(raw, configPath);
|
|
4881
4899
|
const requiredVersion = config.devrouter?.version;
|
|
4882
4900
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4883
|
-
const cliVersion = true ? "0.6.
|
|
4901
|
+
const cliVersion = true ? "0.6.3" : "0.0.0-dev";
|
|
4884
4902
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4885
4903
|
hasWarnedVersionMismatch = true;
|
|
4886
4904
|
process.stderr.write(
|
|
@@ -7153,7 +7171,7 @@ var init_reliability_contract = __esm({
|
|
|
7153
7171
|
|
|
7154
7172
|
// src/core/reliability-operation-store.ts
|
|
7155
7173
|
function installedCliVersion() {
|
|
7156
|
-
return true ? "0.6.
|
|
7174
|
+
return true ? "0.6.3" : "0.0.0-dev";
|
|
7157
7175
|
}
|
|
7158
7176
|
function compareCliVersions(left, right) {
|
|
7159
7177
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -7294,6 +7312,7 @@ function validate2(record6, identity2) {
|
|
|
7294
7312
|
"state",
|
|
7295
7313
|
"worker",
|
|
7296
7314
|
"stopWorkStarted",
|
|
7315
|
+
"freshBootstrap",
|
|
7297
7316
|
"effectSequence",
|
|
7298
7317
|
"outcome",
|
|
7299
7318
|
"result",
|
|
@@ -7311,6 +7330,47 @@ function validate2(record6, identity2) {
|
|
|
7311
7330
|
]);
|
|
7312
7331
|
validateConsumerProtection(record6);
|
|
7313
7332
|
validateIdleProtection(record6);
|
|
7333
|
+
if (record6.freshBootstrap !== void 0) {
|
|
7334
|
+
const attempt = record6.freshBootstrap;
|
|
7335
|
+
keys(attempt, [
|
|
7336
|
+
"version",
|
|
7337
|
+
"operationId",
|
|
7338
|
+
"workerId",
|
|
7339
|
+
"runtimeGeneration",
|
|
7340
|
+
"sourceSha256",
|
|
7341
|
+
"providerId",
|
|
7342
|
+
"providerContext",
|
|
7343
|
+
"definitionSha256",
|
|
7344
|
+
"endpoint",
|
|
7345
|
+
"daemonId",
|
|
7346
|
+
"previousVolumeNameDigests",
|
|
7347
|
+
"stage",
|
|
7348
|
+
"resources"
|
|
7349
|
+
]);
|
|
7350
|
+
const digest5 = (value) => typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
|
|
7351
|
+
const exact = (value) => typeof value === "string" && /^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,127}$/.test(value);
|
|
7352
|
+
if (attempt.version !== 1 || !isReliabilityId(attempt.operationId) || !isReliabilityId(attempt.workerId) || !isReliabilityCounter(attempt.runtimeGeneration) || !digest5(attempt.sourceSha256) || !digest5(attempt.definitionSha256) || !exact(attempt.providerId) || !exact(attempt.providerContext) || typeof attempt.endpoint !== "string" || !attempt.endpoint.startsWith("unix:///") || attempt.endpoint.includes("\0") || typeof attempt.daemonId !== "string" || attempt.daemonId.length === 0 || attempt.daemonId.length > 256 || !["claimed", "provisioned", "initializing", "initialized", "ready", "failed"].includes(
|
|
7353
|
+
attempt.stage
|
|
7354
|
+
) || !Array.isArray(attempt.previousVolumeNameDigests) || attempt.previousVolumeNameDigests.length > 4096 || !attempt.previousVolumeNameDigests.every(digest5) || new Set(attempt.previousVolumeNameDigests).size !== attempt.previousVolumeNameDigests.length)
|
|
7355
|
+
throw new Error("Invalid durable fresh-bootstrap attempt.");
|
|
7356
|
+
if (attempt.resources !== void 0) {
|
|
7357
|
+
const resources = attempt.resources;
|
|
7358
|
+
keys(resources, ["primaryId", "project", "dataVolumes"]);
|
|
7359
|
+
if (!digest5(resources.primaryId) || !exact(resources.project) || !Array.isArray(resources.dataVolumes) || resources.dataVolumes.length === 0 || resources.dataVolumes.length > 64)
|
|
7360
|
+
throw new Error("Invalid fresh-bootstrap resource binding.");
|
|
7361
|
+
const names = /* @__PURE__ */ new Set();
|
|
7362
|
+
const bindings2 = /* @__PURE__ */ new Set();
|
|
7363
|
+
for (const volume of resources.dataVolumes) {
|
|
7364
|
+
keys(volume, ["key", "name", "createdAt", "mountpoint"]);
|
|
7365
|
+
if (!exact(volume.key) || typeof volume.name !== "string" || !/^[a-zA-Z0-9][a-zA-Z0-9_.-]{0,255}$/.test(volume.name) || names.has(volume.name) || bindings2.has(volume.key) || typeof volume.createdAt !== "string" || !Number.isFinite(Date.parse(volume.createdAt)) || typeof volume.mountpoint !== "string" || !import_node_path16.default.isAbsolute(volume.mountpoint) || volume.mountpoint.includes("\0"))
|
|
7366
|
+
throw new Error("Invalid fresh-bootstrap data-volume binding.");
|
|
7367
|
+
names.add(volume.name);
|
|
7368
|
+
bindings2.add(volume.key);
|
|
7369
|
+
}
|
|
7370
|
+
} else if (["provisioned", "initializing", "initialized", "ready"].includes(attempt.stage)) {
|
|
7371
|
+
throw new Error("Fresh-bootstrap phase requires proven resource bindings.");
|
|
7372
|
+
}
|
|
7373
|
+
}
|
|
7314
7374
|
if (record6.writtenByVersion !== void 0 && compareCliVersions(record6.writtenByVersion, installedCliVersion()) > 0) {
|
|
7315
7375
|
throw new Error(
|
|
7316
7376
|
`Reliability record was last written by devrouter ${record6.writtenByVersion}, which is newer than the installed ${installedCliVersion()}; upgrade devrouter (devrouter upgrade) before running lifecycle commands.`
|
|
@@ -7775,10 +7835,30 @@ function updateReliabilityOperation(identity2, operation) {
|
|
|
7775
7835
|
const previousEnrollment = record6.enrollment && { ...record6.enrollment };
|
|
7776
7836
|
const previousProtection = structuredClone(record6.consumerProtection);
|
|
7777
7837
|
const previousIdleProtection = structuredClone(record6.idleProtection);
|
|
7838
|
+
const previousBootstrap = structuredClone(record6.freshBootstrap);
|
|
7778
7839
|
const result = operation(record6);
|
|
7779
7840
|
if (result && typeof result.then === "function") {
|
|
7780
7841
|
throw new Error("Reliability record updates must be synchronous.");
|
|
7781
7842
|
}
|
|
7843
|
+
if (previousBootstrap && !(0, import_node_util3.isDeepStrictEqual)(previousBootstrap, record6.freshBootstrap)) {
|
|
7844
|
+
const current = record6.freshBootstrap;
|
|
7845
|
+
const {
|
|
7846
|
+
stage: previousStage,
|
|
7847
|
+
resources: previousResources,
|
|
7848
|
+
...previousIdentity
|
|
7849
|
+
} = previousBootstrap;
|
|
7850
|
+
const { stage, resources, ...currentIdentity } = current ?? {};
|
|
7851
|
+
const next = {
|
|
7852
|
+
claimed: ["provisioned", "failed"],
|
|
7853
|
+
provisioned: ["initializing", "failed"],
|
|
7854
|
+
initializing: ["initialized", "failed"],
|
|
7855
|
+
initialized: ["ready"],
|
|
7856
|
+
ready: [],
|
|
7857
|
+
failed: []
|
|
7858
|
+
};
|
|
7859
|
+
if (!current || !(0, import_node_util3.isDeepStrictEqual)(previousIdentity, currentIdentity) || !next[previousStage].includes(stage ?? "") || previousResources && !(0, import_node_util3.isDeepStrictEqual)(previousResources, resources))
|
|
7860
|
+
throw new Error("Durable fresh-bootstrap attempt cannot be cleared, replaced or rearmed.");
|
|
7861
|
+
}
|
|
7782
7862
|
if (record6.version < previousVersion || previousEnrollment && !(0, import_node_util3.isDeepStrictEqual)(record6.enrollment, previousEnrollment))
|
|
7783
7863
|
throw new Error("Durable capacity enrollment cannot be downgraded or replaced.");
|
|
7784
7864
|
if (!(0, import_node_util3.isDeepStrictEqual)(record6.consumerProtection, previousProtection))
|
|
@@ -8936,13 +9016,15 @@ function parseControllerRequest(input2) {
|
|
|
8936
9016
|
input2,
|
|
8937
9017
|
"operation-submit",
|
|
8938
9018
|
["session", "store", "epoch", "generation", "requestId", "kind"],
|
|
8939
|
-
["operation", "command"]
|
|
9019
|
+
["operation", "command", "initializeNew"]
|
|
8940
9020
|
);
|
|
8941
9021
|
const kind = input2.kind;
|
|
8942
9022
|
if (kind !== "ensure" && kind !== "exec") invalidRequest();
|
|
8943
9023
|
const operation = optionalString(input2, "operation", parseId);
|
|
8944
9024
|
if (kind === "ensure") {
|
|
8945
9025
|
if (Object.hasOwn(input2, "command")) invalidRequest();
|
|
9026
|
+
if (Object.hasOwn(input2, "initializeNew") && input2.initializeNew !== true)
|
|
9027
|
+
invalidRequest();
|
|
8946
9028
|
return {
|
|
8947
9029
|
...header,
|
|
8948
9030
|
session: parseId(input2.session),
|
|
@@ -8951,10 +9033,12 @@ function parseControllerRequest(input2) {
|
|
|
8951
9033
|
generation: parseId(input2.generation),
|
|
8952
9034
|
requestId: parseId(input2.requestId),
|
|
8953
9035
|
kind,
|
|
8954
|
-
...operation === void 0 ? {} : { operation }
|
|
9036
|
+
...operation === void 0 ? {} : { operation },
|
|
9037
|
+
...input2.initializeNew === true ? { initializeNew: true } : {}
|
|
8955
9038
|
};
|
|
8956
9039
|
}
|
|
8957
|
-
if (!Object.hasOwn(input2, "command")
|
|
9040
|
+
if (!Object.hasOwn(input2, "command") || Object.hasOwn(input2, "initializeNew"))
|
|
9041
|
+
invalidRequest();
|
|
8958
9042
|
return {
|
|
8959
9043
|
...header,
|
|
8960
9044
|
session: parseId(input2.session),
|
|
@@ -14923,12 +15007,113 @@ var init_devsy_mutation = __esm({
|
|
|
14923
15007
|
}
|
|
14924
15008
|
});
|
|
14925
15009
|
|
|
15010
|
+
// src/core/lifecycle-progress.ts
|
|
15011
|
+
function isLifecycleProgressPhase(value) {
|
|
15012
|
+
return typeof value === "string" && Object.hasOwn(ROLES, value);
|
|
15013
|
+
}
|
|
15014
|
+
function muteLifecycleProgressHeartbeat() {
|
|
15015
|
+
heartbeatMuted = true;
|
|
15016
|
+
}
|
|
15017
|
+
function lifecycleProgressHeartbeatMuted() {
|
|
15018
|
+
return heartbeatMuted;
|
|
15019
|
+
}
|
|
15020
|
+
function lifecycleProgressSnapshot(phase, receivedAt, now) {
|
|
15021
|
+
const elapsedMs = receivedAt === void 0 ? null : Math.max(0, Math.floor(now - receivedAt));
|
|
15022
|
+
return {
|
|
15023
|
+
type: "lifecycle-progress",
|
|
15024
|
+
phase: phase ?? "unknown",
|
|
15025
|
+
role: phase ? ROLES[phase] : "unknown",
|
|
15026
|
+
elapsedMs,
|
|
15027
|
+
evidence: elapsedMs === null ? "unknown" : elapsedMs >= 3e4 ? "stale" : "recent",
|
|
15028
|
+
liveness: "unknown"
|
|
15029
|
+
};
|
|
15030
|
+
}
|
|
15031
|
+
var ROLES, heartbeatMuted;
|
|
15032
|
+
var init_lifecycle_progress = __esm({
|
|
15033
|
+
"src/core/lifecycle-progress.ts"() {
|
|
15034
|
+
"use strict";
|
|
15035
|
+
ROLES = {
|
|
15036
|
+
validation: "lifecycle-worker",
|
|
15037
|
+
preparation: "repository-preparation",
|
|
15038
|
+
"fresh-bootstrap": "repository-fresh-bootstrap",
|
|
15039
|
+
provider: "provider-operation",
|
|
15040
|
+
"service-start": "service-reconciliation",
|
|
15041
|
+
"service-stop": "service-reconciliation",
|
|
15042
|
+
"process-start": "repository-process-adapter",
|
|
15043
|
+
"process-stop": "repository-process-adapter",
|
|
15044
|
+
"route-publication": "lifecycle-worker",
|
|
15045
|
+
"route-removal": "lifecycle-worker",
|
|
15046
|
+
readiness: "lifecycle-worker",
|
|
15047
|
+
rollback: "lifecycle-worker",
|
|
15048
|
+
stop: "lifecycle-stop"
|
|
15049
|
+
};
|
|
15050
|
+
heartbeatMuted = false;
|
|
15051
|
+
}
|
|
15052
|
+
});
|
|
15053
|
+
|
|
15054
|
+
// src/core/managed-fresh-bootstrap.ts
|
|
15055
|
+
function object4(value) {
|
|
15056
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
15057
|
+
}
|
|
15058
|
+
function qualifiedContext(source) {
|
|
15059
|
+
if (source.userEnvProbe !== void 0 && source.userEnvProbe !== "loginInteractiveShell" || object4(source.remoteEnv) && Object.hasOwn(source.remoteEnv, "PATH") || object4(source.secrets) && Object.keys(source.secrets).length > 0 || object4(source.features) && Object.keys(source.features).length > 0 || source.onCreateCommand || source.updateContentCommand)
|
|
15060
|
+
throw new Error(
|
|
15061
|
+
"Fresh bootstrap requires a qualified default-probe context without PATH overrides, secrets, features or earlier container hooks."
|
|
15062
|
+
);
|
|
15063
|
+
if (source.postStartCommand && !["postStartCommand", "postAttachCommand"].includes(String(source.waitFor)))
|
|
15064
|
+
throw new Error("Fresh bootstrap requires waitFor to include the declared post-start hook.");
|
|
15065
|
+
}
|
|
15066
|
+
function assertFreshBootstrapRequest(identity2, options) {
|
|
15067
|
+
if (!options.initializeNew) return;
|
|
15068
|
+
if (identity2.provider !== "devsy" || options.repair)
|
|
15069
|
+
throw new Error(
|
|
15070
|
+
"--initialize-new requires a fresh Devsy managed environment without --repair."
|
|
15071
|
+
);
|
|
15072
|
+
if (!loadRepoConfig(identity2.repoPath).managedRuntime?.devcontainer.freshBootstrap)
|
|
15073
|
+
throw new Error("--initialize-new requires managedRuntime.devcontainer.freshBootstrap.");
|
|
15074
|
+
if (readReliabilityOperation(identity2)?.freshBootstrap)
|
|
15075
|
+
throw new Error(
|
|
15076
|
+
"This environment already records an initialization attempt; initialization cannot be replayed. Use preserving recovery or a new disposable checkout."
|
|
15077
|
+
);
|
|
15078
|
+
if (readManagedRuntimeState(identity2.repoPath, identity2.workspace ?? void 0) || selectDevsyWorkspace(listDevsyWorkspaces(), identity2.repoPath))
|
|
15079
|
+
throw new Error("Fresh bootstrap refuses a retained runtime or provider registration.");
|
|
15080
|
+
qualifiedContext(readDevcontainerConfig(identity2.repoPath).source);
|
|
15081
|
+
}
|
|
15082
|
+
var import_node_child_process20, import_node_crypto18, import_node_fs31, import_node_os6, import_node_path39, import_node_util11, import_yaml4;
|
|
15083
|
+
var init_managed_fresh_bootstrap = __esm({
|
|
15084
|
+
"src/core/managed-fresh-bootstrap.ts"() {
|
|
15085
|
+
"use strict";
|
|
15086
|
+
import_node_child_process20 = require("child_process");
|
|
15087
|
+
import_node_crypto18 = require("crypto");
|
|
15088
|
+
import_node_fs31 = __toESM(require("fs"));
|
|
15089
|
+
import_node_os6 = __toESM(require("os"));
|
|
15090
|
+
import_node_path39 = __toESM(require("path"));
|
|
15091
|
+
import_node_util11 = require("util");
|
|
15092
|
+
import_yaml4 = __toESM(require("yaml"));
|
|
15093
|
+
init_devcontainer_config();
|
|
15094
|
+
init_devcontainer_profile();
|
|
15095
|
+
init_devpod_environment();
|
|
15096
|
+
init_devsy_agent();
|
|
15097
|
+
init_devsy_exec_proof();
|
|
15098
|
+
init_devsy_workspaces();
|
|
15099
|
+
init_lifecycle_progress();
|
|
15100
|
+
init_managed_runtime_state();
|
|
15101
|
+
init_managed_stop_recovery();
|
|
15102
|
+
init_network_provider_binding();
|
|
15103
|
+
init_network_provider_inspect();
|
|
15104
|
+
init_reliability_lifecycle();
|
|
15105
|
+
init_reliability_operation_store();
|
|
15106
|
+
init_repo_config();
|
|
15107
|
+
init_workspace();
|
|
15108
|
+
}
|
|
15109
|
+
});
|
|
15110
|
+
|
|
14926
15111
|
// src/core/managed-host-ports.ts
|
|
14927
15112
|
function unavailableEntry(declaration, reason2) {
|
|
14928
15113
|
return { ...declaration, status: "unavailable", reason: reason2 };
|
|
14929
15114
|
}
|
|
14930
15115
|
function livePublishedBindings(containerId, target) {
|
|
14931
|
-
const result = (0,
|
|
15116
|
+
const result = (0, import_node_child_process21.spawnSync)("docker", ["port", containerId, `${target}/tcp`], {
|
|
14932
15117
|
encoding: "utf-8",
|
|
14933
15118
|
timeout: PORT_LOOKUP_TIMEOUT_MS,
|
|
14934
15119
|
maxBuffer: PORT_LOOKUP_MAX_BUFFER,
|
|
@@ -15068,7 +15253,7 @@ function managedHostPortDeclarationsIdentity(declarations) {
|
|
|
15068
15253
|
const keys2 = Object.keys(declarations).sort();
|
|
15069
15254
|
if (keys2.length === 0) return void 0;
|
|
15070
15255
|
const canonical = keys2.map((key) => [key, declarations[key].service, declarations[key].target]);
|
|
15071
|
-
return (0,
|
|
15256
|
+
return (0, import_node_crypto19.createHash)("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
15072
15257
|
}
|
|
15073
15258
|
function assertManagedHostPortsAvailable(report) {
|
|
15074
15259
|
const unavailable = Object.entries(report).filter(([, entry]) => entry.status === "unavailable").map(([key]) => key).sort();
|
|
@@ -15076,12 +15261,12 @@ function assertManagedHostPortsAvailable(report) {
|
|
|
15076
15261
|
throw new Error(`Selected managed host ports are unavailable: ${unavailable.join(", ")}.`);
|
|
15077
15262
|
}
|
|
15078
15263
|
}
|
|
15079
|
-
var
|
|
15264
|
+
var import_node_child_process21, import_node_crypto19, PORT_LOOKUP_TIMEOUT_MS, PORT_LOOKUP_MAX_BUFFER, LOOPBACK_BINDING;
|
|
15080
15265
|
var init_managed_host_ports = __esm({
|
|
15081
15266
|
"src/core/managed-host-ports.ts"() {
|
|
15082
15267
|
"use strict";
|
|
15083
|
-
|
|
15084
|
-
|
|
15268
|
+
import_node_child_process21 = require("child_process");
|
|
15269
|
+
import_node_crypto19 = require("crypto");
|
|
15085
15270
|
init_devpod_environment();
|
|
15086
15271
|
init_network_effect_scope();
|
|
15087
15272
|
PORT_LOOKUP_TIMEOUT_MS = 1e4;
|
|
@@ -15092,21 +15277,21 @@ var init_managed_host_ports = __esm({
|
|
|
15092
15277
|
|
|
15093
15278
|
// src/core/managed-post-start.ts
|
|
15094
15279
|
function readRegularFileBytes(filePath) {
|
|
15095
|
-
if (!
|
|
15096
|
-
return
|
|
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);
|
|
15097
15282
|
}
|
|
15098
15283
|
function readRegularFile(filePath) {
|
|
15099
15284
|
return readRegularFileBytes(filePath)?.toString("utf-8");
|
|
15100
15285
|
}
|
|
15101
15286
|
function adapterFingerprint(adapter) {
|
|
15102
|
-
return (0,
|
|
15287
|
+
return (0, import_node_crypto20.createHash)("sha256").update(adapter).digest("hex");
|
|
15103
15288
|
}
|
|
15104
15289
|
function resolveManagedPostStartPlan(repoPath) {
|
|
15105
|
-
const adapterPath =
|
|
15290
|
+
const adapterPath = import_node_path40.default.join(repoPath, MANAGED_ADAPTER_PATH);
|
|
15106
15291
|
const adapterBytes = readRegularFileBytes(adapterPath);
|
|
15107
15292
|
const adapterText = adapterBytes?.toString("utf-8");
|
|
15108
|
-
const dockerfilePath =
|
|
15109
|
-
const devcontainerPath =
|
|
15293
|
+
const dockerfilePath = import_node_path40.default.join(repoPath, ".devcontainer", "Dockerfile");
|
|
15294
|
+
const devcontainerPath = import_node_path40.default.join(repoPath, ".devcontainer", "devcontainer.json");
|
|
15110
15295
|
const dockerfile = readRegularFile(dockerfilePath) ?? "";
|
|
15111
15296
|
const devcontainer = readRegularFile(devcontainerPath) ?? "";
|
|
15112
15297
|
const devrouterPattern = [adapterText, dockerfile, devcontainer].filter((value) => value !== void 0).some(
|
|
@@ -15152,7 +15337,7 @@ function assertSafeProcessName(name) {
|
|
|
15152
15337
|
}
|
|
15153
15338
|
function runManagedProcessAction(options) {
|
|
15154
15339
|
assertSafeProcessName(options.name);
|
|
15155
|
-
const result = (0,
|
|
15340
|
+
const result = (0, import_node_child_process22.spawnSync)(
|
|
15156
15341
|
"docker",
|
|
15157
15342
|
[
|
|
15158
15343
|
"exec",
|
|
@@ -15189,14 +15374,14 @@ function runManagedProcessAction(options) {
|
|
|
15189
15374
|
}
|
|
15190
15375
|
return "drifted";
|
|
15191
15376
|
}
|
|
15192
|
-
var
|
|
15377
|
+
var import_node_child_process22, import_node_crypto20, import_node_fs32, import_node_path40, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH;
|
|
15193
15378
|
var init_managed_post_start = __esm({
|
|
15194
15379
|
"src/core/managed-post-start.ts"() {
|
|
15195
15380
|
"use strict";
|
|
15196
|
-
|
|
15197
|
-
|
|
15198
|
-
|
|
15199
|
-
|
|
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"));
|
|
15200
15385
|
init_devcontainer_config();
|
|
15201
15386
|
init_managed_host_ports();
|
|
15202
15387
|
init_network_effect_scope();
|
|
@@ -16060,80 +16245,37 @@ var init_reliability_model = __esm({
|
|
|
16060
16245
|
}
|
|
16061
16246
|
});
|
|
16062
16247
|
|
|
16063
|
-
// src/core/lifecycle-progress.ts
|
|
16064
|
-
function isLifecycleProgressPhase(value) {
|
|
16065
|
-
return typeof value === "string" && Object.hasOwn(ROLES, value);
|
|
16066
|
-
}
|
|
16067
|
-
function muteLifecycleProgressHeartbeat() {
|
|
16068
|
-
heartbeatMuted = true;
|
|
16069
|
-
}
|
|
16070
|
-
function lifecycleProgressHeartbeatMuted() {
|
|
16071
|
-
return heartbeatMuted;
|
|
16072
|
-
}
|
|
16073
|
-
function lifecycleProgressSnapshot(phase, receivedAt, now) {
|
|
16074
|
-
const elapsedMs = receivedAt === void 0 ? null : Math.max(0, Math.floor(now - receivedAt));
|
|
16075
|
-
return {
|
|
16076
|
-
type: "lifecycle-progress",
|
|
16077
|
-
phase: phase ?? "unknown",
|
|
16078
|
-
role: phase ? ROLES[phase] : "unknown",
|
|
16079
|
-
elapsedMs,
|
|
16080
|
-
evidence: elapsedMs === null ? "unknown" : elapsedMs >= 3e4 ? "stale" : "recent",
|
|
16081
|
-
liveness: "unknown"
|
|
16082
|
-
};
|
|
16083
|
-
}
|
|
16084
|
-
var ROLES, heartbeatMuted;
|
|
16085
|
-
var init_lifecycle_progress = __esm({
|
|
16086
|
-
"src/core/lifecycle-progress.ts"() {
|
|
16087
|
-
"use strict";
|
|
16088
|
-
ROLES = {
|
|
16089
|
-
validation: "lifecycle-worker",
|
|
16090
|
-
preparation: "repository-preparation",
|
|
16091
|
-
provider: "provider-operation",
|
|
16092
|
-
"service-start": "service-reconciliation",
|
|
16093
|
-
"service-stop": "service-reconciliation",
|
|
16094
|
-
"process-start": "repository-process-adapter",
|
|
16095
|
-
"process-stop": "repository-process-adapter",
|
|
16096
|
-
"route-publication": "lifecycle-worker",
|
|
16097
|
-
"route-removal": "lifecycle-worker",
|
|
16098
|
-
readiness: "lifecycle-worker",
|
|
16099
|
-
rollback: "lifecycle-worker",
|
|
16100
|
-
stop: "lifecycle-stop"
|
|
16101
|
-
};
|
|
16102
|
-
heartbeatMuted = false;
|
|
16103
|
-
}
|
|
16104
|
-
});
|
|
16105
|
-
|
|
16106
16248
|
// src/core/lifecycle-diagnostics.ts
|
|
16107
16249
|
function privateDirectory(directory) {
|
|
16108
|
-
const stat =
|
|
16250
|
+
const stat = import_node_fs33.default.lstatSync(directory);
|
|
16109
16251
|
return stat.isDirectory() && stat.uid === process.getuid?.() && (stat.mode & 63) === 0;
|
|
16110
16252
|
}
|
|
16111
16253
|
function lifecycleDiagnosticsPath(identity2) {
|
|
16112
|
-
return
|
|
16254
|
+
return import_node_path41.default.join(
|
|
16113
16255
|
DEVROUTER_HOME,
|
|
16114
16256
|
"lifecycle-diagnostics",
|
|
16115
|
-
`${(0,
|
|
16257
|
+
`${(0, import_node_crypto21.createHash)("sha256").update(identity2.repoPath).digest("hex")}.json`
|
|
16116
16258
|
);
|
|
16117
16259
|
}
|
|
16118
16260
|
function readReceipt(identity2) {
|
|
16119
16261
|
let descriptor;
|
|
16120
16262
|
try {
|
|
16121
16263
|
const file = lifecycleDiagnosticsPath(identity2);
|
|
16122
|
-
if (!privateDirectory(
|
|
16123
|
-
descriptor =
|
|
16264
|
+
if (!privateDirectory(import_node_path41.default.dirname(file))) return void 0;
|
|
16265
|
+
descriptor = import_node_fs33.default.openSync(
|
|
16124
16266
|
file,
|
|
16125
|
-
|
|
16267
|
+
import_node_fs33.default.constants.O_RDONLY | import_node_fs33.default.constants.O_NOFOLLOW | import_node_fs33.default.constants.O_NONBLOCK
|
|
16126
16268
|
);
|
|
16127
|
-
const stat =
|
|
16269
|
+
const stat = import_node_fs33.default.fstatSync(descriptor);
|
|
16128
16270
|
if (!stat.isFile() || stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0 || stat.size > MAX_RECEIPT_BYTES)
|
|
16129
16271
|
return void 0;
|
|
16130
16272
|
const buffer = Buffer.alloc(MAX_RECEIPT_BYTES + 1);
|
|
16131
|
-
const size =
|
|
16273
|
+
const size = import_node_fs33.default.readSync(descriptor, buffer, 0, buffer.length, 0);
|
|
16132
16274
|
if (size > MAX_RECEIPT_BYTES) return void 0;
|
|
16133
16275
|
const receipt = JSON.parse(buffer.subarray(0, size).toString("utf8"));
|
|
16134
16276
|
const timestamp = (value) => typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
16135
16277
|
const optionalTime = (value) => value === null || timestamp(value);
|
|
16136
|
-
if (receipt.version !== 1 || !(0,
|
|
16278
|
+
if (receipt.version !== 1 || !(0, import_node_util12.isDeepStrictEqual)(receipt.identity, identity2) || typeof receipt.operationId !== "string" || typeof receipt.workerId !== "string" || !timestamp(receipt.startedAtMs) || !timestamp(receipt.updatedAtMs) || receipt.updatedAtMs < receipt.startedAtMs || !(receipt.phase === null || isLifecycleProgressPhase(receipt.phase)) || !optionalTime(receipt.phaseAtMs) || !optionalTime(receipt.lastOutputAtMs) || !optionalTime(receipt.lastProgressAtMs) || !(receipt.buildPackage === null || typeof receipt.buildPackage === "string" && receipt.buildPackage.length <= 128 && /^(?:@[a-zA-Z0-9_.-]+\/)?[a-zA-Z0-9_.-]+$/.test(receipt.buildPackage)) || typeof receipt.cancellationRequested !== "boolean" || typeof receipt.closed !== "boolean" || !Array.isArray(receipt.output) || receipt.output.length > 64)
|
|
16137
16279
|
return void 0;
|
|
16138
16280
|
let bytes2 = 0;
|
|
16139
16281
|
for (const chunk of receipt.output) {
|
|
@@ -16145,7 +16287,7 @@ function readReceipt(identity2) {
|
|
|
16145
16287
|
} catch {
|
|
16146
16288
|
return void 0;
|
|
16147
16289
|
} finally {
|
|
16148
|
-
if (descriptor !== void 0)
|
|
16290
|
+
if (descriptor !== void 0) import_node_fs33.default.closeSync(descriptor);
|
|
16149
16291
|
}
|
|
16150
16292
|
}
|
|
16151
16293
|
function readLifecycleDiagnostics(identity2, now = Date.now()) {
|
|
@@ -16153,7 +16295,7 @@ function readLifecycleDiagnostics(identity2, now = Date.now()) {
|
|
|
16153
16295
|
const before = readReliabilityOperation(identity2);
|
|
16154
16296
|
const receipt = readReceipt(identity2);
|
|
16155
16297
|
const after = readReliabilityOperation(identity2);
|
|
16156
|
-
if (!before || !after || !receipt || before.revision !== after.revision || !(0,
|
|
16298
|
+
if (!before || !after || !receipt || before.revision !== after.revision || !(0, import_node_util12.isDeepStrictEqual)(before, after) || !(0, import_node_util12.isDeepStrictEqual)(receipt.fence, reliabilityFence(after.state)) || after.state.operation?.id !== receipt.operationId || after.state.operation.kind !== "ensure" || after.worker !== null && after.worker.id !== receipt.workerId || !receipt.closed && !after.worker || now < receipt.updatedAtMs || [receipt.phaseAtMs, receipt.lastOutputAtMs, receipt.lastProgressAtMs].some(
|
|
16157
16299
|
(time) => time !== null && (time < receipt.startedAtMs || time > receipt.updatedAtMs)
|
|
16158
16300
|
))
|
|
16159
16301
|
return void 0;
|
|
@@ -16183,14 +16325,14 @@ function readLifecycleDiagnostics(identity2, now = Date.now()) {
|
|
|
16183
16325
|
return void 0;
|
|
16184
16326
|
}
|
|
16185
16327
|
}
|
|
16186
|
-
var
|
|
16328
|
+
var import_node_crypto21, import_node_fs33, import_node_path41, import_node_util12, MAX_TAIL_BYTES, MAX_RECEIPT_BYTES, PACKAGE_TASK, LifecycleDiagnosticRecorder;
|
|
16187
16329
|
var init_lifecycle_diagnostics = __esm({
|
|
16188
16330
|
"src/core/lifecycle-diagnostics.ts"() {
|
|
16189
16331
|
"use strict";
|
|
16190
|
-
|
|
16191
|
-
|
|
16192
|
-
|
|
16193
|
-
|
|
16332
|
+
import_node_crypto21 = require("crypto");
|
|
16333
|
+
import_node_fs33 = __toESM(require("fs"));
|
|
16334
|
+
import_node_path41 = __toESM(require("path"));
|
|
16335
|
+
import_node_util12 = require("util");
|
|
16194
16336
|
init_atomic_file();
|
|
16195
16337
|
init_lifecycle_progress();
|
|
16196
16338
|
init_reliability_contract();
|
|
@@ -16242,7 +16384,7 @@ var init_lifecycle_diagnostics = __esm({
|
|
|
16242
16384
|
const lines = text6.split(/[\r\n]/);
|
|
16243
16385
|
this.fragments[stream] = (lines.pop() ?? "").slice(-4096);
|
|
16244
16386
|
for (const raw of lines) {
|
|
16245
|
-
const line = (0,
|
|
16387
|
+
const line = (0, import_node_util12.stripVTControlCharacters)(raw).trim();
|
|
16246
16388
|
if (!line || line === this.lastLine || [...line].some(
|
|
16247
16389
|
(character) => character.charCodeAt(0) < 32 || character.charCodeAt(0) === 127
|
|
16248
16390
|
) || line.startsWith('{"type":"lifecycle-progress"'))
|
|
@@ -16271,7 +16413,7 @@ var init_lifecycle_diagnostics = __esm({
|
|
|
16271
16413
|
this.pending = void 0;
|
|
16272
16414
|
try {
|
|
16273
16415
|
const record6 = readReliabilityOperation(this.request.identity);
|
|
16274
|
-
if (!record6 || record6.state.operation?.id !== this.request.operationId || !(0,
|
|
16416
|
+
if (!record6 || record6.state.operation?.id !== this.request.operationId || !(0, import_node_util12.isDeepStrictEqual)(reliabilityFence(record6.state), this.request.fence) || record6.worker && record6.worker.id !== this.request.workerId)
|
|
16275
16417
|
return;
|
|
16276
16418
|
let remaining = MAX_TAIL_BYTES;
|
|
16277
16419
|
const chunks = [];
|
|
@@ -16284,8 +16426,8 @@ var init_lifecycle_diagnostics = __esm({
|
|
|
16284
16426
|
this.receipt.output = chunks;
|
|
16285
16427
|
this.receipt.updatedAtMs = Date.now();
|
|
16286
16428
|
const file = lifecycleDiagnosticsPath(this.request.identity);
|
|
16287
|
-
|
|
16288
|
-
if (!privateDirectory(
|
|
16429
|
+
import_node_fs33.default.mkdirSync(import_node_path41.default.dirname(file), { recursive: true, mode: 448 });
|
|
16430
|
+
if (!privateDirectory(import_node_path41.default.dirname(file))) return;
|
|
16289
16431
|
writeFileAtomically(file, `${JSON.stringify(this.receipt)}
|
|
16290
16432
|
`);
|
|
16291
16433
|
} catch {
|
|
@@ -16318,11 +16460,11 @@ function workerGroupAbsent(pid) {
|
|
|
16318
16460
|
if (process.platform !== "linux") return false;
|
|
16319
16461
|
let observedZombie = false;
|
|
16320
16462
|
try {
|
|
16321
|
-
for (const entry of
|
|
16463
|
+
for (const entry of import_node_fs34.default.readdirSync("/proc")) {
|
|
16322
16464
|
if (!/^\d+$/.test(entry)) continue;
|
|
16323
16465
|
let stat;
|
|
16324
16466
|
try {
|
|
16325
|
-
stat =
|
|
16467
|
+
stat = import_node_fs34.default.readFileSync(`/proc/${entry}/stat`, "utf8");
|
|
16326
16468
|
} catch (error) {
|
|
16327
16469
|
if (error.code === "ENOENT") continue;
|
|
16328
16470
|
return false;
|
|
@@ -16353,10 +16495,10 @@ async function runLifecycleWorker(request2, supervision, beforeAdmission) {
|
|
|
16353
16495
|
throw new Error("Lifecycle invocation was cancelled before dispatch.");
|
|
16354
16496
|
if (process.platform === "win32")
|
|
16355
16497
|
throw new Error("Lifecycle workers require POSIX process-group ownership.");
|
|
16356
|
-
const workerPath =
|
|
16357
|
-
if (!
|
|
16498
|
+
const workerPath = import_node_path42.default.join(__dirname, "devrouter-lifecycle-worker.js");
|
|
16499
|
+
if (!import_node_fs34.default.existsSync(workerPath))
|
|
16358
16500
|
throw new Error("The packaged lifecycle worker is missing; rebuild the CLI.");
|
|
16359
|
-
const child = (0,
|
|
16501
|
+
const child = (0, import_node_child_process23.fork)(workerPath, [], {
|
|
16360
16502
|
detached: true,
|
|
16361
16503
|
stdio: supervision ? ["ignore", "pipe", "pipe", "ipc"] : request2.kind === "ensure" ? ["inherit", "pipe", "pipe", "ipc"] : ["inherit", "inherit", "inherit", "ipc"],
|
|
16362
16504
|
execArgv: []
|
|
@@ -16645,16 +16787,16 @@ async function runLifecycleWorker(request2, supervision, beforeAdmission) {
|
|
|
16645
16787
|
}
|
|
16646
16788
|
}
|
|
16647
16789
|
function newLifecycleIds() {
|
|
16648
|
-
return { requestId: (0,
|
|
16790
|
+
return { requestId: (0, import_node_crypto22.randomUUID)(), operationId: (0, import_node_crypto22.randomUUID)(), workerId: (0, import_node_crypto22.randomUUID)() };
|
|
16649
16791
|
}
|
|
16650
|
-
var
|
|
16792
|
+
var import_node_child_process23, import_node_crypto22, import_node_fs34, import_node_path42, OUTPUT_BUFFER_LIMIT, DEFAULT_OUTPUT_PAGE_BYTES, LifecycleOutput, LifecycleWorkerAdmissionBusyError;
|
|
16651
16793
|
var init_reliability_worker = __esm({
|
|
16652
16794
|
"src/core/reliability-worker.ts"() {
|
|
16653
16795
|
"use strict";
|
|
16654
|
-
|
|
16655
|
-
|
|
16656
|
-
|
|
16657
|
-
|
|
16796
|
+
import_node_child_process23 = require("child_process");
|
|
16797
|
+
import_node_crypto22 = require("crypto");
|
|
16798
|
+
import_node_fs34 = __toESM(require("fs"));
|
|
16799
|
+
import_node_path42 = __toESM(require("path"));
|
|
16658
16800
|
init_file_lock();
|
|
16659
16801
|
init_lifecycle_diagnostics();
|
|
16660
16802
|
init_lifecycle_progress();
|
|
@@ -16773,7 +16915,7 @@ var init_reliability_worker = __esm({
|
|
|
16773
16915
|
|
|
16774
16916
|
// src/core/devpod-mutation.ts
|
|
16775
16917
|
function withMutationLock2(activity, target, operation) {
|
|
16776
|
-
|
|
16918
|
+
import_node_fs35.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
|
|
16777
16919
|
return withFileLockSync(
|
|
16778
16920
|
DEVPOD_MUTATION_LOCK_FILE,
|
|
16779
16921
|
{
|
|
@@ -16793,7 +16935,7 @@ function runDevpodAction(action2, devpodId, force = false, repoPath) {
|
|
|
16793
16935
|
const args = action2 === "delete" ? [action2, devpodId, ...force ? ["--force"] : [], "--ignore-not-found"] : [action2, devpodId];
|
|
16794
16936
|
claimLifecycleEffect();
|
|
16795
16937
|
const binding = repoPath ? networkProviderEffectOptions("devpod", devpodId, repoPath) : { args: [] };
|
|
16796
|
-
const result = (0,
|
|
16938
|
+
const result = (0, import_node_child_process24.spawnSync)("devpod", [...args, ...binding.args], {
|
|
16797
16939
|
encoding: "utf-8",
|
|
16798
16940
|
...binding.env ? { env: binding.env } : {}
|
|
16799
16941
|
});
|
|
@@ -16863,13 +17005,13 @@ function deleteOwnedDevpodWorkspace(devpodId, worktreePath) {
|
|
|
16863
17005
|
resetWorkspaceRuntimeCaches();
|
|
16864
17006
|
return result;
|
|
16865
17007
|
}
|
|
16866
|
-
var
|
|
17008
|
+
var import_node_child_process24, import_node_fs35, import_node_path43, DEVPOD_MUTATION_LOCK_FILE, DEVPOD_MUTATION_WAIT_MS;
|
|
16867
17009
|
var init_devpod_mutation = __esm({
|
|
16868
17010
|
"src/core/devpod-mutation.ts"() {
|
|
16869
17011
|
"use strict";
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
17012
|
+
import_node_child_process24 = require("child_process");
|
|
17013
|
+
import_node_fs35 = __toESM(require("fs"));
|
|
17014
|
+
import_node_path43 = __toESM(require("path"));
|
|
16873
17015
|
init_devpod_workspaces();
|
|
16874
17016
|
init_devsy_mutation();
|
|
16875
17017
|
init_file_lock();
|
|
@@ -16878,7 +17020,7 @@ var init_devpod_mutation = __esm({
|
|
|
16878
17020
|
init_reliability_context();
|
|
16879
17021
|
init_router();
|
|
16880
17022
|
init_workspace_runtime();
|
|
16881
|
-
DEVPOD_MUTATION_LOCK_FILE =
|
|
17023
|
+
DEVPOD_MUTATION_LOCK_FILE = import_node_path43.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
|
|
16882
17024
|
DEVPOD_MUTATION_WAIT_MS = 18e5;
|
|
16883
17025
|
}
|
|
16884
17026
|
});
|
|
@@ -16979,7 +17121,7 @@ function hostPortBindingsConflict(desired, holder) {
|
|
|
16979
17121
|
(desired.hostIp === null || holder.hostIp === null || desired.hostIp === holder.hostIp);
|
|
16980
17122
|
}
|
|
16981
17123
|
function runDocker(args) {
|
|
16982
|
-
const result = (0,
|
|
17124
|
+
const result = (0, import_node_child_process25.spawnSync)("docker", args, {
|
|
16983
17125
|
...networkDockerOptions(),
|
|
16984
17126
|
encoding: "utf-8",
|
|
16985
17127
|
timeout: DOCKER_TIMEOUT_MS,
|
|
@@ -17049,7 +17191,7 @@ function listHolderSnapshots() {
|
|
|
17049
17191
|
}
|
|
17050
17192
|
function renderManagedComposeModel(plan, workspace) {
|
|
17051
17193
|
const fileArgs = plan.composeFiles.flatMap((file) => ["-f", file]);
|
|
17052
|
-
const result = (0,
|
|
17194
|
+
const result = (0, import_node_child_process25.spawnSync)(
|
|
17053
17195
|
"docker",
|
|
17054
17196
|
[
|
|
17055
17197
|
"compose",
|
|
@@ -17084,8 +17226,8 @@ function renderManagedComposeModel(plan, workspace) {
|
|
|
17084
17226
|
}
|
|
17085
17227
|
}
|
|
17086
17228
|
function attributeHolderWorktree(workingDir) {
|
|
17087
|
-
if (
|
|
17088
|
-
return comparableWorkspacePath(
|
|
17229
|
+
if (import_node_path44.default.basename(workingDir) !== ".devcontainer") return void 0;
|
|
17230
|
+
return comparableWorkspacePath(import_node_path44.default.dirname(workingDir));
|
|
17089
17231
|
}
|
|
17090
17232
|
function holderAttribution(holder, repoPath) {
|
|
17091
17233
|
const attribution = {};
|
|
@@ -17120,7 +17262,7 @@ function detectHostPortClaimConflicts(options) {
|
|
|
17120
17262
|
);
|
|
17121
17263
|
if (desired.length === 0) return [];
|
|
17122
17264
|
const holders = listHolderSnapshots();
|
|
17123
|
-
const devcontainerDir =
|
|
17265
|
+
const devcontainerDir = import_node_path44.default.join(options.repoPath, ".devcontainer");
|
|
17124
17266
|
const conflicts = [];
|
|
17125
17267
|
for (const binding of desired) {
|
|
17126
17268
|
for (const holder of holders) {
|
|
@@ -17142,12 +17284,12 @@ function detectHostPortClaimConflicts(options) {
|
|
|
17142
17284
|
}
|
|
17143
17285
|
return conflicts;
|
|
17144
17286
|
}
|
|
17145
|
-
var
|
|
17287
|
+
var import_node_child_process25, 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;
|
|
17146
17288
|
var init_host_port_claims = __esm({
|
|
17147
17289
|
"src/core/host-port-claims.ts"() {
|
|
17148
17290
|
"use strict";
|
|
17149
|
-
|
|
17150
|
-
|
|
17291
|
+
import_node_child_process25 = require("child_process");
|
|
17292
|
+
import_node_path44 = __toESM(require("path"));
|
|
17151
17293
|
init_devcontainer_profile();
|
|
17152
17294
|
init_network_effect_scope();
|
|
17153
17295
|
init_router();
|
|
@@ -17189,7 +17331,7 @@ function probeHttpRoute(host, options = {}) {
|
|
|
17189
17331
|
args.push("--cacert", CERT_FILE);
|
|
17190
17332
|
}
|
|
17191
17333
|
args.push(url);
|
|
17192
|
-
const result = (0,
|
|
17334
|
+
const result = (0, import_node_child_process26.spawnSync)("curl", args, { encoding: "utf-8" });
|
|
17193
17335
|
const stdout = result.stdout?.trim() ?? "";
|
|
17194
17336
|
const status = /^\d{3}$/.test(stdout) ? Number(stdout) : void 0;
|
|
17195
17337
|
const ok = result.status === 0 && status !== void 0 && status >= 100 && status < 500;
|
|
@@ -17224,7 +17366,7 @@ function probeHttpReadinessSync(host, readiness, maxTimeSeconds, repoPath) {
|
|
|
17224
17366
|
}
|
|
17225
17367
|
let result;
|
|
17226
17368
|
try {
|
|
17227
|
-
result = (0,
|
|
17369
|
+
result = (0, import_node_child_process26.spawnSync)("curl", args, {
|
|
17228
17370
|
encoding: "utf-8",
|
|
17229
17371
|
maxBuffer: CONTRACT_MAX_BUFFER,
|
|
17230
17372
|
timeout: Math.ceil(parentTimeoutMs)
|
|
@@ -17306,11 +17448,11 @@ function transportFailure() {
|
|
|
17306
17448
|
classification: "transport"
|
|
17307
17449
|
};
|
|
17308
17450
|
}
|
|
17309
|
-
var
|
|
17451
|
+
var import_node_child_process26, DEFAULT_MAX_TIME_SECONDS, CONTROLLER_CURL_MAX_TIME_SECONDS, PARENT_TIMEOUT_PADDING_MS, CONTRACT_MAX_BUFFER, MIME_TOKEN_RE2;
|
|
17310
17452
|
var init_http_route_probe = __esm({
|
|
17311
17453
|
"src/core/http-route-probe.ts"() {
|
|
17312
17454
|
"use strict";
|
|
17313
|
-
|
|
17455
|
+
import_node_child_process26 = require("child_process");
|
|
17314
17456
|
init_router();
|
|
17315
17457
|
init_tls();
|
|
17316
17458
|
DEFAULT_MAX_TIME_SECONDS = 5;
|
|
@@ -17322,12 +17464,12 @@ var init_http_route_probe = __esm({
|
|
|
17322
17464
|
});
|
|
17323
17465
|
|
|
17324
17466
|
// src/core/managed-host-preparation.ts
|
|
17325
|
-
var
|
|
17467
|
+
var import_node_child_process27, import_node_fs36;
|
|
17326
17468
|
var init_managed_host_preparation = __esm({
|
|
17327
17469
|
"src/core/managed-host-preparation.ts"() {
|
|
17328
17470
|
"use strict";
|
|
17329
|
-
|
|
17330
|
-
|
|
17471
|
+
import_node_child_process27 = require("child_process");
|
|
17472
|
+
import_node_fs36 = __toESM(require("fs"));
|
|
17331
17473
|
init_repo_config();
|
|
17332
17474
|
}
|
|
17333
17475
|
});
|
|
@@ -17452,7 +17594,7 @@ function classifyManagedMountNesting(configured, effectiveDestinations, containe
|
|
|
17452
17594
|
};
|
|
17453
17595
|
}
|
|
17454
17596
|
function readContainerMountinfo(containerId, options) {
|
|
17455
|
-
const result = (0,
|
|
17597
|
+
const result = (0, import_node_child_process28.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
|
|
17456
17598
|
encoding: "utf-8",
|
|
17457
17599
|
timeout: options.timeoutMs ?? 5e3,
|
|
17458
17600
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -17467,11 +17609,11 @@ function observeManagedMountNesting(container, options = {}) {
|
|
|
17467
17609
|
const effective = destinations.some((_destination, index) => isNestedIndex(destinations, index)) ? readContainerMountinfo(container.id, options) : null;
|
|
17468
17610
|
return classifyManagedMountNesting(container.mounts, effective, container.id);
|
|
17469
17611
|
}
|
|
17470
|
-
var
|
|
17612
|
+
var import_node_child_process28, NESTED_MOUNT_REASON, UNREADABLE_MOUNT_REASON;
|
|
17471
17613
|
var init_managed_mount_nesting = __esm({
|
|
17472
17614
|
"src/core/managed-mount-nesting.ts"() {
|
|
17473
17615
|
"use strict";
|
|
17474
|
-
|
|
17616
|
+
import_node_child_process28 = require("child_process");
|
|
17475
17617
|
init_network_effect_scope();
|
|
17476
17618
|
NESTED_MOUNT_REASON = "no configured mount is nested inside another configured mount";
|
|
17477
17619
|
UNREADABLE_MOUNT_REASON = "the container's own mount table could not be read";
|
|
@@ -17489,7 +17631,11 @@ function reliabilityRecovery(reason2, repoPath, variant) {
|
|
|
17489
17631
|
switch (reason2) {
|
|
17490
17632
|
case "stop-incomplete":
|
|
17491
17633
|
case "operation-unknown":
|
|
17492
|
-
return [
|
|
17634
|
+
return [
|
|
17635
|
+
`Run: devrouter stop ${checkout}`,
|
|
17636
|
+
"Verify the repository startup hooks preserve retained data and startup is authorized before continuing.",
|
|
17637
|
+
`Run: devrouter ensure ${checkout}${variantOption}`
|
|
17638
|
+
];
|
|
17493
17639
|
case "start-refused":
|
|
17494
17640
|
return [
|
|
17495
17641
|
`Run: devrouter doctor --repo ${checkout} to read the refused fixed host-port claim and its holder`,
|
|
@@ -18029,7 +18175,7 @@ function readDocker(endpoint, args, timeoutMs) {
|
|
|
18029
18175
|
const env = { ...process.env };
|
|
18030
18176
|
delete env.DOCKER_CONTEXT;
|
|
18031
18177
|
delete env.DOCKER_HOST;
|
|
18032
|
-
const result = (0,
|
|
18178
|
+
const result = (0, import_node_child_process29.spawnSync)("docker", ["--host", endpoint, ...args], {
|
|
18033
18179
|
env,
|
|
18034
18180
|
encoding: "utf-8",
|
|
18035
18181
|
timeout: timeoutMs,
|
|
@@ -18191,11 +18337,11 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
|
|
|
18191
18337
|
}
|
|
18192
18338
|
return result;
|
|
18193
18339
|
}
|
|
18194
|
-
var
|
|
18340
|
+
var import_node_child_process29, NetworkInventoryError, MAX_IDS, MAX_OUTPUT_BYTES, FULL_ID, NETWORK_TEMPLATE, CONTAINER_TEMPLATE;
|
|
18195
18341
|
var init_network_inventory = __esm({
|
|
18196
18342
|
"src/core/network-inventory.ts"() {
|
|
18197
18343
|
"use strict";
|
|
18198
|
-
|
|
18344
|
+
import_node_child_process29 = require("child_process");
|
|
18199
18345
|
init_devpod_environment();
|
|
18200
18346
|
NetworkInventoryError = class extends Error {
|
|
18201
18347
|
};
|
|
@@ -18523,26 +18669,26 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18523
18669
|
try {
|
|
18524
18670
|
if (!endpoint.startsWith("unix:///")) return false;
|
|
18525
18671
|
const socket = endpoint.slice("unix://".length);
|
|
18526
|
-
const table =
|
|
18672
|
+
const table = import_node_fs37.default.readFileSync(import_node_path45.default.join(procRoot, "net/unix"), "utf8");
|
|
18527
18673
|
if (Buffer.byteLength(table) > 1024 * 1024) return false;
|
|
18528
18674
|
const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
|
|
18529
18675
|
if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
|
|
18530
18676
|
const inode = `socket:[${rows2[0][6]}]`;
|
|
18531
|
-
const ownNamespace =
|
|
18532
|
-
const pids =
|
|
18677
|
+
const ownNamespace = import_node_fs37.default.readlinkSync(import_node_path45.default.join(procRoot, "self/ns/net"));
|
|
18678
|
+
const pids = import_node_fs37.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
|
|
18533
18679
|
if (pids.length > 4096) return false;
|
|
18534
18680
|
for (const pid of pids) {
|
|
18535
18681
|
if (Date.now() > deadline) return false;
|
|
18536
18682
|
try {
|
|
18537
|
-
const root =
|
|
18538
|
-
if (
|
|
18539
|
-
if (
|
|
18540
|
-
const descriptors =
|
|
18683
|
+
const root = import_node_path45.default.join(procRoot, pid);
|
|
18684
|
+
if (import_node_path45.default.basename(import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "exe"))) !== "dockerd") continue;
|
|
18685
|
+
if (import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "ns/net")) !== ownNamespace) continue;
|
|
18686
|
+
const descriptors = import_node_fs37.default.readdirSync(import_node_path45.default.join(root, "fd"));
|
|
18541
18687
|
if (descriptors.length > 4096) continue;
|
|
18542
18688
|
if (descriptors.some((fd) => {
|
|
18543
18689
|
if (Date.now() > deadline) return false;
|
|
18544
18690
|
try {
|
|
18545
|
-
return
|
|
18691
|
+
return import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "fd", fd)) === inode;
|
|
18546
18692
|
} catch {
|
|
18547
18693
|
return false;
|
|
18548
18694
|
}
|
|
@@ -18556,12 +18702,12 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18556
18702
|
}
|
|
18557
18703
|
return false;
|
|
18558
18704
|
}
|
|
18559
|
-
var
|
|
18705
|
+
var import_node_fs37, import_node_path45;
|
|
18560
18706
|
var init_network_local_daemon = __esm({
|
|
18561
18707
|
"src/core/network-local-daemon.ts"() {
|
|
18562
18708
|
"use strict";
|
|
18563
|
-
|
|
18564
|
-
|
|
18709
|
+
import_node_fs37 = __toESM(require("fs"));
|
|
18710
|
+
import_node_path45 = __toESM(require("path"));
|
|
18565
18711
|
}
|
|
18566
18712
|
});
|
|
18567
18713
|
|
|
@@ -18589,7 +18735,7 @@ function parseLinuxNetworkRoutes(output2) {
|
|
|
18589
18735
|
function collectNetworkRoutes(options) {
|
|
18590
18736
|
if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
|
|
18591
18737
|
return { status: "unknown", routes: [] };
|
|
18592
|
-
const result = (0,
|
|
18738
|
+
const result = (0, import_node_child_process30.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
|
|
18593
18739
|
encoding: "utf8",
|
|
18594
18740
|
timeout: 5e3,
|
|
18595
18741
|
maxBuffer: 1024 * 1024
|
|
@@ -18597,11 +18743,11 @@ function collectNetworkRoutes(options) {
|
|
|
18597
18743
|
if (result.error || result.status !== 0) return { status: "unknown", routes: [] };
|
|
18598
18744
|
return parseLinuxNetworkRoutes(result.stdout);
|
|
18599
18745
|
}
|
|
18600
|
-
var
|
|
18746
|
+
var import_node_child_process30, import_node_net3;
|
|
18601
18747
|
var init_network_routes = __esm({
|
|
18602
18748
|
"src/core/network-routes.ts"() {
|
|
18603
18749
|
"use strict";
|
|
18604
|
-
|
|
18750
|
+
import_node_child_process30 = require("child_process");
|
|
18605
18751
|
import_node_net3 = require("net");
|
|
18606
18752
|
init_network_capacity();
|
|
18607
18753
|
init_network_local_daemon();
|
|
@@ -18769,11 +18915,11 @@ function extendDockerComposeFile(nativeConfig, overlayPath) {
|
|
|
18769
18915
|
const config = { ...nativeConfig, dockerComposeFile };
|
|
18770
18916
|
return { status: "ready", config, reasons: [] };
|
|
18771
18917
|
}
|
|
18772
|
-
var
|
|
18918
|
+
var import_node_crypto23;
|
|
18773
18919
|
var init_network_compose = __esm({
|
|
18774
18920
|
"src/core/network-compose.ts"() {
|
|
18775
18921
|
"use strict";
|
|
18776
|
-
|
|
18922
|
+
import_node_crypto23 = require("crypto");
|
|
18777
18923
|
}
|
|
18778
18924
|
});
|
|
18779
18925
|
|
|
@@ -18781,8 +18927,8 @@ var init_network_compose = __esm({
|
|
|
18781
18927
|
function prepareNetworkComposeFiles(plan, subnet) {
|
|
18782
18928
|
const overlay = deriveComposeNetworkOverlay(subnet);
|
|
18783
18929
|
if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
|
|
18784
|
-
const overlayPath =
|
|
18785
|
-
const ignored = (0,
|
|
18930
|
+
const overlayPath = import_node_path46.default.join(plan.composeDirectory, OVERLAY);
|
|
18931
|
+
const ignored = (0, import_node_child_process31.spawnSync)("git", [
|
|
18786
18932
|
"-C",
|
|
18787
18933
|
plan.composeDirectory,
|
|
18788
18934
|
"check-ignore",
|
|
@@ -18794,11 +18940,11 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18794
18940
|
if (ignored.status !== 0)
|
|
18795
18941
|
throw new Error("Generated network overlay must be ignored before allocation.");
|
|
18796
18942
|
const bytes2 = `${MARKER}
|
|
18797
|
-
${
|
|
18943
|
+
${import_yaml5.default.stringify(overlay.overlay)}`;
|
|
18798
18944
|
const assertOwnership = () => {
|
|
18799
|
-
if (!
|
|
18800
|
-
const stat =
|
|
18801
|
-
if (!stat.isFile() || stat.size > MAX_BYTES3 ||
|
|
18945
|
+
if (!import_node_fs38.default.existsSync(overlayPath)) return;
|
|
18946
|
+
const stat = import_node_fs38.default.lstatSync(overlayPath);
|
|
18947
|
+
if (!stat.isFile() || stat.size > MAX_BYTES3 || import_node_fs38.default.readFileSync(overlayPath, "utf8") !== bytes2)
|
|
18802
18948
|
throw new Error("Retained network overlay changed; repair is required.");
|
|
18803
18949
|
};
|
|
18804
18950
|
assertOwnership();
|
|
@@ -18812,7 +18958,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18812
18958
|
...plan,
|
|
18813
18959
|
contents,
|
|
18814
18960
|
composeFiles: [...plan.composeFiles, overlayPath],
|
|
18815
|
-
effectiveConfigSha256: (0,
|
|
18961
|
+
effectiveConfigSha256: (0, import_node_crypto24.createHash)("sha256").update(contents).digest("hex")
|
|
18816
18962
|
};
|
|
18817
18963
|
return {
|
|
18818
18964
|
plan: result,
|
|
@@ -18822,15 +18968,15 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18822
18968
|
}
|
|
18823
18969
|
};
|
|
18824
18970
|
}
|
|
18825
|
-
var
|
|
18971
|
+
var import_node_child_process31, import_node_crypto24, import_node_fs38, import_node_path46, import_yaml5, OVERLAY, MARKER, MAX_BYTES3;
|
|
18826
18972
|
var init_network_compose_files = __esm({
|
|
18827
18973
|
"src/core/network-compose-files.ts"() {
|
|
18828
18974
|
"use strict";
|
|
18829
|
-
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18975
|
+
import_node_child_process31 = require("child_process");
|
|
18976
|
+
import_node_crypto24 = require("crypto");
|
|
18977
|
+
import_node_fs38 = __toESM(require("fs"));
|
|
18978
|
+
import_node_path46 = __toESM(require("path"));
|
|
18979
|
+
import_yaml5 = __toESM(require("yaml"));
|
|
18834
18980
|
init_atomic_file();
|
|
18835
18981
|
init_devcontainer_profile();
|
|
18836
18982
|
init_network_compose();
|
|
@@ -18841,11 +18987,11 @@ var init_network_compose_files = __esm({
|
|
|
18841
18987
|
});
|
|
18842
18988
|
|
|
18843
18989
|
// src/core/network-connected-route.ts
|
|
18844
|
-
var
|
|
18990
|
+
var import_node_child_process32;
|
|
18845
18991
|
var init_network_connected_route = __esm({
|
|
18846
18992
|
"src/core/network-connected-route.ts"() {
|
|
18847
18993
|
"use strict";
|
|
18848
|
-
|
|
18994
|
+
import_node_child_process32 = require("child_process");
|
|
18849
18995
|
init_network_capacity();
|
|
18850
18996
|
}
|
|
18851
18997
|
});
|
|
@@ -18861,11 +19007,11 @@ var init_network_lifecycle = __esm({
|
|
|
18861
19007
|
});
|
|
18862
19008
|
|
|
18863
19009
|
// src/core/network-managed.ts
|
|
18864
|
-
var
|
|
19010
|
+
var import_node_crypto25;
|
|
18865
19011
|
var init_network_managed = __esm({
|
|
18866
19012
|
"src/core/network-managed.ts"() {
|
|
18867
19013
|
"use strict";
|
|
18868
|
-
|
|
19014
|
+
import_node_crypto25 = require("crypto");
|
|
18869
19015
|
init_devpod_environment();
|
|
18870
19016
|
init_network_capacity();
|
|
18871
19017
|
init_network_claim_lookup();
|
|
@@ -18935,13 +19081,13 @@ function resolveLinkedTarget(repoPath) {
|
|
|
18935
19081
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
18936
19082
|
};
|
|
18937
19083
|
}
|
|
18938
|
-
var
|
|
19084
|
+
var import_node_child_process33, import_node_fs39, import_node_path47;
|
|
18939
19085
|
var init_workspace_ensure = __esm({
|
|
18940
19086
|
"src/core/workspace-ensure.ts"() {
|
|
18941
19087
|
"use strict";
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
19088
|
+
import_node_child_process33 = require("child_process");
|
|
19089
|
+
import_node_fs39 = __toESM(require("fs"));
|
|
19090
|
+
import_node_path47 = __toESM(require("path"));
|
|
18945
19091
|
init_devcontainer_profile();
|
|
18946
19092
|
init_devpod_environment();
|
|
18947
19093
|
init_devpod_mutation();
|
|
@@ -18952,6 +19098,7 @@ var init_workspace_ensure = __esm({
|
|
|
18952
19098
|
init_host_routes();
|
|
18953
19099
|
init_http_route_probe();
|
|
18954
19100
|
init_lifecycle_progress();
|
|
19101
|
+
init_managed_fresh_bootstrap();
|
|
18955
19102
|
init_managed_host_ports();
|
|
18956
19103
|
init_managed_host_preparation();
|
|
18957
19104
|
init_managed_post_start();
|
|
@@ -19057,6 +19204,9 @@ function prepareManagedLifecycleOperation(input2) {
|
|
|
19057
19204
|
throw new Error("Invalid managed operation command.");
|
|
19058
19205
|
if (Buffer.byteLength(JSON.stringify(input2)) > 32768)
|
|
19059
19206
|
throw new Error("Managed operation input exceeds its byte limit.");
|
|
19207
|
+
if (input2.initializeNew && input2.kind !== "ensure")
|
|
19208
|
+
throw new Error("Initialization intent is valid only for an ensure operation.");
|
|
19209
|
+
if (input2.kind === "ensure") assertFreshBootstrapRequest(input2.identity, input2);
|
|
19060
19210
|
const ids2 = newLifecycleIds();
|
|
19061
19211
|
return updateReliabilityOperation(input2.identity, (record6) => {
|
|
19062
19212
|
const retained = readManagedRuntimeState(
|
|
@@ -19105,13 +19255,17 @@ function prepareManagedLifecycleOperation(input2) {
|
|
|
19105
19255
|
repoPath: input2.identity.repoPath,
|
|
19106
19256
|
identity: { ...input2.identity },
|
|
19107
19257
|
fence: reliabilityFence(record6.state),
|
|
19108
|
-
options: {
|
|
19258
|
+
options: {
|
|
19259
|
+
profile: input2.profile,
|
|
19260
|
+
quiet: true,
|
|
19261
|
+
...input2.initializeNew ? { initializeNew: true } : {}
|
|
19262
|
+
},
|
|
19109
19263
|
...input2.command ? { command: [...input2.command] } : {}
|
|
19110
19264
|
}
|
|
19111
19265
|
};
|
|
19112
19266
|
});
|
|
19113
19267
|
}
|
|
19114
|
-
function assertCurrentCapacityController(expected, directory =
|
|
19268
|
+
function assertCurrentCapacityController(expected, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller")) {
|
|
19115
19269
|
const current = new ControllerStore(directory).read();
|
|
19116
19270
|
if (!expected || current?.store !== expected.store || current.epoch !== expected.epoch)
|
|
19117
19271
|
throw new Error("Capacity controller incarnation changed.");
|
|
@@ -19282,7 +19436,7 @@ function withdrawUnstartedLifecycleStop(input2) {
|
|
|
19282
19436
|
if (record6.worker || record6.stopWorkStarted) return false;
|
|
19283
19437
|
if (state.desired !== "stopped-by-user" || state.phase !== "stopping") return false;
|
|
19284
19438
|
if (state.stopProof.workloadsStopped || state.stopProof.routesRemoved) return false;
|
|
19285
|
-
if (!(0,
|
|
19439
|
+
if (!(0, import_node_util13.isDeepStrictEqual)(state.operation, intent.recordedOperation)) return false;
|
|
19286
19440
|
const prior = intent.prior;
|
|
19287
19441
|
state.intentRevision = prior.intentRevision;
|
|
19288
19442
|
state.observationsAfterMs = prior.observationsAfterMs;
|
|
@@ -19360,7 +19514,7 @@ function prepareResumeLifecycleOperation(input2) {
|
|
|
19360
19514
|
});
|
|
19361
19515
|
}
|
|
19362
19516
|
function settlePreparedLifecycleCapacity(input2) {
|
|
19363
|
-
const directory = input2.directory ??
|
|
19517
|
+
const directory = input2.directory ?? import_node_path48.default.join(DEVROUTER_HOME, "controller");
|
|
19364
19518
|
const store = createLifecycleCapacityStore(directory);
|
|
19365
19519
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
19366
19520
|
const snapshot = store.read();
|
|
@@ -19388,21 +19542,21 @@ function settlePreparedLifecycleCapacity(input2) {
|
|
|
19388
19542
|
reservationId: binding.reservationId,
|
|
19389
19543
|
policyRevision: binding.policyRevision
|
|
19390
19544
|
};
|
|
19391
|
-
if (operation.kind === "exec" && !(0,
|
|
19545
|
+
if (operation.kind === "exec" && !(0, import_node_util13.isDeepStrictEqual)(target.totals, binding.execSteady?.totals))
|
|
19392
19546
|
return null;
|
|
19393
19547
|
const retained = snapshot.reservations.find(
|
|
19394
19548
|
(entry) => entry.environmentId === target.environmentId
|
|
19395
19549
|
);
|
|
19396
19550
|
if (!retained || retained.reservationId !== target.reservationId || retained.operationId !== target.operationId || retained.policyRevision !== target.policyRevision)
|
|
19397
19551
|
return null;
|
|
19398
|
-
if (!record6.phaseSettlement && (0,
|
|
19552
|
+
if (!record6.phaseSettlement && (0, import_node_util13.isDeepStrictEqual)(retained, target)) return null;
|
|
19399
19553
|
const marker = {
|
|
19400
19554
|
id: binding.reservationId,
|
|
19401
19555
|
fence: { ...proof.fence },
|
|
19402
19556
|
target,
|
|
19403
19557
|
estimatesDigest: input2.enrollment.estimatesDigest
|
|
19404
19558
|
};
|
|
19405
|
-
if (record6.phaseSettlement && !(0,
|
|
19559
|
+
if (record6.phaseSettlement && !(0, import_node_util13.isDeepStrictEqual)(record6.phaseSettlement, marker))
|
|
19406
19560
|
throw new Error("Capacity phase settlement proof changed.");
|
|
19407
19561
|
binding.validUntilMs = 0;
|
|
19408
19562
|
record6.phaseSettlement = marker;
|
|
@@ -19417,7 +19571,7 @@ function settlePreparedLifecycleCapacity(input2) {
|
|
|
19417
19571
|
}
|
|
19418
19572
|
return updateReliabilityOperation(input2.identity, (record6) => {
|
|
19419
19573
|
assertCurrentCapacityController(input2.controller, directory);
|
|
19420
|
-
if (!matchesFence(record6, pending.fence) || !(0,
|
|
19574
|
+
if (!matchesFence(record6, pending.fence) || !(0, import_node_util13.isDeepStrictEqual)(record6.phaseSettlement, pending))
|
|
19421
19575
|
return false;
|
|
19422
19576
|
record6.phaseSettlement = null;
|
|
19423
19577
|
return true;
|
|
@@ -19467,6 +19621,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19467
19621
|
};
|
|
19468
19622
|
const ids2 = newLifecycleIds();
|
|
19469
19623
|
const copiedOptions = { ...options };
|
|
19624
|
+
if (kind === "ensure") assertFreshBootstrapRequest(identity2, options);
|
|
19470
19625
|
const copiedCommand = command ? [...command] : void 0;
|
|
19471
19626
|
if (kind === "stop") {
|
|
19472
19627
|
const intent = updateReliabilityOperation(identity2, (record6) => {
|
|
@@ -19510,6 +19665,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19510
19665
|
identity: identity2,
|
|
19511
19666
|
requestId: ids2.requestId,
|
|
19512
19667
|
profile: copiedOptions.profile,
|
|
19668
|
+
...copiedOptions.initializeNew ? { initializeNew: true } : {},
|
|
19513
19669
|
...copiedCommand ? { command: copiedCommand } : {}
|
|
19514
19670
|
});
|
|
19515
19671
|
if (initial.state.executionPolicy !== "manual")
|
|
@@ -19616,7 +19772,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19616
19772
|
removeSignals();
|
|
19617
19773
|
}
|
|
19618
19774
|
}
|
|
19619
|
-
function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs, maxSampleAgeMs, directory =
|
|
19775
|
+
function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs, maxSampleAgeMs, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller"), controller, admission) {
|
|
19620
19776
|
if (request2.kind === "stop") throw new Error("Stop never requires capacity admission.");
|
|
19621
19777
|
const capacity = createLifecycleCapacityStore(directory);
|
|
19622
19778
|
const snapshot = capacity.read();
|
|
@@ -19672,10 +19828,10 @@ function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs,
|
|
|
19672
19828
|
totals
|
|
19673
19829
|
};
|
|
19674
19830
|
if (binding.operationId === request2.operationId) {
|
|
19675
|
-
if (binding.execSteady && !(0,
|
|
19831
|
+
if (binding.execSteady && !(0, import_node_util13.isDeepStrictEqual)(binding.execSteady, receipt))
|
|
19676
19832
|
throw new Error("Repeated exec settlement proof changed.");
|
|
19677
19833
|
execSteady = binding.execSteady;
|
|
19678
|
-
} else if (!retained.startup && !retained.heavy && (0,
|
|
19834
|
+
} else if (!retained.startup && !retained.heavy && (0, import_node_util13.isDeepStrictEqual)(retained.totals, totals)) {
|
|
19679
19835
|
execSteady = receipt;
|
|
19680
19836
|
}
|
|
19681
19837
|
} else if (binding.operationId === request2.operationId && binding.execSteady) {
|
|
@@ -19716,7 +19872,7 @@ function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs,
|
|
|
19716
19872
|
return decision;
|
|
19717
19873
|
}
|
|
19718
19874
|
function capacityPolicyTargets(repoPath) {
|
|
19719
|
-
const policy = readCapacityPolicy(
|
|
19875
|
+
const policy = readCapacityPolicy(import_node_path48.default.join(DEVROUTER_HOME, "controller"));
|
|
19720
19876
|
return policy?.admissions === "enabled" && policy.enrollments.some((entry) => entry.repoPath === repoPath);
|
|
19721
19877
|
}
|
|
19722
19878
|
function controllerWaitSeconds(deadline) {
|
|
@@ -19725,7 +19881,7 @@ function controllerWaitSeconds(deadline) {
|
|
|
19725
19881
|
async function superviseThroughController(input2) {
|
|
19726
19882
|
if (input2.kind === "exec" && !input2.command)
|
|
19727
19883
|
throw new Error("Exec requires a command for controller admission.");
|
|
19728
|
-
const directory =
|
|
19884
|
+
const directory = import_node_path48.default.join(DEVROUTER_HOME, "controller");
|
|
19729
19885
|
const cancellation = { requested: false };
|
|
19730
19886
|
const removeSignals = installLifecycleWaitSignals(cancellation);
|
|
19731
19887
|
const cancelled = () => {
|
|
@@ -19749,7 +19905,7 @@ async function superviseThroughController(input2) {
|
|
|
19749
19905
|
try {
|
|
19750
19906
|
const bind = () => observeControllerBinding(directory, {
|
|
19751
19907
|
path: input2.repoPath,
|
|
19752
|
-
session: (0,
|
|
19908
|
+
session: (0, import_node_crypto26.randomUUID)(),
|
|
19753
19909
|
profile: input2.profile ?? "full",
|
|
19754
19910
|
// The protocol requires at least one readiness selector, and every
|
|
19755
19911
|
// supervised operation depends on runtime readiness; "runtime" is the
|
|
@@ -19759,7 +19915,12 @@ async function superviseThroughController(input2) {
|
|
|
19759
19915
|
let binding = await bind();
|
|
19760
19916
|
let pending = await submitControllerOperation(
|
|
19761
19917
|
directory,
|
|
19762
|
-
input2.kind === "exec" ? { ...binding, requestId: input2.requestId, kind: "exec", command: input2.command ?? [] } : {
|
|
19918
|
+
input2.kind === "exec" ? { ...binding, requestId: input2.requestId, kind: "exec", command: input2.command ?? [] } : {
|
|
19919
|
+
...binding,
|
|
19920
|
+
requestId: input2.requestId,
|
|
19921
|
+
kind: "ensure",
|
|
19922
|
+
...input2.initializeNew ? { initializeNew: true } : {}
|
|
19923
|
+
},
|
|
19763
19924
|
{ waitSeconds: controllerWaitSeconds(deadline), onOutput }
|
|
19764
19925
|
);
|
|
19765
19926
|
while (pending.status !== "terminal") {
|
|
@@ -19797,7 +19958,7 @@ async function superviseThroughController(input2) {
|
|
|
19797
19958
|
removeSignals();
|
|
19798
19959
|
}
|
|
19799
19960
|
}
|
|
19800
|
-
function renewLifecycleCapacity(request2, policy, samples, controller, directory =
|
|
19961
|
+
function renewLifecycleCapacity(request2, policy, samples, controller, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller"), nowMs = Date.now()) {
|
|
19801
19962
|
return updateReliabilityOperation(request2.identity, (record6) => {
|
|
19802
19963
|
const binding = record6.capacity;
|
|
19803
19964
|
if (!matchesFence(record6, request2.fence) || !binding || binding.operationId !== request2.operationId || binding.workerId !== request2.workerId || binding.controller?.store !== controller.store || binding.controller?.epoch !== controller.epoch)
|
|
@@ -19885,7 +20046,7 @@ function retireQueuedLifecycle(request2, supersededOnly = false) {
|
|
|
19885
20046
|
return true;
|
|
19886
20047
|
});
|
|
19887
20048
|
}
|
|
19888
|
-
function bindLifecycleCapacity(request2, binding, directory =
|
|
20049
|
+
function bindLifecycleCapacity(request2, binding, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller")) {
|
|
19889
20050
|
if (request2.kind === "stop") throw new Error("Stop never requires capacity admission.");
|
|
19890
20051
|
updateReliabilityOperation(request2.identity, (record6) => {
|
|
19891
20052
|
if (!matchesFence(record6, request2.fence) || record6.worker || record6.state.operation?.id !== request2.operationId || record6.state.operation.status !== "NOT_STARTED" || record6.state.operation.drained)
|
|
@@ -19900,13 +20061,13 @@ function bindLifecycleCapacity(request2, binding, directory = import_node_path47
|
|
|
19900
20061
|
stepRecord(record6, { ...request2.fence, type: "admission", result: "admitted" });
|
|
19901
20062
|
});
|
|
19902
20063
|
}
|
|
19903
|
-
var
|
|
20064
|
+
var import_node_crypto26, import_node_path48, import_node_util13, activeWorker, lockHeld, BUSY_LIFECYCLE_WAIT_MS, BUSY_LIFECYCLE_POLL_MS, CAPACITY_CLIENT_WAIT_MS, BUSY_LIFECYCLE_PROGRESS_MS;
|
|
19904
20065
|
var init_reliability_lifecycle = __esm({
|
|
19905
20066
|
"src/core/reliability-lifecycle.ts"() {
|
|
19906
20067
|
"use strict";
|
|
19907
|
-
|
|
19908
|
-
|
|
19909
|
-
|
|
20068
|
+
import_node_crypto26 = require("crypto");
|
|
20069
|
+
import_node_path48 = __toESM(require("path"));
|
|
20070
|
+
import_node_util13 = require("util");
|
|
19910
20071
|
init_capacity_accounting();
|
|
19911
20072
|
init_capacity_policy();
|
|
19912
20073
|
init_capacity_request();
|
|
@@ -19922,6 +20083,7 @@ var init_reliability_lifecycle = __esm({
|
|
|
19922
20083
|
init_file_lock();
|
|
19923
20084
|
init_host_routes();
|
|
19924
20085
|
init_managed_devsy_stop();
|
|
20086
|
+
init_managed_fresh_bootstrap();
|
|
19925
20087
|
init_managed_post_start();
|
|
19926
20088
|
init_managed_runtime_state();
|
|
19927
20089
|
init_managed_stop_recovery();
|
|
@@ -19947,11 +20109,11 @@ var init_reliability_lifecycle = __esm({
|
|
|
19947
20109
|
});
|
|
19948
20110
|
|
|
19949
20111
|
// src/core/capacity-queue.ts
|
|
19950
|
-
var
|
|
20112
|
+
var import_node_util14, CapacityQueue;
|
|
19951
20113
|
var init_capacity_queue = __esm({
|
|
19952
20114
|
"src/core/capacity-queue.ts"() {
|
|
19953
20115
|
"use strict";
|
|
19954
|
-
|
|
20116
|
+
import_node_util14 = require("util");
|
|
19955
20117
|
init_capacity_policy();
|
|
19956
20118
|
init_capacity_store();
|
|
19957
20119
|
init_reliability_contract();
|
|
@@ -19987,7 +20149,7 @@ var init_capacity_queue = __esm({
|
|
|
19987
20149
|
if (existing) {
|
|
19988
20150
|
const existingRequest = existing.phase === "terminal" ? { ...existing.request, command: void 0 } : existing.request;
|
|
19989
20151
|
const incomingRequest = existing.phase === "terminal" ? { ...request2, command: void 0 } : request2;
|
|
19990
|
-
if (!(0,
|
|
20152
|
+
if (!(0, import_node_util14.isDeepStrictEqual)(existingRequest, incomingRequest) || !(0, import_node_util14.isDeepStrictEqual)(existing.reservation, reservation) || !(0, import_node_util14.isDeepStrictEqual)(existing.admission, admission) || existing.autoResume !== autoResume)
|
|
19991
20153
|
throw new Error("Operation reference belongs to another accepted request.");
|
|
19992
20154
|
return request2.operationId;
|
|
19993
20155
|
}
|
|
@@ -20150,7 +20312,7 @@ var init_capacity_queue = __esm({
|
|
|
20150
20312
|
const operation = record6?.state.operation?.id === entry.request.operationId ? record6.state.operation : record6?.state.operationHistory.find(
|
|
20151
20313
|
(operation2) => operation2.id === entry.request.operationId
|
|
20152
20314
|
);
|
|
20153
|
-
if (record6 && (!(0,
|
|
20315
|
+
if (record6 && (!(0, import_node_util14.isDeepStrictEqual)(reliabilityFence(record6.state), entry.request.fence) || record6.state.operation?.id !== entry.request.operationId) && operation?.drained && ["NOT_STARTED", "NOT_LAUNCHED"].includes(operation.status) && record6.worker?.operationId !== entry.request.operationId) {
|
|
20154
20316
|
entry.reason = "intent-superseded";
|
|
20155
20317
|
entry.phase = "terminal";
|
|
20156
20318
|
entry.request.command = void 0;
|
|
@@ -20286,7 +20448,7 @@ var init_capacity_startup_witness = __esm({
|
|
|
20286
20448
|
function readHostWakeEpoch(platform = process.platform) {
|
|
20287
20449
|
if (platform !== "darwin") return void 0;
|
|
20288
20450
|
try {
|
|
20289
|
-
const result = (0,
|
|
20451
|
+
const result = (0, import_node_child_process34.spawnSync)("/usr/sbin/sysctl", ["-n", "kern.wake_abs_time"], {
|
|
20290
20452
|
encoding: "utf8",
|
|
20291
20453
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20292
20454
|
timeout: 250,
|
|
@@ -20301,11 +20463,11 @@ function readHostWakeEpoch(platform = process.platform) {
|
|
|
20301
20463
|
return null;
|
|
20302
20464
|
}
|
|
20303
20465
|
}
|
|
20304
|
-
var
|
|
20466
|
+
var import_node_child_process34;
|
|
20305
20467
|
var init_host_wake = __esm({
|
|
20306
20468
|
"src/core/host-wake.ts"() {
|
|
20307
20469
|
"use strict";
|
|
20308
|
-
|
|
20470
|
+
import_node_child_process34 = require("child_process");
|
|
20309
20471
|
}
|
|
20310
20472
|
});
|
|
20311
20473
|
|
|
@@ -20379,7 +20541,7 @@ function createCapacityController(options) {
|
|
|
20379
20541
|
let matches = false;
|
|
20380
20542
|
try {
|
|
20381
20543
|
current = new ControllerStore(options.directory).read();
|
|
20382
|
-
matches = current?.store === controller.store && current.epoch === controller.epoch && (0,
|
|
20544
|
+
matches = current?.store === controller.store && current.epoch === controller.epoch && (0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy);
|
|
20383
20545
|
} catch {
|
|
20384
20546
|
}
|
|
20385
20547
|
if (invalidated || lifetime.signal.aborted || !matches) {
|
|
@@ -20531,12 +20693,12 @@ function createCapacityController(options) {
|
|
|
20531
20693
|
controller,
|
|
20532
20694
|
policyRevision: policy.revision
|
|
20533
20695
|
});
|
|
20534
|
-
const payloadKey = (0,
|
|
20696
|
+
const payloadKey = (0, import_node_crypto27.randomBytes)(32);
|
|
20535
20697
|
const acceptedPayloads = /* @__PURE__ */ new Map();
|
|
20536
20698
|
const settlePreparations = () => {
|
|
20537
20699
|
if (lifetime.signal.aborted) return;
|
|
20538
20700
|
try {
|
|
20539
|
-
if (!(0,
|
|
20701
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy)) return;
|
|
20540
20702
|
} catch {
|
|
20541
20703
|
return;
|
|
20542
20704
|
}
|
|
@@ -20550,7 +20712,7 @@ function createCapacityController(options) {
|
|
|
20550
20712
|
const record6 = readReliabilityOperation(identity2);
|
|
20551
20713
|
if (!record6?.capacity || !record6.preparation && !record6.capacity.execSteady || record6.worker || !record6.state.operation?.drained || !["ensure", "exec"].includes(record6.state.operation.kind))
|
|
20552
20714
|
continue;
|
|
20553
|
-
const bytes2 = readControllerEvidence(
|
|
20715
|
+
const bytes2 = readControllerEvidence(import_node_path49.default.join(enrollment.repoPath, ".devrouter.yml"));
|
|
20554
20716
|
const estimates = loadRepoConfig(enrollment.repoPath, () => bytes2).capacity;
|
|
20555
20717
|
if (!estimates) continue;
|
|
20556
20718
|
settlePreparedLifecycleCapacity({
|
|
@@ -20588,7 +20750,7 @@ function createCapacityController(options) {
|
|
|
20588
20750
|
};
|
|
20589
20751
|
const resolveCapacityTarget = async (environment, signal) => {
|
|
20590
20752
|
const current = readCapacityPolicy(options.directory);
|
|
20591
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20753
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return void 0;
|
|
20592
20754
|
let resolved2;
|
|
20593
20755
|
try {
|
|
20594
20756
|
resolved2 = await resolveCapacityEnrollment(
|
|
@@ -20600,10 +20762,10 @@ function createCapacityController(options) {
|
|
|
20600
20762
|
} catch {
|
|
20601
20763
|
return void 0;
|
|
20602
20764
|
}
|
|
20603
|
-
if (signal.aborted || !(0,
|
|
20604
|
-
if (!(0,
|
|
20765
|
+
if (signal.aborted || !(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment)) return void 0;
|
|
20766
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return void 0;
|
|
20605
20767
|
const runtime = current.domains[resolved2.enrollment.runtimeDomain];
|
|
20606
|
-
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0,
|
|
20768
|
+
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0, import_node_util15.isDeepStrictEqual)(entry, resolved2.enrollment)))
|
|
20607
20769
|
return void 0;
|
|
20608
20770
|
return { current, resolved: resolved2, runtime };
|
|
20609
20771
|
};
|
|
@@ -20645,7 +20807,7 @@ function createCapacityController(options) {
|
|
|
20645
20807
|
const bounded = AbortSignal.any([signal, lifetime.signal]);
|
|
20646
20808
|
if (bounded.aborted) return false;
|
|
20647
20809
|
const current = readCapacityPolicy(options.directory);
|
|
20648
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20810
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return false;
|
|
20649
20811
|
const request2 = reconcileParkedLifecycleStop({
|
|
20650
20812
|
identity: { ...identity2 },
|
|
20651
20813
|
controller,
|
|
@@ -20695,7 +20857,7 @@ function createCapacityController(options) {
|
|
|
20695
20857
|
{
|
|
20696
20858
|
...charge,
|
|
20697
20859
|
operationId: prepared.operationId,
|
|
20698
|
-
reservationId: (0,
|
|
20860
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20699
20861
|
policyRevision: target.current.revision
|
|
20700
20862
|
},
|
|
20701
20863
|
{
|
|
@@ -20724,7 +20886,7 @@ function createCapacityController(options) {
|
|
|
20724
20886
|
signal = AbortSignal.any([signal, lifetime.signal]);
|
|
20725
20887
|
if (signal.aborted) throw new Error("Capacity submission unavailable.");
|
|
20726
20888
|
const current = readCapacityPolicy(options.directory);
|
|
20727
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20889
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy))
|
|
20728
20890
|
throw new Error("Capacity controller policy changed.");
|
|
20729
20891
|
validate3();
|
|
20730
20892
|
const resolved2 = await enrollCapacityLifecycle(
|
|
@@ -20738,12 +20900,12 @@ function createCapacityController(options) {
|
|
|
20738
20900
|
options.directory,
|
|
20739
20901
|
bindingResolver
|
|
20740
20902
|
);
|
|
20741
|
-
if (!(0,
|
|
20903
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment) || signal.aborted)
|
|
20742
20904
|
throw new Error("Capacity submission binding changed.");
|
|
20743
|
-
if (!(0,
|
|
20905
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current))
|
|
20744
20906
|
throw new Error("Capacity submission policy changed during resolution.");
|
|
20745
20907
|
const runtime = current.domains[resolved2.enrollment.runtimeDomain];
|
|
20746
|
-
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0,
|
|
20908
|
+
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0, import_node_util15.isDeepStrictEqual)(entry, resolved2.enrollment)))
|
|
20747
20909
|
throw new Error("Capacity pool does not match policy enrollment.");
|
|
20748
20910
|
const pool = {
|
|
20749
20911
|
daemonId: runtime.daemonId,
|
|
@@ -20780,7 +20942,8 @@ function createCapacityController(options) {
|
|
|
20780
20942
|
profile: environment.profile,
|
|
20781
20943
|
consumer: initialConsumer,
|
|
20782
20944
|
runtimeRunning: request2.kind === "exec" && Boolean(resolveRunningWorkspaceContainer(environment.repoPath)),
|
|
20783
|
-
...request2.kind === "exec" ? { command: request2.command } : {}
|
|
20945
|
+
...request2.kind === "exec" ? { command: request2.command } : {},
|
|
20946
|
+
...request2.kind === "ensure" && request2.initializeNew ? { initializeNew: true } : {}
|
|
20784
20947
|
});
|
|
20785
20948
|
if (prepared.request && request2.kind === "ensure") {
|
|
20786
20949
|
try {
|
|
@@ -20798,13 +20961,14 @@ function createCapacityController(options) {
|
|
|
20798
20961
|
throw error;
|
|
20799
20962
|
}
|
|
20800
20963
|
}
|
|
20801
|
-
const signature = (0,
|
|
20964
|
+
const signature = (0, import_node_crypto27.createHmac)("sha256", payloadKey).update(
|
|
20802
20965
|
JSON.stringify({
|
|
20803
20966
|
repoPath: identity2.repoPath,
|
|
20804
20967
|
profile: environment.profile,
|
|
20805
20968
|
kind: request2.kind,
|
|
20806
20969
|
operation: request2.operation ?? null,
|
|
20807
|
-
command: request2.kind === "exec" ? request2.command : null
|
|
20970
|
+
command: request2.kind === "exec" ? request2.command : null,
|
|
20971
|
+
...request2.kind === "ensure" && request2.initializeNew ? { initializeNew: true } : {}
|
|
20808
20972
|
})
|
|
20809
20973
|
).digest("hex");
|
|
20810
20974
|
const previousPayload = acceptedPayloads.get(prepared.operationId);
|
|
@@ -20818,7 +20982,7 @@ function createCapacityController(options) {
|
|
|
20818
20982
|
{
|
|
20819
20983
|
...charge,
|
|
20820
20984
|
operationId: prepared.operationId,
|
|
20821
|
-
reservationId: (0,
|
|
20985
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20822
20986
|
policyRevision: current.revision
|
|
20823
20987
|
},
|
|
20824
20988
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -20877,7 +21041,7 @@ function createCapacityController(options) {
|
|
|
20877
21041
|
if (signal.aborted || !policy.recovery.enabled) return;
|
|
20878
21042
|
if (failedCapabilities.length === 0 || failedCapabilities.length > 64) return;
|
|
20879
21043
|
const current = readCapacityPolicy(options.directory);
|
|
20880
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
21044
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return;
|
|
20881
21045
|
let observed;
|
|
20882
21046
|
try {
|
|
20883
21047
|
observed = revalidate();
|
|
@@ -20897,10 +21061,10 @@ function createCapacityController(options) {
|
|
|
20897
21061
|
} catch {
|
|
20898
21062
|
return;
|
|
20899
21063
|
}
|
|
20900
|
-
if (signal.aborted || !(0,
|
|
20901
|
-
if (!(0,
|
|
21064
|
+
if (signal.aborted || !(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment)) return;
|
|
21065
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return;
|
|
20902
21066
|
const runtime = current.domains[resolved2.enrollment.runtimeDomain];
|
|
20903
|
-
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0,
|
|
21067
|
+
if (runtime?.kind !== "runtime" || runtime.hostDomain !== resolved2.enrollment.hostDomain || current.domains[runtime.hostDomain]?.kind !== "host" || !current.enrollments.some((entry) => (0, import_node_util15.isDeepStrictEqual)(entry, resolved2.enrollment)))
|
|
20904
21068
|
return;
|
|
20905
21069
|
const identity2 = environmentIdentity(environment);
|
|
20906
21070
|
const record6 = readReliabilityOperation(identity2);
|
|
@@ -20953,7 +21117,7 @@ function createCapacityController(options) {
|
|
|
20953
21117
|
// the budget module then falls back to the conservative wall duration.
|
|
20954
21118
|
activeElapsedMs: null,
|
|
20955
21119
|
profile: environment.profile,
|
|
20956
|
-
incidentId: `incident-${(0,
|
|
21120
|
+
incidentId: `incident-${(0, import_node_crypto27.randomUUID)()}`
|
|
20957
21121
|
});
|
|
20958
21122
|
} catch {
|
|
20959
21123
|
return;
|
|
@@ -20971,7 +21135,7 @@ function createCapacityController(options) {
|
|
|
20971
21135
|
{
|
|
20972
21136
|
...charge,
|
|
20973
21137
|
operationId: prepared.operationId,
|
|
20974
|
-
reservationId: (0,
|
|
21138
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20975
21139
|
policyRevision: current.revision
|
|
20976
21140
|
},
|
|
20977
21141
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -20991,13 +21155,13 @@ function createCapacityController(options) {
|
|
|
20991
21155
|
}
|
|
20992
21156
|
};
|
|
20993
21157
|
}
|
|
20994
|
-
var
|
|
21158
|
+
var import_node_crypto27, import_node_path49, import_node_util15;
|
|
20995
21159
|
var init_capacity_controller = __esm({
|
|
20996
21160
|
"src/core/capacity-controller.ts"() {
|
|
20997
21161
|
"use strict";
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21162
|
+
import_node_crypto27 = require("crypto");
|
|
21163
|
+
import_node_path49 = __toESM(require("path"));
|
|
21164
|
+
import_node_util15 = require("util");
|
|
21001
21165
|
init_capacity_accounting();
|
|
21002
21166
|
init_capacity_docker_probe();
|
|
21003
21167
|
init_capacity_enrollment();
|
|
@@ -21093,7 +21257,7 @@ printf '%s %s %s\n' "$pid" "$birth" "$fingerprint"
|
|
|
21093
21257
|
|
|
21094
21258
|
// src/core/controller-observation.ts
|
|
21095
21259
|
function digest2(value) {
|
|
21096
|
-
return (0,
|
|
21260
|
+
return (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
21097
21261
|
}
|
|
21098
21262
|
function readRoutes() {
|
|
21099
21263
|
return readHostRouteStateReadOnly((file) => readControllerEvidence(file, 1048576));
|
|
@@ -21156,14 +21320,14 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21156
21320
|
)).trim().split("\n");
|
|
21157
21321
|
if (metadata.length !== 2) throw new Error("Observation ownership paths unavailable.");
|
|
21158
21322
|
const [gitDir, commonDir] = metadata;
|
|
21159
|
-
const sourcePath =
|
|
21323
|
+
const sourcePath = import_node_path50.default.join(environment.repoPath, ".devcontainer/devcontainer.json");
|
|
21160
21324
|
const files = [
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21325
|
+
import_node_path50.default.join(commonDir, "devrouter/workspaces", `${environment.workspace}.json`),
|
|
21326
|
+
import_node_path50.default.join(environment.repoPath, ".devrouter.yml"),
|
|
21327
|
+
import_node_path50.default.join(gitDir, "devrouter-workspace"),
|
|
21164
21328
|
managedRuntimeStatePath(environment.repoPath, environment.workspace),
|
|
21165
21329
|
sourcePath,
|
|
21166
|
-
|
|
21330
|
+
import_node_path50.default.join(environment.repoPath, MANAGED_DEVCONTAINER_PATH)
|
|
21167
21331
|
];
|
|
21168
21332
|
const persisted = captureControllerEvidence(files);
|
|
21169
21333
|
if (fingerprint(persisted.contents[0], persisted.contents[1]) !== environment.fingerprint)
|
|
@@ -21177,7 +21341,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21177
21341
|
() => persisted.contents[3]
|
|
21178
21342
|
);
|
|
21179
21343
|
const source = parseDevcontainerConfig(persisted.contents[4], sourcePath);
|
|
21180
|
-
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0,
|
|
21344
|
+
if (!state || state.devpodId !== environment.providerId || state.profile !== environment.profile || typeof source.service !== "string" || !source.service || (0, import_node_crypto28.createHash)("sha256").update(persisted.contents[4]).digest("hex") !== state.sourceConfigSha256 || (0, import_node_crypto28.createHash)("sha256").update(persisted.contents[5]).digest("hex") !== state.effectiveConfigSha256)
|
|
21181
21345
|
throw new ControllerObservationBindingChanged("Observation retained configuration changed.");
|
|
21182
21346
|
const identity2 = {
|
|
21183
21347
|
repoPath: environment.repoPath,
|
|
@@ -21188,7 +21352,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21188
21352
|
if (!journal) throw new Error("Observation journal is unavailable.");
|
|
21189
21353
|
const routes = readRoutes().filter((route) => route.repoPath === environment.repoPath);
|
|
21190
21354
|
const before = await containers(state.composeProject, signal);
|
|
21191
|
-
const composeDirectory =
|
|
21355
|
+
const composeDirectory = import_node_path50.default.join(environment.repoPath, ".devcontainer");
|
|
21192
21356
|
const references = typeof source.dockerComposeFile === "string" ? [source.dockerComposeFile] : source.dockerComposeFile;
|
|
21193
21357
|
if (!Array.isArray(references) || !references.length || references.some((value) => typeof value !== "string"))
|
|
21194
21358
|
throw new Error("Observation Compose source is unavailable.");
|
|
@@ -21205,7 +21369,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21205
21369
|
if (!recorded || container.labels["com.docker.compose.project.working_dir"] !== composeDirectory)
|
|
21206
21370
|
throw new Error("Observation Compose ownership is unavailable.");
|
|
21207
21371
|
const files2 = recorded.split(",").map((file) => file.trim());
|
|
21208
|
-
if (files2.some((file) => !
|
|
21372
|
+
if (files2.some((file) => !import_node_path50.default.isAbsolute(file)) || !hasExactComposeIdentity(container, {
|
|
21209
21373
|
repoPath: environment.repoPath,
|
|
21210
21374
|
service: container.labels["com.docker.compose.service"] ?? "",
|
|
21211
21375
|
composeProject: state.composeProject,
|
|
@@ -21352,12 +21516,12 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21352
21516
|
};
|
|
21353
21517
|
};
|
|
21354
21518
|
}
|
|
21355
|
-
var
|
|
21519
|
+
var import_node_crypto28, import_node_path50, OBSERVATION_INSPECT_TEMPLATE;
|
|
21356
21520
|
var init_controller_observation = __esm({
|
|
21357
21521
|
"src/core/controller-observation.ts"() {
|
|
21358
21522
|
"use strict";
|
|
21359
|
-
|
|
21360
|
-
|
|
21523
|
+
import_node_crypto28 = require("crypto");
|
|
21524
|
+
import_node_path50 = __toESM(require("path"));
|
|
21361
21525
|
init_controller_binding();
|
|
21362
21526
|
init_controller_monitor();
|
|
21363
21527
|
init_controller_probe();
|
|
@@ -21381,12 +21545,12 @@ var init_controller_observation = __esm({
|
|
|
21381
21545
|
});
|
|
21382
21546
|
|
|
21383
21547
|
// src/core/controller-sessions.ts
|
|
21384
|
-
var
|
|
21548
|
+
var import_node_crypto29, import_node_util16, ControllerSessions;
|
|
21385
21549
|
var init_controller_sessions = __esm({
|
|
21386
21550
|
"src/core/controller-sessions.ts"() {
|
|
21387
21551
|
"use strict";
|
|
21388
|
-
|
|
21389
|
-
|
|
21552
|
+
import_node_crypto29 = require("crypto");
|
|
21553
|
+
import_node_util16 = require("util");
|
|
21390
21554
|
ControllerSessions = class {
|
|
21391
21555
|
constructor(store, readWakeEpoch = () => void 0) {
|
|
21392
21556
|
this.store = store;
|
|
@@ -21465,7 +21629,7 @@ var init_controller_sessions = __esm({
|
|
|
21465
21629
|
}
|
|
21466
21630
|
checkEnvironment(next, environment) {
|
|
21467
21631
|
const shared = next.environments.find((entry) => entry.repoPath === environment.repoPath);
|
|
21468
|
-
if (shared && !(0,
|
|
21632
|
+
if (shared && !(0, import_node_util16.isDeepStrictEqual)(shared, environment))
|
|
21469
21633
|
throw new Error("Controller environment binding conflicts.");
|
|
21470
21634
|
const known = [
|
|
21471
21635
|
...next.environments,
|
|
@@ -21579,7 +21743,7 @@ var init_controller_sessions = __esm({
|
|
|
21579
21743
|
const session = {
|
|
21580
21744
|
id: id5,
|
|
21581
21745
|
environmentId: environment.id,
|
|
21582
|
-
generation: (0,
|
|
21746
|
+
generation: (0, import_node_crypto29.randomUUID)(),
|
|
21583
21747
|
requirements: required,
|
|
21584
21748
|
renewedAtMs: wall,
|
|
21585
21749
|
parkingConsent: "protected",
|
|
@@ -21601,13 +21765,13 @@ var init_controller_sessions = __esm({
|
|
|
21601
21765
|
const retained = next.retainedSessions.find(
|
|
21602
21766
|
(entry) => entry.id === previous.session && entry.epoch === previous.epoch && entry.generation === previous.generation
|
|
21603
21767
|
);
|
|
21604
|
-
if (previous.store !== next.store || next.version !== 3 || previous.epoch < next.fingerprint.enrolledEpoch || !retained || next.sessions.some((entry) => entry.id === previous.session) || !(0,
|
|
21768
|
+
if (previous.store !== next.store || next.version !== 3 || previous.epoch < next.fingerprint.enrolledEpoch || !retained || next.sessions.some((entry) => entry.id === previous.session) || !(0, import_node_util16.isDeepStrictEqual)(retained.environment, environment) || !(0, import_node_util16.isDeepStrictEqual)([...retained.requirements].sort(), required))
|
|
21605
21769
|
throw new Error("Controller reconnect binding is unavailable or changed.");
|
|
21606
21770
|
const shared = this.checkEnvironment(next, environment);
|
|
21607
21771
|
const session = {
|
|
21608
21772
|
id: previous.session,
|
|
21609
21773
|
environmentId: environment.id,
|
|
21610
|
-
generation: (0,
|
|
21774
|
+
generation: (0, import_node_crypto29.randomUUID)(),
|
|
21611
21775
|
requirements: required,
|
|
21612
21776
|
renewedAtMs: wall,
|
|
21613
21777
|
parkingConsent: "protected",
|
|
@@ -21767,26 +21931,26 @@ var init_controller_sessions = __esm({
|
|
|
21767
21931
|
|
|
21768
21932
|
// src/core/controller-server.ts
|
|
21769
21933
|
function privateDirectory2(directory) {
|
|
21770
|
-
const absolute2 =
|
|
21771
|
-
let current =
|
|
21772
|
-
for (const part of absolute2.slice(current.length).split(
|
|
21773
|
-
current =
|
|
21934
|
+
const absolute2 = import_node_path51.default.resolve(directory);
|
|
21935
|
+
let current = import_node_path51.default.parse(absolute2).root;
|
|
21936
|
+
for (const part of absolute2.slice(current.length).split(import_node_path51.default.sep)) {
|
|
21937
|
+
current = import_node_path51.default.join(current, part);
|
|
21774
21938
|
try {
|
|
21775
|
-
const stat2 =
|
|
21939
|
+
const stat2 = import_node_fs40.default.lstatSync(current);
|
|
21776
21940
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
21777
21941
|
throw new Error("Unsafe controller directory.");
|
|
21778
21942
|
} catch (error) {
|
|
21779
21943
|
if (error.code !== "ENOENT") throw error;
|
|
21780
|
-
|
|
21944
|
+
import_node_fs40.default.mkdirSync(current, { mode: 448 });
|
|
21781
21945
|
}
|
|
21782
21946
|
}
|
|
21783
|
-
const stat =
|
|
21947
|
+
const stat = import_node_fs40.default.lstatSync(absolute2);
|
|
21784
21948
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
21785
21949
|
throw new Error("Controller directory is not private.");
|
|
21786
21950
|
}
|
|
21787
21951
|
function validateOwnedFile(file, socket) {
|
|
21788
21952
|
try {
|
|
21789
|
-
const stat =
|
|
21953
|
+
const stat = import_node_fs40.default.lstatSync(file);
|
|
21790
21954
|
if (stat.uid !== process.getuid?.() || (socket ? !stat.isSocket() : !stat.isFile()) || (stat.mode & 63) !== 0)
|
|
21791
21955
|
throw new Error("Unsafe controller artifact.");
|
|
21792
21956
|
return true;
|
|
@@ -21806,12 +21970,12 @@ async function runController(options) {
|
|
|
21806
21970
|
throw new Error("Controller bindings require one owner.");
|
|
21807
21971
|
if (options.operations && options.createOperations)
|
|
21808
21972
|
throw new Error("Controller operations have multiple owners.");
|
|
21809
|
-
const socketPath =
|
|
21973
|
+
const socketPath = import_node_path51.default.join(options.directory, "control.sock");
|
|
21810
21974
|
if (Buffer.byteLength(socketPath) > 103) throw new Error("Controller socket path is too long.");
|
|
21811
21975
|
privateDirectory2(options.directory);
|
|
21812
|
-
const lockPath =
|
|
21976
|
+
const lockPath = import_node_path51.default.join(options.directory, "owner.lock");
|
|
21813
21977
|
try {
|
|
21814
|
-
const stat =
|
|
21978
|
+
const stat = import_node_fs40.default.lstatSync(lockPath);
|
|
21815
21979
|
if (!stat.isFile() || stat.uid !== process.getuid?.())
|
|
21816
21980
|
throw new Error("Unsafe controller owner lock.");
|
|
21817
21981
|
} catch (error) {
|
|
@@ -21822,7 +21986,7 @@ async function runController(options) {
|
|
|
21822
21986
|
await withFileLock(lockPath, { activity: "controller ownership", waitMs: 0 }, async () => {
|
|
21823
21987
|
const staleSocket = validateOwnedFile(socketPath, true);
|
|
21824
21988
|
const sessions = new ControllerSessions(store, options.wakeEpoch ?? readHostWakeEpoch);
|
|
21825
|
-
if (staleSocket)
|
|
21989
|
+
if (staleSocket) import_node_fs40.default.unlinkSync(socketPath);
|
|
21826
21990
|
const incarnation = sessions.read();
|
|
21827
21991
|
const { resolve, collect } = options.createBindings?.(store.bindingFingerprint()) ?? {
|
|
21828
21992
|
resolve: options.resolve,
|
|
@@ -22368,7 +22532,7 @@ async function runController(options) {
|
|
|
22368
22532
|
resolve2();
|
|
22369
22533
|
});
|
|
22370
22534
|
});
|
|
22371
|
-
|
|
22535
|
+
import_node_fs40.default.chmodSync(socketPath, 384);
|
|
22372
22536
|
await new Promise((resolve2) => {
|
|
22373
22537
|
finish = resolve2;
|
|
22374
22538
|
options.signal.addEventListener("abort", shutdown, { once: true });
|
|
@@ -22387,13 +22551,13 @@ async function runController(options) {
|
|
|
22387
22551
|
}
|
|
22388
22552
|
});
|
|
22389
22553
|
}
|
|
22390
|
-
var
|
|
22554
|
+
var import_node_fs40, import_node_net4, import_node_path51, FRAME_BYTES;
|
|
22391
22555
|
var init_controller_server = __esm({
|
|
22392
22556
|
"src/core/controller-server.ts"() {
|
|
22393
22557
|
"use strict";
|
|
22394
|
-
|
|
22558
|
+
import_node_fs40 = __toESM(require("fs"));
|
|
22395
22559
|
import_node_net4 = __toESM(require("net"));
|
|
22396
|
-
|
|
22560
|
+
import_node_path51 = __toESM(require("path"));
|
|
22397
22561
|
init_controller_monitor();
|
|
22398
22562
|
init_controller_protocol();
|
|
22399
22563
|
init_controller_sessions();
|
|
@@ -22412,7 +22576,7 @@ __export(controller_exports, {
|
|
|
22412
22576
|
runControllerCommand: () => runControllerCommand
|
|
22413
22577
|
});
|
|
22414
22578
|
async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
22415
|
-
const directory =
|
|
22579
|
+
const directory = import_node_path52.default.join(DEVROUTER_HOME, "controller");
|
|
22416
22580
|
try {
|
|
22417
22581
|
if (method === "run") {
|
|
22418
22582
|
const controller = new AbortController();
|
|
@@ -22458,7 +22622,7 @@ async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
|
22458
22622
|
if (fields2.timeout !== void 0) fields2.timeout = Number(fields2.timeout);
|
|
22459
22623
|
await controllerRequest(
|
|
22460
22624
|
directory,
|
|
22461
|
-
{ method, ...fields2, ...repo ? { path:
|
|
22625
|
+
{ method, ...fields2, ...repo ? { path: import_node_path52.default.resolve(repo) } : {} },
|
|
22462
22626
|
(value) => process.stdout.write(`${JSON.stringify(value)}
|
|
22463
22627
|
`)
|
|
22464
22628
|
);
|
|
@@ -22473,11 +22637,11 @@ async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
|
22473
22637
|
process.exitCode = 1;
|
|
22474
22638
|
}
|
|
22475
22639
|
}
|
|
22476
|
-
var
|
|
22640
|
+
var import_node_path52;
|
|
22477
22641
|
var init_controller = __esm({
|
|
22478
22642
|
"src/commands/controller.ts"() {
|
|
22479
22643
|
"use strict";
|
|
22480
|
-
|
|
22644
|
+
import_node_path52 = __toESM(require("path"));
|
|
22481
22645
|
init_capacity_collector();
|
|
22482
22646
|
init_capacity_controller();
|
|
22483
22647
|
init_capacity_policy();
|
|
@@ -22561,7 +22725,7 @@ function refusalLines(refusal) {
|
|
|
22561
22725
|
}
|
|
22562
22726
|
async function runCapacityCommand(method, options, dependencies = {}) {
|
|
22563
22727
|
if (method !== "reconcile") throw new Error(`Unsupported capacity command: ${method}`);
|
|
22564
|
-
const directory = dependencies.directory ??
|
|
22728
|
+
const directory = dependencies.directory ?? import_node_path53.default.join(DEVROUTER_HOME, "controller");
|
|
22565
22729
|
const json = Boolean(options.json);
|
|
22566
22730
|
const emit = (payload, human) => {
|
|
22567
22731
|
process.stdout.write(json ? `${JSON.stringify(payload, null, 2)}
|
|
@@ -22617,11 +22781,11 @@ async function runCapacityCommand(method, options, dependencies = {}) {
|
|
|
22617
22781
|
);
|
|
22618
22782
|
}
|
|
22619
22783
|
}
|
|
22620
|
-
var
|
|
22784
|
+
var import_node_path53, POOL_PROBE_TIMEOUT_MS, CapacityReconcileRefusal;
|
|
22621
22785
|
var init_capacity = __esm({
|
|
22622
22786
|
"src/commands/capacity.ts"() {
|
|
22623
22787
|
"use strict";
|
|
22624
|
-
|
|
22788
|
+
import_node_path53 = __toESM(require("path"));
|
|
22625
22789
|
init_capacity_docker_probe();
|
|
22626
22790
|
init_capacity_policy();
|
|
22627
22791
|
init_reliability_operation_store();
|
|
@@ -22677,28 +22841,28 @@ function replaceDevrouterSection(content) {
|
|
|
22677
22841
|
return `${content.slice(0, start)}${buildDevrouterSection()}${content.slice(end)}`;
|
|
22678
22842
|
}
|
|
22679
22843
|
function writeRepoFile(repoPath, relPath, content) {
|
|
22680
|
-
const absolutePath = (0,
|
|
22681
|
-
(0,
|
|
22682
|
-
(0,
|
|
22844
|
+
const absolutePath = (0, import_node_path54.join)(repoPath, relPath);
|
|
22845
|
+
(0, import_node_fs41.mkdirSync)((0, import_node_path54.dirname)(absolutePath), { recursive: true });
|
|
22846
|
+
(0, import_node_fs41.writeFileSync)(absolutePath, content, "utf-8");
|
|
22683
22847
|
return absolutePath;
|
|
22684
22848
|
}
|
|
22685
22849
|
function ensureAgentsMdSection(repoPath) {
|
|
22686
|
-
const filePath = (0,
|
|
22687
|
-
if ((0,
|
|
22688
|
-
const content = (0,
|
|
22850
|
+
const filePath = (0, import_node_path54.join)(repoPath, AGENTS_MD);
|
|
22851
|
+
if ((0, import_node_fs41.existsSync)(filePath)) {
|
|
22852
|
+
const content = (0, import_node_fs41.readFileSync)(filePath, "utf-8");
|
|
22689
22853
|
if (content.includes(DEVROUTER_SENTINEL)) {
|
|
22690
22854
|
const updated = replaceDevrouterSection(content);
|
|
22691
22855
|
if (updated === void 0 || updated === content) return { path: filePath, written: false };
|
|
22692
|
-
(0,
|
|
22856
|
+
(0, import_node_fs41.writeFileSync)(filePath, updated, "utf-8");
|
|
22693
22857
|
return { path: filePath, written: true };
|
|
22694
22858
|
}
|
|
22695
|
-
(0,
|
|
22859
|
+
(0, import_node_fs41.writeFileSync)(filePath, `${content.trimEnd()}
|
|
22696
22860
|
|
|
22697
22861
|
${buildDevrouterSection()}
|
|
22698
22862
|
`, "utf-8");
|
|
22699
22863
|
return { path: filePath, written: true };
|
|
22700
22864
|
}
|
|
22701
|
-
(0,
|
|
22865
|
+
(0, import_node_fs41.writeFileSync)(filePath, `# AGENTS.md
|
|
22702
22866
|
|
|
22703
22867
|
${buildDevrouterSection()}
|
|
22704
22868
|
`, "utf-8");
|
|
@@ -22708,12 +22872,12 @@ function ensureSkillFile(repoPath) {
|
|
|
22708
22872
|
const filePath = writeRepoFile(repoPath, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT);
|
|
22709
22873
|
return { path: filePath, written: true };
|
|
22710
22874
|
}
|
|
22711
|
-
var
|
|
22875
|
+
var import_node_fs41, import_node_path54, DEVROUTER_SENTINEL, DEVROUTER_END_SENTINEL, LEGACY_DEVROUTER_SECTION_END, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
|
|
22712
22876
|
var init_agents_md = __esm({
|
|
22713
22877
|
"src/core/agents-md.ts"() {
|
|
22714
22878
|
"use strict";
|
|
22715
|
-
|
|
22716
|
-
|
|
22879
|
+
import_node_fs41 = require("fs");
|
|
22880
|
+
import_node_path54 = require("path");
|
|
22717
22881
|
DEVROUTER_SENTINEL = "<!-- devrouter -->";
|
|
22718
22882
|
DEVROUTER_END_SENTINEL = "<!-- /devrouter -->";
|
|
22719
22883
|
LEGACY_DEVROUTER_SECTION_END = "- `devrouter ls`";
|
|
@@ -23335,6 +23499,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
23335
23499
|
"- 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.",
|
|
23336
23500
|
"- 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.",
|
|
23337
23501
|
"- 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.",
|
|
23502
|
+
"- 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.",
|
|
23338
23503
|
"- 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.",
|
|
23339
23504
|
"- 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.",
|
|
23340
23505
|
"- `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.",
|
|
@@ -23504,7 +23669,7 @@ var init_ai_prompt = __esm({
|
|
|
23504
23669
|
purpose: "Write/update devrouter section in the repo's AGENTS.md and install the devrouter skill."
|
|
23505
23670
|
},
|
|
23506
23671
|
{
|
|
23507
|
-
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair] [--open] [--json]",
|
|
23672
|
+
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair | --initialize-new] [--open] [--json]",
|
|
23508
23673
|
purpose: "Canonical startup and proof for an exact primary or linked checkout; atomically publishes routes after readiness."
|
|
23509
23674
|
},
|
|
23510
23675
|
{
|
|
@@ -24222,11 +24387,11 @@ function extractCurrentVersionFromRepoConfig(repoPath) {
|
|
|
24222
24387
|
};
|
|
24223
24388
|
}
|
|
24224
24389
|
function readPromptDirectory(promptDirPath) {
|
|
24225
|
-
if (!
|
|
24390
|
+
if (!import_node_fs42.default.existsSync(promptDirPath)) {
|
|
24226
24391
|
throw new Error(`Missing ${UPGRADE_PROMPTS_DIR} directory at ${promptDirPath}.`);
|
|
24227
24392
|
}
|
|
24228
24393
|
const releases = [];
|
|
24229
|
-
const files =
|
|
24394
|
+
const files = import_node_fs42.default.readdirSync(promptDirPath, { withFileTypes: true });
|
|
24230
24395
|
for (const file of files) {
|
|
24231
24396
|
if (!file.isFile() || !file.name.endsWith(".md")) {
|
|
24232
24397
|
continue;
|
|
@@ -24236,8 +24401,8 @@ function readPromptDirectory(promptDirPath) {
|
|
|
24236
24401
|
continue;
|
|
24237
24402
|
}
|
|
24238
24403
|
const version = normalizeVersion(basename);
|
|
24239
|
-
const promptPath =
|
|
24240
|
-
const prompt =
|
|
24404
|
+
const promptPath = import_node_path55.default.join(promptDirPath, file.name);
|
|
24405
|
+
const prompt = import_node_fs42.default.readFileSync(promptPath, "utf-8").trim();
|
|
24241
24406
|
releases.push({ version, prompt, promptPath });
|
|
24242
24407
|
}
|
|
24243
24408
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -24258,19 +24423,19 @@ function listAvailableUpgradeTargets(currentVersion, releases) {
|
|
|
24258
24423
|
}
|
|
24259
24424
|
function resolvePromptDirectory(explicitPath) {
|
|
24260
24425
|
if (explicitPath) {
|
|
24261
|
-
return
|
|
24426
|
+
return import_node_path55.default.resolve(explicitPath);
|
|
24262
24427
|
}
|
|
24263
|
-
const entryFile = process.argv[1] ?
|
|
24264
|
-
const entryDir =
|
|
24265
|
-
const resolvedEntryDir =
|
|
24428
|
+
const entryFile = process.argv[1] ? import_node_path55.default.resolve(process.argv[1]) : __filename;
|
|
24429
|
+
const entryDir = import_node_path55.default.dirname(entryFile);
|
|
24430
|
+
const resolvedEntryDir = import_node_fs42.default.existsSync(entryFile) ? import_node_path55.default.dirname(import_node_fs42.default.realpathSync(entryFile)) : entryDir;
|
|
24266
24431
|
const candidates = [
|
|
24267
|
-
|
|
24268
|
-
|
|
24269
|
-
|
|
24270
|
-
|
|
24271
|
-
|
|
24432
|
+
import_node_path55.default.resolve(resolvedEntryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24433
|
+
import_node_path55.default.resolve(entryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24434
|
+
import_node_path55.default.resolve(__dirname, "..", UPGRADE_PROMPTS_DIR),
|
|
24435
|
+
import_node_path55.default.resolve(__dirname, "..", "..", UPGRADE_PROMPTS_DIR),
|
|
24436
|
+
import_node_path55.default.resolve(process.cwd(), UPGRADE_PROMPTS_DIR)
|
|
24272
24437
|
];
|
|
24273
|
-
const existing = candidates.find((candidate) =>
|
|
24438
|
+
const existing = candidates.find((candidate) => import_node_fs42.default.existsSync(candidate));
|
|
24274
24439
|
return existing ?? candidates[0];
|
|
24275
24440
|
}
|
|
24276
24441
|
function loadUpgradeCatalog(options = {}) {
|
|
@@ -24286,12 +24451,12 @@ function loadUpgradeCatalog(options = {}) {
|
|
|
24286
24451
|
releases
|
|
24287
24452
|
};
|
|
24288
24453
|
}
|
|
24289
|
-
var
|
|
24454
|
+
var import_node_fs42, import_node_path55, SEMVER_RE, UPGRADE_PROMPTS_DIR;
|
|
24290
24455
|
var init_upgrade = __esm({
|
|
24291
24456
|
"src/core/upgrade.ts"() {
|
|
24292
24457
|
"use strict";
|
|
24293
|
-
|
|
24294
|
-
|
|
24458
|
+
import_node_fs42 = __toESM(require("fs"));
|
|
24459
|
+
import_node_path55 = __toESM(require("path"));
|
|
24295
24460
|
init_repo_config();
|
|
24296
24461
|
SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)$/;
|
|
24297
24462
|
UPGRADE_PROMPTS_DIR = "upgrade-prompts";
|
|
@@ -24444,7 +24609,7 @@ function isLoopbackHost(host) {
|
|
|
24444
24609
|
return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
|
|
24445
24610
|
}
|
|
24446
24611
|
function inspectCompose(composeFile, _workspace) {
|
|
24447
|
-
if (!
|
|
24612
|
+
if (!import_node_fs43.default.existsSync(composeFile)) {
|
|
24448
24613
|
return {
|
|
24449
24614
|
aliases: [],
|
|
24450
24615
|
publishedPorts: [],
|
|
@@ -24453,8 +24618,8 @@ function inspectCompose(composeFile, _workspace) {
|
|
|
24453
24618
|
};
|
|
24454
24619
|
}
|
|
24455
24620
|
try {
|
|
24456
|
-
const raw =
|
|
24457
|
-
const parsed =
|
|
24621
|
+
const raw = import_node_fs43.default.readFileSync(composeFile, "utf-8");
|
|
24622
|
+
const parsed = import_yaml6.default.parse(raw);
|
|
24458
24623
|
const root = asRecord(parsed);
|
|
24459
24624
|
const services = asRecord(root?.services);
|
|
24460
24625
|
const networks = asRecord(root?.networks);
|
|
@@ -24550,11 +24715,11 @@ function buildHostPortClaimsCheck(repoPath, workspace) {
|
|
|
24550
24715
|
}
|
|
24551
24716
|
}
|
|
24552
24717
|
function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
24553
|
-
const devcontainerDir =
|
|
24554
|
-
if (!
|
|
24718
|
+
const devcontainerDir = import_node_path56.default.join(repoPath, ".devcontainer");
|
|
24719
|
+
if (!import_node_fs43.default.existsSync(devcontainerDir)) {
|
|
24555
24720
|
return [];
|
|
24556
24721
|
}
|
|
24557
|
-
const compose = inspectCompose(
|
|
24722
|
+
const compose = inspectCompose(import_node_path56.default.join(devcontainerDir, "docker-compose.yml"), workspace);
|
|
24558
24723
|
const checks = [];
|
|
24559
24724
|
if (compose.parseError) {
|
|
24560
24725
|
checks.push({
|
|
@@ -24581,9 +24746,9 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24581
24746
|
details: compose.publishedPorts.length > 0 ? compose.publishedPorts.join(", ") : void 0,
|
|
24582
24747
|
suggestion: compose.parseError || compose.publishedPorts.length > 0 ? "Remove published ports and route services through devnet aliases with devrouter proxy apps." : void 0
|
|
24583
24748
|
});
|
|
24584
|
-
const dockerfilePath =
|
|
24585
|
-
const dockerfileExists =
|
|
24586
|
-
const dockerfile = dockerfileExists ?
|
|
24749
|
+
const dockerfilePath = import_node_path56.default.join(devcontainerDir, "Dockerfile");
|
|
24750
|
+
const dockerfileExists = import_node_fs43.default.existsSync(dockerfilePath);
|
|
24751
|
+
const dockerfile = dockerfileExists ? import_node_fs43.default.readFileSync(dockerfilePath, "utf-8") : "";
|
|
24587
24752
|
const devrouterArtifacts = ["@devrouter/cli", "devrouter-process"].filter(
|
|
24588
24753
|
(artifact) => dockerfile.includes(artifact)
|
|
24589
24754
|
);
|
|
@@ -24641,13 +24806,13 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24641
24806
|
});
|
|
24642
24807
|
return checks;
|
|
24643
24808
|
}
|
|
24644
|
-
var
|
|
24809
|
+
var import_node_fs43, import_node_path56, import_yaml6;
|
|
24645
24810
|
var init_devcontainer_diagnostics = __esm({
|
|
24646
24811
|
"src/core/devcontainer-diagnostics.ts"() {
|
|
24647
24812
|
"use strict";
|
|
24648
|
-
|
|
24649
|
-
|
|
24650
|
-
|
|
24813
|
+
import_node_fs43 = __toESM(require("fs"));
|
|
24814
|
+
import_node_path56 = __toESM(require("path"));
|
|
24815
|
+
import_yaml6 = __toESM(require("yaml"));
|
|
24651
24816
|
init_devcontainer_profile();
|
|
24652
24817
|
init_host_port_claims();
|
|
24653
24818
|
init_managed_post_start();
|
|
@@ -24742,11 +24907,11 @@ function reconcileRouteRunConflict(repoPath, app) {
|
|
|
24742
24907
|
}
|
|
24743
24908
|
}
|
|
24744
24909
|
}
|
|
24745
|
-
var
|
|
24910
|
+
var import_node_fs44;
|
|
24746
24911
|
var init_route_state = __esm({
|
|
24747
24912
|
"src/core/route-state.ts"() {
|
|
24748
24913
|
"use strict";
|
|
24749
|
-
|
|
24914
|
+
import_node_fs44 = __toESM(require("fs"));
|
|
24750
24915
|
init_host_routes();
|
|
24751
24916
|
init_workspace();
|
|
24752
24917
|
}
|
|
@@ -24921,7 +25086,7 @@ function toRepoStatus(repoPath) {
|
|
|
24921
25086
|
const resolvedRepoPath = resolveRepoPath(repoPath);
|
|
24922
25087
|
const configPath = getRepoConfigPath(resolvedRepoPath);
|
|
24923
25088
|
const explicitRepo = typeof repoPath === "string" && repoPath.trim().length > 0;
|
|
24924
|
-
const configExists =
|
|
25089
|
+
const configExists = import_node_fs45.default.existsSync(configPath);
|
|
24925
25090
|
if (!explicitRepo && !configExists) {
|
|
24926
25091
|
return void 0;
|
|
24927
25092
|
}
|
|
@@ -25074,11 +25239,11 @@ async function collectRouterStatus(repoPath) {
|
|
|
25074
25239
|
}
|
|
25075
25240
|
};
|
|
25076
25241
|
}
|
|
25077
|
-
var
|
|
25242
|
+
var import_node_fs45;
|
|
25078
25243
|
var init_status = __esm({
|
|
25079
25244
|
"src/core/status.ts"() {
|
|
25080
25245
|
"use strict";
|
|
25081
|
-
|
|
25246
|
+
import_node_fs45 = __toESM(require("fs"));
|
|
25082
25247
|
init_docker();
|
|
25083
25248
|
init_managed_runtime_state();
|
|
25084
25249
|
init_managed_runtime_status();
|
|
@@ -25088,14 +25253,14 @@ var init_status = __esm({
|
|
|
25088
25253
|
});
|
|
25089
25254
|
|
|
25090
25255
|
// src/core/idle-sweep.ts
|
|
25091
|
-
function idleSweepPaths(home =
|
|
25092
|
-
const directory =
|
|
25256
|
+
function idleSweepPaths(home = import_node_os7.default.homedir(), devrouterHome = DEVROUTER_HOME) {
|
|
25257
|
+
const directory = import_node_path57.default.join(devrouterHome, "idle");
|
|
25093
25258
|
return {
|
|
25094
|
-
plist:
|
|
25259
|
+
plist: import_node_path57.default.join(home, "Library", "LaunchAgents", `${IDLE_SWEEP_LABEL}.plist`),
|
|
25095
25260
|
directory,
|
|
25096
|
-
log:
|
|
25097
|
-
lastSweep:
|
|
25098
|
-
lock:
|
|
25261
|
+
log: import_node_path57.default.join(directory, "sweep.log"),
|
|
25262
|
+
lastSweep: import_node_path57.default.join(directory, "last-sweep.json"),
|
|
25263
|
+
lock: import_node_path57.default.join(directory, "sweep.lock")
|
|
25099
25264
|
};
|
|
25100
25265
|
}
|
|
25101
25266
|
function xml(value) {
|
|
@@ -25140,14 +25305,14 @@ ${env}
|
|
|
25140
25305
|
function readInstalledIdleFor(plistPath) {
|
|
25141
25306
|
let contents;
|
|
25142
25307
|
try {
|
|
25143
|
-
contents =
|
|
25308
|
+
contents = import_node_fs46.default.readFileSync(plistPath, "utf-8");
|
|
25144
25309
|
} catch {
|
|
25145
25310
|
return void 0;
|
|
25146
25311
|
}
|
|
25147
25312
|
return /<string>--idle-for<\/string>\s*<string>([^<]+)<\/string>/.exec(contents)?.[1] ?? "unknown";
|
|
25148
25313
|
}
|
|
25149
25314
|
function locateTool(name) {
|
|
25150
|
-
const result = (0,
|
|
25315
|
+
const result = (0, import_node_child_process35.spawnSync)("/bin/sh", ["-c", `command -v ${name}`], { encoding: "utf-8" });
|
|
25151
25316
|
const found = result.status === 0 ? result.stdout.trim() : "";
|
|
25152
25317
|
return found.startsWith("/") ? found : void 0;
|
|
25153
25318
|
}
|
|
@@ -25155,7 +25320,7 @@ function resolveIdleSweepEnvironment(env = process.env, locate = locateTool) {
|
|
|
25155
25320
|
const docker = locate("docker");
|
|
25156
25321
|
if (!docker)
|
|
25157
25322
|
throw new Error("docker is not on PATH; the idle sweep cannot inspect environments.");
|
|
25158
|
-
const toolDirs = [docker, locate("devsy"), locate("devpod"), process.execPath].filter((tool) => Boolean(tool)).map((tool) =>
|
|
25323
|
+
const toolDirs = [docker, locate("devsy"), locate("devpod"), process.execPath].filter((tool) => Boolean(tool)).map((tool) => import_node_path57.default.dirname(tool));
|
|
25159
25324
|
const environment = {
|
|
25160
25325
|
PATH: [.../* @__PURE__ */ new Set([...toolDirs, ...SYSTEM_PATH])].join(":")
|
|
25161
25326
|
};
|
|
@@ -25173,9 +25338,9 @@ function installIdleSweep(input2) {
|
|
|
25173
25338
|
throw new Error("The idle sweep uses launchd and is only available on macOS.");
|
|
25174
25339
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25175
25340
|
const launchctl = input2.launchctl ?? defaultLaunchctl;
|
|
25176
|
-
const entryPath = input2.entryPath ??
|
|
25177
|
-
|
|
25178
|
-
|
|
25341
|
+
const entryPath = input2.entryPath ?? import_node_fs46.default.realpathSync(process.argv[1]);
|
|
25342
|
+
import_node_fs46.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25343
|
+
import_node_fs46.default.mkdirSync(import_node_path57.default.dirname(paths.plist), { recursive: true });
|
|
25179
25344
|
const contents = renderIdleSweepPlist({
|
|
25180
25345
|
nodePath: process.execPath,
|
|
25181
25346
|
entryPath,
|
|
@@ -25184,7 +25349,7 @@ function installIdleSweep(input2) {
|
|
|
25184
25349
|
logPath: paths.log
|
|
25185
25350
|
});
|
|
25186
25351
|
launchctl(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25187
|
-
|
|
25352
|
+
import_node_fs46.default.writeFileSync(paths.plist, contents, { mode: 420 });
|
|
25188
25353
|
const loaded = launchctl(["bootstrap", launchDomain(), paths.plist]);
|
|
25189
25354
|
if (loaded.status !== 0)
|
|
25190
25355
|
throw new Error(
|
|
@@ -25194,9 +25359,9 @@ function installIdleSweep(input2) {
|
|
|
25194
25359
|
}
|
|
25195
25360
|
function removeIdleSweep(input2 = {}) {
|
|
25196
25361
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25197
|
-
if (!
|
|
25362
|
+
if (!import_node_fs46.default.existsSync(paths.plist)) return false;
|
|
25198
25363
|
(input2.launchctl ?? defaultLaunchctl)(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25199
|
-
|
|
25364
|
+
import_node_fs46.default.rmSync(paths.plist, { force: true });
|
|
25200
25365
|
return true;
|
|
25201
25366
|
}
|
|
25202
25367
|
function summarizeSweep(idleFor, stops, error) {
|
|
@@ -25211,13 +25376,13 @@ function summarizeSweep(idleFor, stops, error) {
|
|
|
25211
25376
|
};
|
|
25212
25377
|
}
|
|
25213
25378
|
function writeLastSweep(record6, paths = idleSweepPaths()) {
|
|
25214
|
-
|
|
25215
|
-
|
|
25379
|
+
import_node_fs46.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25380
|
+
import_node_fs46.default.writeFileSync(paths.lastSweep, `${JSON.stringify(record6, null, 2)}
|
|
25216
25381
|
`, { mode: 384 });
|
|
25217
25382
|
}
|
|
25218
25383
|
function readLastSweep(paths) {
|
|
25219
25384
|
try {
|
|
25220
|
-
return JSON.parse(
|
|
25385
|
+
return JSON.parse(import_node_fs46.default.readFileSync(paths.lastSweep, "utf-8"));
|
|
25221
25386
|
} catch {
|
|
25222
25387
|
return void 0;
|
|
25223
25388
|
}
|
|
@@ -25262,20 +25427,20 @@ function idleSweepCheck(paths = idleSweepPaths(), nowMs = Date.now()) {
|
|
|
25262
25427
|
...stale || last.failed > 0 ? { suggestion: `Inspect: ${paths.log}` } : {}
|
|
25263
25428
|
};
|
|
25264
25429
|
}
|
|
25265
|
-
var
|
|
25430
|
+
var import_node_child_process35, import_node_fs46, import_node_os7, import_node_path57, IDLE_SWEEP_LABEL, SWEEP_INTERVAL_SECONDS, SYSTEM_PATH, defaultLaunchctl;
|
|
25266
25431
|
var init_idle_sweep = __esm({
|
|
25267
25432
|
"src/core/idle-sweep.ts"() {
|
|
25268
25433
|
"use strict";
|
|
25269
|
-
|
|
25270
|
-
|
|
25271
|
-
|
|
25272
|
-
|
|
25434
|
+
import_node_child_process35 = require("child_process");
|
|
25435
|
+
import_node_fs46 = __toESM(require("fs"));
|
|
25436
|
+
import_node_os7 = __toESM(require("os"));
|
|
25437
|
+
import_node_path57 = __toESM(require("path"));
|
|
25273
25438
|
init_router();
|
|
25274
25439
|
IDLE_SWEEP_LABEL = "dev.devrouter.idle-stop";
|
|
25275
25440
|
SWEEP_INTERVAL_SECONDS = 300;
|
|
25276
25441
|
SYSTEM_PATH = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
25277
25442
|
defaultLaunchctl = (args) => {
|
|
25278
|
-
const result = (0,
|
|
25443
|
+
const result = (0, import_node_child_process35.spawnSync)("launchctl", args, { encoding: "utf-8" });
|
|
25279
25444
|
return { status: result.status, stderr: result.stderr || result.error?.message || "" };
|
|
25280
25445
|
};
|
|
25281
25446
|
}
|
|
@@ -25289,7 +25454,7 @@ function outputFromResult(result) {
|
|
|
25289
25454
|
return output2.length > 0 ? output2 : void 0;
|
|
25290
25455
|
}
|
|
25291
25456
|
function runTool(command, args = []) {
|
|
25292
|
-
const result = (0,
|
|
25457
|
+
const result = (0, import_node_child_process36.spawnSync)(command, args, {
|
|
25293
25458
|
encoding: "utf-8"
|
|
25294
25459
|
});
|
|
25295
25460
|
if (result.error) {
|
|
@@ -25346,12 +25511,12 @@ function parseMinimumNodeMajor(value) {
|
|
|
25346
25511
|
return Number(match[1]);
|
|
25347
25512
|
}
|
|
25348
25513
|
function readPackageJson(repoPath) {
|
|
25349
|
-
const packagePath =
|
|
25350
|
-
if (!
|
|
25514
|
+
const packagePath = import_node_path58.default.join(repoPath, "package.json");
|
|
25515
|
+
if (!import_node_fs47.default.existsSync(packagePath)) {
|
|
25351
25516
|
return void 0;
|
|
25352
25517
|
}
|
|
25353
25518
|
try {
|
|
25354
|
-
return JSON.parse(
|
|
25519
|
+
return JSON.parse(import_node_fs47.default.readFileSync(packagePath, "utf-8"));
|
|
25355
25520
|
} catch {
|
|
25356
25521
|
return void 0;
|
|
25357
25522
|
}
|
|
@@ -25456,17 +25621,17 @@ function realpathOrUndefined(value) {
|
|
|
25456
25621
|
return void 0;
|
|
25457
25622
|
}
|
|
25458
25623
|
try {
|
|
25459
|
-
return
|
|
25624
|
+
return import_node_fs47.default.realpathSync(value);
|
|
25460
25625
|
} catch {
|
|
25461
25626
|
return void 0;
|
|
25462
25627
|
}
|
|
25463
25628
|
}
|
|
25464
25629
|
function isExecutableFile(filePath) {
|
|
25465
25630
|
try {
|
|
25466
|
-
if (!
|
|
25631
|
+
if (!import_node_fs47.default.statSync(filePath).isFile()) {
|
|
25467
25632
|
return false;
|
|
25468
25633
|
}
|
|
25469
|
-
|
|
25634
|
+
import_node_fs47.default.accessSync(filePath, import_node_fs47.default.constants.X_OK);
|
|
25470
25635
|
return true;
|
|
25471
25636
|
} catch {
|
|
25472
25637
|
return false;
|
|
@@ -25474,13 +25639,13 @@ function isExecutableFile(filePath) {
|
|
|
25474
25639
|
}
|
|
25475
25640
|
function displayPath(filePath) {
|
|
25476
25641
|
const home = process.env.HOME;
|
|
25477
|
-
if (!home || home.length < 2 || !filePath.startsWith(`${home}${
|
|
25642
|
+
if (!home || home.length < 2 || !filePath.startsWith(`${home}${import_node_path58.default.sep}`)) {
|
|
25478
25643
|
return filePath;
|
|
25479
25644
|
}
|
|
25480
25645
|
return `~${filePath.slice(home.length)}`;
|
|
25481
25646
|
}
|
|
25482
25647
|
function probeInstalledCliVersion(executable) {
|
|
25483
|
-
const result = (0,
|
|
25648
|
+
const result = (0, import_node_child_process36.spawnSync)(executable, ["-V"], {
|
|
25484
25649
|
encoding: "utf-8",
|
|
25485
25650
|
timeout: CLI_PATH_PROBE_TIMEOUT_MS
|
|
25486
25651
|
});
|
|
@@ -25491,7 +25656,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
25491
25656
|
}
|
|
25492
25657
|
function buildCliPathCheck(options = {}) {
|
|
25493
25658
|
const id5 = "global.cli-path";
|
|
25494
|
-
const runningVersion = options.runningVersion ?? (true ? "0.6.
|
|
25659
|
+
const runningVersion = options.runningVersion ?? (true ? "0.6.3" : "0.0.0-dev");
|
|
25495
25660
|
if (runningVersion === "0.0.0-dev") {
|
|
25496
25661
|
return {
|
|
25497
25662
|
id: id5,
|
|
@@ -25504,11 +25669,11 @@ function buildCliPathCheck(options = {}) {
|
|
|
25504
25669
|
const probeVersion = options.probeVersion ?? probeInstalledCliVersion;
|
|
25505
25670
|
const entries = [];
|
|
25506
25671
|
const seen = /* @__PURE__ */ new Set();
|
|
25507
|
-
for (const dir of (options.pathValue ?? process.env.PATH ?? "").split(
|
|
25672
|
+
for (const dir of (options.pathValue ?? process.env.PATH ?? "").split(import_node_path58.default.delimiter)) {
|
|
25508
25673
|
if (dir.length === 0) {
|
|
25509
25674
|
continue;
|
|
25510
25675
|
}
|
|
25511
|
-
const executable =
|
|
25676
|
+
const executable = import_node_path58.default.join(dir, "devrouter");
|
|
25512
25677
|
if (!isExecutableFile(executable)) {
|
|
25513
25678
|
continue;
|
|
25514
25679
|
}
|
|
@@ -25665,13 +25830,13 @@ function buildGlobalToolChecksWithoutTelemetry(repoPath) {
|
|
|
25665
25830
|
checks.push(nodeToolchainCheck(repoPath));
|
|
25666
25831
|
return checks;
|
|
25667
25832
|
}
|
|
25668
|
-
var
|
|
25833
|
+
var import_node_child_process36, import_node_fs47, import_node_path58, DEVSY_DISABLE_TELEMETRY, CLI_PATH_PROBE_TIMEOUT_MS, INSTALLED_CLI_VERSION_RE;
|
|
25669
25834
|
var init_tool_diagnostics = __esm({
|
|
25670
25835
|
"src/core/tool-diagnostics.ts"() {
|
|
25671
25836
|
"use strict";
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25837
|
+
import_node_child_process36 = require("child_process");
|
|
25838
|
+
import_node_fs47 = __toESM(require("fs"));
|
|
25839
|
+
import_node_path58 = __toESM(require("path"));
|
|
25675
25840
|
init_devsy_agent();
|
|
25676
25841
|
init_idle_sweep();
|
|
25677
25842
|
init_repo_config();
|
|
@@ -25692,10 +25857,10 @@ function inRepositoryWorkspaceScope(repoPath, worktreePath, livePaths) {
|
|
|
25692
25857
|
if (livePaths.some((candidate) => sameWorkspacePath(candidate, worktreePath))) return true;
|
|
25693
25858
|
const comparableRepo = comparableWorkspacePath(repoPath);
|
|
25694
25859
|
const comparableWorktree = comparableWorkspacePath(worktreePath);
|
|
25695
|
-
const localRoot =
|
|
25860
|
+
const localRoot = import_node_path59.default.join(comparableRepo, "trees") + import_node_path59.default.sep;
|
|
25696
25861
|
if (comparableWorktree.startsWith(localRoot)) return true;
|
|
25697
|
-
const legacyPrefix = `${
|
|
25698
|
-
return
|
|
25862
|
+
const legacyPrefix = `${import_node_path59.default.basename(comparableRepo)}-`;
|
|
25863
|
+
return import_node_path59.default.dirname(comparableWorktree) === import_node_path59.default.dirname(comparableRepo) && import_node_path59.default.basename(comparableWorktree).startsWith(legacyPrefix);
|
|
25699
25864
|
}
|
|
25700
25865
|
function previewActions(devpodStatus, routeCount, includeRecord) {
|
|
25701
25866
|
const actions = [
|
|
@@ -25947,11 +26112,11 @@ function applyWorkspaceGc(plan) {
|
|
|
25947
26112
|
candidates
|
|
25948
26113
|
};
|
|
25949
26114
|
}
|
|
25950
|
-
var
|
|
26115
|
+
var import_node_path59;
|
|
25951
26116
|
var init_workspace_gc = __esm({
|
|
25952
26117
|
"src/core/workspace-gc.ts"() {
|
|
25953
26118
|
"use strict";
|
|
25954
|
-
|
|
26119
|
+
import_node_path59 = __toESM(require("path"));
|
|
25955
26120
|
init_devpod_mutation();
|
|
25956
26121
|
init_devpod_workspaces();
|
|
25957
26122
|
init_host_routes();
|
|
@@ -26021,12 +26186,12 @@ function inspectPostgresCredentials(repoPath, config) {
|
|
|
26021
26186
|
parseErrors.push(`${app.name}: ${composeFile} (${message})`);
|
|
26022
26187
|
continue;
|
|
26023
26188
|
}
|
|
26024
|
-
if (!
|
|
26189
|
+
if (!import_node_fs48.default.existsSync(absolutePath)) {
|
|
26025
26190
|
continue;
|
|
26026
26191
|
}
|
|
26027
26192
|
try {
|
|
26028
|
-
const raw =
|
|
26029
|
-
const parsed =
|
|
26193
|
+
const raw = import_node_fs48.default.readFileSync(absolutePath, "utf-8");
|
|
26194
|
+
const parsed = import_yaml7.default.parse(raw);
|
|
26030
26195
|
const root = asRecord2(parsed);
|
|
26031
26196
|
const services = asRecord2(root?.services);
|
|
26032
26197
|
const service = asRecord2(services?.[app.docker.service]);
|
|
@@ -26389,7 +26554,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26389
26554
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
26390
26555
|
});
|
|
26391
26556
|
}
|
|
26392
|
-
const cliVersion = true ? "0.6.
|
|
26557
|
+
const cliVersion = true ? "0.6.3" : "0.0.0-dev";
|
|
26393
26558
|
const configVersion = config.devrouter?.version;
|
|
26394
26559
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
26395
26560
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -26425,9 +26590,9 @@ async function buildDoctorReport(options = {}) {
|
|
|
26425
26590
|
(app) => app.docker.composeFiles.map((filePath) => ({
|
|
26426
26591
|
app: app.name,
|
|
26427
26592
|
filePath,
|
|
26428
|
-
absolutePath:
|
|
26593
|
+
absolutePath: import_node_path60.default.resolve(repo.path, filePath)
|
|
26429
26594
|
}))
|
|
26430
|
-
).filter((entry) => !
|
|
26595
|
+
).filter((entry) => !import_node_fs48.default.existsSync(entry.absolutePath));
|
|
26431
26596
|
addCheck(checks, {
|
|
26432
26597
|
id: "repo.compose-files",
|
|
26433
26598
|
level: missingComposeFiles.length === 0 ? "ok" : "error",
|
|
@@ -26470,8 +26635,8 @@ async function buildDoctorReport(options = {}) {
|
|
|
26470
26635
|
const missingHostCwds = config.apps.filter((app) => app.runtime === "host").map((app) => ({
|
|
26471
26636
|
app: app.name,
|
|
26472
26637
|
cwd: app.hostRun.cwd,
|
|
26473
|
-
absolutePath:
|
|
26474
|
-
})).filter((entry) => !
|
|
26638
|
+
absolutePath: import_node_path60.default.resolve(repo.path, app.hostRun.cwd)
|
|
26639
|
+
})).filter((entry) => !import_node_fs48.default.existsSync(entry.absolutePath));
|
|
26475
26640
|
addCheck(checks, {
|
|
26476
26641
|
id: "repo.host-cwd",
|
|
26477
26642
|
level: missingHostCwds.length === 0 ? "ok" : "error",
|
|
@@ -26615,13 +26780,13 @@ async function buildDoctorReport(options = {}) {
|
|
|
26615
26780
|
nextSteps
|
|
26616
26781
|
};
|
|
26617
26782
|
}
|
|
26618
|
-
var
|
|
26783
|
+
var import_node_fs48, import_node_path60, import_yaml7, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
|
|
26619
26784
|
var init_doctor = __esm({
|
|
26620
26785
|
"src/core/doctor.ts"() {
|
|
26621
26786
|
"use strict";
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26787
|
+
import_node_fs48 = __toESM(require("fs"));
|
|
26788
|
+
import_node_path60 = __toESM(require("path"));
|
|
26789
|
+
import_yaml7 = __toESM(require("yaml"));
|
|
26625
26790
|
init_capacity_store();
|
|
26626
26791
|
init_docker();
|
|
26627
26792
|
init_host_routes();
|
|
@@ -27016,12 +27181,12 @@ function parseSsPortListeners(stdout, port) {
|
|
|
27016
27181
|
return listeners;
|
|
27017
27182
|
}
|
|
27018
27183
|
function findPortListeners(port) {
|
|
27019
|
-
const result = (0,
|
|
27184
|
+
const result = (0, import_node_child_process37.spawnSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
|
|
27020
27185
|
encoding: "utf-8"
|
|
27021
27186
|
});
|
|
27022
27187
|
if (result.error && result.error.code === "ENOENT") {
|
|
27023
27188
|
if (process.platform === "linux") {
|
|
27024
|
-
const ssResult = (0,
|
|
27189
|
+
const ssResult = (0, import_node_child_process37.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
27025
27190
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
27026
27191
|
return parseSsPortListeners(ssResult.stdout, port);
|
|
27027
27192
|
}
|
|
@@ -27050,11 +27215,11 @@ function findPortListeners(port) {
|
|
|
27050
27215
|
};
|
|
27051
27216
|
});
|
|
27052
27217
|
}
|
|
27053
|
-
var
|
|
27218
|
+
var import_node_child_process37;
|
|
27054
27219
|
var init_ports = __esm({
|
|
27055
27220
|
"src/util/ports.ts"() {
|
|
27056
27221
|
"use strict";
|
|
27057
|
-
|
|
27222
|
+
import_node_child_process37 = require("child_process");
|
|
27058
27223
|
}
|
|
27059
27224
|
});
|
|
27060
27225
|
|
|
@@ -27140,6 +27305,7 @@ async function runEnsureCommand(options) {
|
|
|
27140
27305
|
quiet: Boolean(options.json),
|
|
27141
27306
|
profile: options.profile,
|
|
27142
27307
|
...options.repair ? { repair: true } : {},
|
|
27308
|
+
...options.initializeNew ? { initializeNew: true } : {},
|
|
27143
27309
|
...options.variant !== void 0 ? { variant: options.variant } : {}
|
|
27144
27310
|
};
|
|
27145
27311
|
const result = await superviseLifecycle(
|
|
@@ -27327,7 +27493,7 @@ function resolveLoopback(app, repoPath, evidence) {
|
|
|
27327
27493
|
if (!evidence.containers) {
|
|
27328
27494
|
return { loopback: null, loopbackReason: "unavailable" };
|
|
27329
27495
|
}
|
|
27330
|
-
const devcontainerDir =
|
|
27496
|
+
const devcontainerDir = import_node_path61.default.join(repoPath, ".devcontainer");
|
|
27331
27497
|
const owners = evidence.containers.filter(
|
|
27332
27498
|
(container) => sameWorkspacePath(
|
|
27333
27499
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
@@ -27387,13 +27553,13 @@ function buildHostEnvReport(input2) {
|
|
|
27387
27553
|
};
|
|
27388
27554
|
}
|
|
27389
27555
|
function listDevcontainerContainers(repoPath) {
|
|
27390
|
-
const listed = (0,
|
|
27556
|
+
const listed = (0, import_node_child_process38.spawnSync)(
|
|
27391
27557
|
"docker",
|
|
27392
27558
|
[
|
|
27393
27559
|
"ps",
|
|
27394
27560
|
"-a",
|
|
27395
27561
|
"--filter",
|
|
27396
|
-
`label=com.docker.compose.project.working_dir=${
|
|
27562
|
+
`label=com.docker.compose.project.working_dir=${import_node_path61.default.join(repoPath, ".devcontainer")}`,
|
|
27397
27563
|
"--format",
|
|
27398
27564
|
"{{.ID}}"
|
|
27399
27565
|
],
|
|
@@ -27408,7 +27574,7 @@ function listDevcontainerContainers(repoPath) {
|
|
|
27408
27574
|
}
|
|
27409
27575
|
}
|
|
27410
27576
|
function dockerPortBindings(containerId, port) {
|
|
27411
|
-
const result = (0,
|
|
27577
|
+
const result = (0, import_node_child_process38.spawnSync)("docker", ["port", containerId, `${port}/tcp`], {
|
|
27412
27578
|
encoding: "utf-8",
|
|
27413
27579
|
...networkDockerOptions()
|
|
27414
27580
|
});
|
|
@@ -27523,12 +27689,12 @@ function hostEnvVariables(report, processEnv) {
|
|
|
27523
27689
|
}
|
|
27524
27690
|
return variables;
|
|
27525
27691
|
}
|
|
27526
|
-
var
|
|
27692
|
+
var import_node_child_process38, import_node_path61, LOOPBACK_UPSTREAM_HOSTS, ROUTED_TCP_PARAMS;
|
|
27527
27693
|
var init_host_env = __esm({
|
|
27528
27694
|
"src/core/host-env.ts"() {
|
|
27529
27695
|
"use strict";
|
|
27530
|
-
|
|
27531
|
-
|
|
27696
|
+
import_node_child_process38 = require("child_process");
|
|
27697
|
+
import_node_path61 = __toESM(require("path"));
|
|
27532
27698
|
init_devcontainer_profile();
|
|
27533
27699
|
init_devpod_environment();
|
|
27534
27700
|
init_docker();
|
|
@@ -27625,7 +27791,7 @@ function hostCommandEnvironment(report, processEnv) {
|
|
|
27625
27791
|
}
|
|
27626
27792
|
function runHostCommand(command, env) {
|
|
27627
27793
|
return new Promise((resolve) => {
|
|
27628
|
-
const child = (0,
|
|
27794
|
+
const child = (0, import_node_child_process39.spawn)(command[0], command.slice(1), { env, stdio: "inherit" });
|
|
27629
27795
|
const forward = (signal) => () => child.kill(signal);
|
|
27630
27796
|
const handlers = [
|
|
27631
27797
|
["SIGINT", forward("SIGINT")],
|
|
@@ -27645,7 +27811,7 @@ function runHostCommand(command, env) {
|
|
|
27645
27811
|
settle(error.code === "ENOENT" ? 127 : 126);
|
|
27646
27812
|
});
|
|
27647
27813
|
child.on("exit", (code, signal) => {
|
|
27648
|
-
settle(code ?? 128 + (signal ?
|
|
27814
|
+
settle(code ?? 128 + (signal ? import_node_os8.constants.signals[signal] ?? 0 : 0));
|
|
27649
27815
|
});
|
|
27650
27816
|
});
|
|
27651
27817
|
}
|
|
@@ -27665,12 +27831,12 @@ async function runEnvCommand(invocation) {
|
|
|
27665
27831
|
}
|
|
27666
27832
|
process.stdout.write(formatEnvReport(report));
|
|
27667
27833
|
}
|
|
27668
|
-
var
|
|
27834
|
+
var import_node_child_process39, import_node_os8, HOST_PORT_ENV_PREFIX;
|
|
27669
27835
|
var init_env = __esm({
|
|
27670
27836
|
"src/commands/env.ts"() {
|
|
27671
27837
|
"use strict";
|
|
27672
|
-
|
|
27673
|
-
|
|
27838
|
+
import_node_child_process39 = require("child_process");
|
|
27839
|
+
import_node_os8 = require("os");
|
|
27674
27840
|
init_host_env();
|
|
27675
27841
|
init_managed_host_ports();
|
|
27676
27842
|
init_output();
|
|
@@ -27719,8 +27885,8 @@ var init_status2 = __esm({
|
|
|
27719
27885
|
|
|
27720
27886
|
// src/core/harness-continuation.ts
|
|
27721
27887
|
function harnessContinuationPath(repoRoot) {
|
|
27722
|
-
const key = (0,
|
|
27723
|
-
return
|
|
27888
|
+
const key = (0, import_node_crypto30.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
|
|
27889
|
+
return import_node_path62.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
|
|
27724
27890
|
}
|
|
27725
27891
|
function counter4(value) {
|
|
27726
27892
|
return Number.isSafeInteger(value) && value >= 0;
|
|
@@ -27733,7 +27899,7 @@ function validEntry(value) {
|
|
|
27733
27899
|
function readLedgerSync(file, nowMs) {
|
|
27734
27900
|
let stat;
|
|
27735
27901
|
try {
|
|
27736
|
-
stat =
|
|
27902
|
+
stat = import_node_fs49.default.lstatSync(file);
|
|
27737
27903
|
} catch {
|
|
27738
27904
|
return [];
|
|
27739
27905
|
}
|
|
@@ -27741,7 +27907,7 @@ function readLedgerSync(file, nowMs) {
|
|
|
27741
27907
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0) return [];
|
|
27742
27908
|
let parsed;
|
|
27743
27909
|
try {
|
|
27744
|
-
parsed = JSON.parse(
|
|
27910
|
+
parsed = JSON.parse(import_node_fs49.default.readFileSync(file, "utf-8"));
|
|
27745
27911
|
} catch {
|
|
27746
27912
|
return [];
|
|
27747
27913
|
}
|
|
@@ -27761,7 +27927,7 @@ function claimHarnessContinuation(repoRoot, claim2) {
|
|
|
27761
27927
|
const nowMs = claim2.nowMs ?? Date.now();
|
|
27762
27928
|
try {
|
|
27763
27929
|
const file = harnessContinuationPath(repoRoot);
|
|
27764
|
-
|
|
27930
|
+
import_node_fs49.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27765
27931
|
return withFileLockSync(
|
|
27766
27932
|
`${file}.lock`,
|
|
27767
27933
|
{ activity: "harness continuation claim", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27793,7 +27959,7 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27793
27959
|
const nowMs = settlement.nowMs ?? Date.now();
|
|
27794
27960
|
try {
|
|
27795
27961
|
const file = harnessContinuationPath(repoRoot);
|
|
27796
|
-
|
|
27962
|
+
import_node_fs49.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27797
27963
|
withFileLockSync(
|
|
27798
27964
|
`${file}.lock`,
|
|
27799
27965
|
{ activity: "harness continuation settlement", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27817,13 +27983,13 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27817
27983
|
} catch {
|
|
27818
27984
|
}
|
|
27819
27985
|
}
|
|
27820
|
-
var
|
|
27986
|
+
var import_node_crypto30, import_node_fs49, 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;
|
|
27821
27987
|
var init_harness_continuation = __esm({
|
|
27822
27988
|
"src/core/harness-continuation.ts"() {
|
|
27823
27989
|
"use strict";
|
|
27824
|
-
|
|
27825
|
-
|
|
27826
|
-
|
|
27990
|
+
import_node_crypto30 = require("crypto");
|
|
27991
|
+
import_node_fs49 = __toESM(require("fs"));
|
|
27992
|
+
import_node_path62 = __toESM(require("path"));
|
|
27827
27993
|
init_atomic_file();
|
|
27828
27994
|
init_file_lock();
|
|
27829
27995
|
init_router();
|
|
@@ -27842,12 +28008,12 @@ function isTransitionalHarnessPhase(phase) {
|
|
|
27842
28008
|
return TRANSITIONAL_PHASES.includes(phase);
|
|
27843
28009
|
}
|
|
27844
28010
|
function findHarnessGateRepoRoot(cwd) {
|
|
27845
|
-
let current =
|
|
28011
|
+
let current = import_node_path63.default.resolve(cwd);
|
|
27846
28012
|
for (let depth = 0; depth < REPO_ROOT_MAX_DEPTH; depth += 1) {
|
|
27847
|
-
if (
|
|
28013
|
+
if (import_node_fs50.default.existsSync(import_node_path63.default.join(current, ".devrouter.yml"))) {
|
|
27848
28014
|
return current;
|
|
27849
28015
|
}
|
|
27850
|
-
const parent =
|
|
28016
|
+
const parent = import_node_path63.default.dirname(current);
|
|
27851
28017
|
if (parent === current) {
|
|
27852
28018
|
return void 0;
|
|
27853
28019
|
}
|
|
@@ -27939,12 +28105,12 @@ function parseHarnessGateBudget(value) {
|
|
|
27939
28105
|
}
|
|
27940
28106
|
return Math.min(Math.trunc(parsed), HARNESS_GATE_MAX_BUDGET_MS);
|
|
27941
28107
|
}
|
|
27942
|
-
var
|
|
28108
|
+
var import_node_fs50, import_node_path63, HARNESS_GATE_DEFAULT_BUDGET_MS, HARNESS_GATE_MAX_BUDGET_MS, HARNESS_GATE_POLL_INTERVAL_MS, TRANSITIONAL_PHASES, REPO_ROOT_MAX_DEPTH;
|
|
27943
28109
|
var init_harness_gate = __esm({
|
|
27944
28110
|
"src/core/harness-gate.ts"() {
|
|
27945
28111
|
"use strict";
|
|
27946
|
-
|
|
27947
|
-
|
|
28112
|
+
import_node_fs50 = __toESM(require("fs"));
|
|
28113
|
+
import_node_path63 = __toESM(require("path"));
|
|
27948
28114
|
init_reliability_operation_store();
|
|
27949
28115
|
init_workspace();
|
|
27950
28116
|
init_workspace_runtime();
|
|
@@ -28203,7 +28369,7 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28203
28369
|
}
|
|
28204
28370
|
const budgetMs = parseHarnessGateBudget(options.waitBudgetMs);
|
|
28205
28371
|
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;
|
|
28206
|
-
const payloadSha256 = (0,
|
|
28372
|
+
const payloadSha256 = (0, import_node_crypto31.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
|
|
28207
28373
|
const claim2 = dependencies.claim ?? ((root, input2) => {
|
|
28208
28374
|
const outcome = claimHarnessContinuation(root, input2);
|
|
28209
28375
|
if (outcome.kind === "claimed") {
|
|
@@ -28311,11 +28477,11 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28311
28477
|
`
|
|
28312
28478
|
);
|
|
28313
28479
|
}
|
|
28314
|
-
var
|
|
28480
|
+
var import_node_crypto31, MAX_HOOK_PAYLOAD_BYTES, STDIN_TIMEOUT_MS, MAX_TOOL_USE_ID_LENGTH2, DEVROUTER_EXECUTABLES, LAUNCHER_WORDS, LAUNCHER_SUBCOMMANDS, COMMAND_WORD_LIMIT;
|
|
28315
28481
|
var init_harness = __esm({
|
|
28316
28482
|
"src/commands/harness.ts"() {
|
|
28317
28483
|
"use strict";
|
|
28318
|
-
|
|
28484
|
+
import_node_crypto31 = require("crypto");
|
|
28319
28485
|
init_harness_continuation();
|
|
28320
28486
|
init_harness_gate();
|
|
28321
28487
|
MAX_HOOK_PAYLOAD_BYTES = 256 * 1024;
|
|
@@ -28431,7 +28597,7 @@ async function runOpenCommand(name) {
|
|
|
28431
28597
|
);
|
|
28432
28598
|
return;
|
|
28433
28599
|
}
|
|
28434
|
-
const result = (0,
|
|
28600
|
+
const result = (0, import_node_child_process40.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
28435
28601
|
if (result.status !== 0) {
|
|
28436
28602
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
28437
28603
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -28439,11 +28605,11 @@ async function runOpenCommand(name) {
|
|
|
28439
28605
|
process.stdout.write(`Opened ${url}
|
|
28440
28606
|
`);
|
|
28441
28607
|
}
|
|
28442
|
-
var
|
|
28608
|
+
var import_node_child_process40;
|
|
28443
28609
|
var init_open = __esm({
|
|
28444
28610
|
"src/commands/open.ts"() {
|
|
28445
28611
|
"use strict";
|
|
28446
|
-
|
|
28612
|
+
import_node_child_process40 = require("child_process");
|
|
28447
28613
|
init_docker();
|
|
28448
28614
|
init_host_routes();
|
|
28449
28615
|
init_repo_config();
|
|
@@ -28487,7 +28653,7 @@ async function runLogsCommand(options) {
|
|
|
28487
28653
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
28488
28654
|
if (options.follow) {
|
|
28489
28655
|
args.splice(1, 0, "-f");
|
|
28490
|
-
const child = (0,
|
|
28656
|
+
const child = (0, import_node_child_process41.spawn)("docker", args, { stdio: "inherit" });
|
|
28491
28657
|
const onSignal = () => {
|
|
28492
28658
|
child.kill("SIGTERM");
|
|
28493
28659
|
};
|
|
@@ -28501,17 +28667,17 @@ async function runLogsCommand(options) {
|
|
|
28501
28667
|
});
|
|
28502
28668
|
});
|
|
28503
28669
|
} else {
|
|
28504
|
-
const result = (0,
|
|
28670
|
+
const result = (0, import_node_child_process41.spawnSync)("docker", args, { stdio: "inherit" });
|
|
28505
28671
|
if (result.status !== 0) {
|
|
28506
28672
|
throw new Error("Failed to retrieve router logs.");
|
|
28507
28673
|
}
|
|
28508
28674
|
}
|
|
28509
28675
|
}
|
|
28510
|
-
var
|
|
28676
|
+
var import_node_child_process41;
|
|
28511
28677
|
var init_logs = __esm({
|
|
28512
28678
|
"src/commands/logs.ts"() {
|
|
28513
28679
|
"use strict";
|
|
28514
|
-
|
|
28680
|
+
import_node_child_process41 = require("child_process");
|
|
28515
28681
|
init_docker();
|
|
28516
28682
|
init_lifecycle_diagnostics();
|
|
28517
28683
|
init_router();
|
|
@@ -28555,17 +28721,17 @@ function asRecord3(value) {
|
|
|
28555
28721
|
return value;
|
|
28556
28722
|
}
|
|
28557
28723
|
function readJson(filePath) {
|
|
28558
|
-
if (!
|
|
28724
|
+
if (!import_node_fs51.default.existsSync(filePath)) {
|
|
28559
28725
|
return void 0;
|
|
28560
28726
|
}
|
|
28561
28727
|
try {
|
|
28562
|
-
return JSON.parse(
|
|
28728
|
+
return JSON.parse(import_node_fs51.default.readFileSync(filePath, "utf-8"));
|
|
28563
28729
|
} catch {
|
|
28564
28730
|
return void 0;
|
|
28565
28731
|
}
|
|
28566
28732
|
}
|
|
28567
28733
|
function relative(repoPath, filePath) {
|
|
28568
|
-
return
|
|
28734
|
+
return import_node_path64.default.relative(repoPath, filePath) || ".";
|
|
28569
28735
|
}
|
|
28570
28736
|
function redactEnvAssignments(value) {
|
|
28571
28737
|
return value.replace(
|
|
@@ -28606,7 +28772,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
28606
28772
|
["bun.lock", "bun"]
|
|
28607
28773
|
];
|
|
28608
28774
|
for (const [fileName, name] of lockfiles) {
|
|
28609
|
-
if (
|
|
28775
|
+
if (import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28610
28776
|
return { name, source: fileName };
|
|
28611
28777
|
}
|
|
28612
28778
|
}
|
|
@@ -28621,9 +28787,9 @@ function inspectNode(repoPath, pkg) {
|
|
|
28621
28787
|
if (typeof engines?.node === "string") {
|
|
28622
28788
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
28623
28789
|
}
|
|
28624
|
-
const nvmrc =
|
|
28625
|
-
if (
|
|
28626
|
-
const version =
|
|
28790
|
+
const nvmrc = import_node_path64.default.join(repoPath, ".nvmrc");
|
|
28791
|
+
if (import_node_fs51.default.existsSync(nvmrc)) {
|
|
28792
|
+
const version = import_node_fs51.default.readFileSync(nvmrc, "utf-8").trim();
|
|
28627
28793
|
return { version, source: ".nvmrc" };
|
|
28628
28794
|
}
|
|
28629
28795
|
return void 0;
|
|
@@ -28684,7 +28850,7 @@ function configuredComposeFiles(repoPath) {
|
|
|
28684
28850
|
const files = config.apps.filter(
|
|
28685
28851
|
(app) => app.runtime === "docker"
|
|
28686
28852
|
).flatMap((app) => app.docker.composeFiles).filter(
|
|
28687
|
-
(fileName) => !
|
|
28853
|
+
(fileName) => !import_node_path64.default.isAbsolute(fileName) && !import_node_path64.default.normalize(fileName).startsWith("..")
|
|
28688
28854
|
);
|
|
28689
28855
|
return Array.from(new Set(files));
|
|
28690
28856
|
} catch {
|
|
@@ -28702,7 +28868,7 @@ function composeFiles(repoPath) {
|
|
|
28702
28868
|
...configuredComposeFiles(repoPath)
|
|
28703
28869
|
];
|
|
28704
28870
|
return Array.from(new Set(candidates)).filter(
|
|
28705
|
-
(fileName) =>
|
|
28871
|
+
(fileName) => import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))
|
|
28706
28872
|
);
|
|
28707
28873
|
}
|
|
28708
28874
|
function stringArray2(value) {
|
|
@@ -28740,7 +28906,7 @@ function inspectServices(repoPath) {
|
|
|
28740
28906
|
const services = [];
|
|
28741
28907
|
for (const fileName of composeFiles(repoPath)) {
|
|
28742
28908
|
try {
|
|
28743
|
-
const parsed =
|
|
28909
|
+
const parsed = import_yaml8.default.parse(import_node_fs51.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8"));
|
|
28744
28910
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
28745
28911
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
28746
28912
|
const service = asRecord3(value);
|
|
@@ -28775,8 +28941,8 @@ function inspectServices(repoPath) {
|
|
|
28775
28941
|
return services;
|
|
28776
28942
|
}
|
|
28777
28943
|
function inspectEnvFiles(repoPath) {
|
|
28778
|
-
const files =
|
|
28779
|
-
const content =
|
|
28944
|
+
const files = import_node_fs51.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
28945
|
+
const content = import_node_fs51.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8");
|
|
28780
28946
|
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();
|
|
28781
28947
|
return { path: fileName, names };
|
|
28782
28948
|
});
|
|
@@ -28790,18 +28956,18 @@ function inspectEnvFiles(repoPath) {
|
|
|
28790
28956
|
};
|
|
28791
28957
|
}
|
|
28792
28958
|
function inspectDevcontainer(repoPath) {
|
|
28793
|
-
const dir =
|
|
28794
|
-
if (!
|
|
28959
|
+
const dir = import_node_path64.default.join(repoPath, ".devcontainer");
|
|
28960
|
+
if (!import_node_fs51.default.existsSync(dir)) {
|
|
28795
28961
|
return { exists: false, files: [] };
|
|
28796
28962
|
}
|
|
28797
28963
|
return {
|
|
28798
28964
|
exists: true,
|
|
28799
|
-
files:
|
|
28965
|
+
files: import_node_fs51.default.readdirSync(dir).filter((fileName) => import_node_fs51.default.statSync(import_node_path64.default.join(dir, fileName)).isFile()).sort().map((fileName) => `.devcontainer/${fileName}`)
|
|
28800
28966
|
};
|
|
28801
28967
|
}
|
|
28802
28968
|
function inspectDevrouter(repoPath) {
|
|
28803
28969
|
const configPath = getRepoConfigPath(repoPath);
|
|
28804
|
-
if (!
|
|
28970
|
+
if (!import_node_fs51.default.existsSync(configPath)) {
|
|
28805
28971
|
return {
|
|
28806
28972
|
exists: false,
|
|
28807
28973
|
configPath,
|
|
@@ -28845,15 +29011,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
28845
29011
|
["AGENTS.md", "agents"],
|
|
28846
29012
|
["CLAUDE.md", "claude"]
|
|
28847
29013
|
]) {
|
|
28848
|
-
if (
|
|
29014
|
+
if (import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28849
29015
|
results.push({ path: fileName, kind });
|
|
28850
29016
|
}
|
|
28851
29017
|
}
|
|
28852
|
-
const skillsDir =
|
|
28853
|
-
if (
|
|
28854
|
-
for (const name of
|
|
28855
|
-
const skillPath =
|
|
28856
|
-
if (
|
|
29018
|
+
const skillsDir = import_node_path64.default.join(repoPath, ".agents", "skills");
|
|
29019
|
+
if (import_node_fs51.default.existsSync(skillsDir)) {
|
|
29020
|
+
for (const name of import_node_fs51.default.readdirSync(skillsDir).sort()) {
|
|
29021
|
+
const skillPath = import_node_path64.default.join(skillsDir, name, "SKILL.md");
|
|
29022
|
+
if (import_node_fs51.default.existsSync(skillPath)) {
|
|
28857
29023
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
28858
29024
|
}
|
|
28859
29025
|
}
|
|
@@ -28896,7 +29062,7 @@ function buildIssues(report) {
|
|
|
28896
29062
|
}
|
|
28897
29063
|
function inspectRepo(options = {}) {
|
|
28898
29064
|
const repoPath = resolveRepoPath(options.repo);
|
|
28899
|
-
const pkg = readJson(
|
|
29065
|
+
const pkg = readJson(import_node_path64.default.join(repoPath, "package.json"));
|
|
28900
29066
|
const scripts = inspectScripts(pkg);
|
|
28901
29067
|
const reportWithoutIssues = {
|
|
28902
29068
|
repoPath,
|
|
@@ -28915,13 +29081,13 @@ function inspectRepo(options = {}) {
|
|
|
28915
29081
|
issues: buildIssues(reportWithoutIssues)
|
|
28916
29082
|
};
|
|
28917
29083
|
}
|
|
28918
|
-
var
|
|
29084
|
+
var import_node_fs51, import_node_path64, import_yaml8;
|
|
28919
29085
|
var init_repo_inspect = __esm({
|
|
28920
29086
|
"src/core/repo-inspect.ts"() {
|
|
28921
29087
|
"use strict";
|
|
28922
|
-
|
|
28923
|
-
|
|
28924
|
-
|
|
29088
|
+
import_node_fs51 = __toESM(require("fs"));
|
|
29089
|
+
import_node_path64 = __toESM(require("path"));
|
|
29090
|
+
import_yaml8 = __toESM(require("yaml"));
|
|
28925
29091
|
init_repo_config();
|
|
28926
29092
|
}
|
|
28927
29093
|
});
|
|
@@ -29025,7 +29191,7 @@ function requiredFileChecks(repoPath) {
|
|
|
29025
29191
|
".devcontainer/docker-compose.yml",
|
|
29026
29192
|
".devrouter.yml"
|
|
29027
29193
|
];
|
|
29028
|
-
const missing = required.filter((fileName) => !
|
|
29194
|
+
const missing = required.filter((fileName) => !import_node_fs52.default.existsSync(import_node_path65.default.join(repoPath, fileName)));
|
|
29029
29195
|
return {
|
|
29030
29196
|
id: "repo.devcontainer.verify-files",
|
|
29031
29197
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -29250,12 +29416,12 @@ async function verifyDevcontainer(options = {}) {
|
|
|
29250
29416
|
nextSteps: collectNextSteps3(checks)
|
|
29251
29417
|
};
|
|
29252
29418
|
}
|
|
29253
|
-
var
|
|
29419
|
+
var import_node_fs52, import_node_path65;
|
|
29254
29420
|
var init_devcontainer_verify = __esm({
|
|
29255
29421
|
"src/core/devcontainer-verify.ts"() {
|
|
29256
29422
|
"use strict";
|
|
29257
|
-
|
|
29258
|
-
|
|
29423
|
+
import_node_fs52 = __toESM(require("fs"));
|
|
29424
|
+
import_node_path65 = __toESM(require("path"));
|
|
29259
29425
|
init_capabilities();
|
|
29260
29426
|
init_doctor();
|
|
29261
29427
|
init_host_routes();
|
|
@@ -29552,7 +29718,7 @@ function packageManagerIssues(repo) {
|
|
|
29552
29718
|
}
|
|
29553
29719
|
function plannedFiles(repoPath, version) {
|
|
29554
29720
|
const repo = inspectRepo({ repo: repoPath });
|
|
29555
|
-
const projectName = sanitizeProjectName(
|
|
29721
|
+
const projectName = sanitizeProjectName(import_node_path66.default.basename(repo.repoPath));
|
|
29556
29722
|
const nodeMajor = majorVersion(repo.node?.version, "24");
|
|
29557
29723
|
const pnpmVersion = repo.packageManager?.name === "pnpm" && repo.packageManager.version ? repo.packageManager.version : DEFAULT_PNPM_VERSION;
|
|
29558
29724
|
const port = inferPort2(repo);
|
|
@@ -29597,8 +29763,8 @@ function plannedFiles(repoPath, version) {
|
|
|
29597
29763
|
};
|
|
29598
29764
|
}
|
|
29599
29765
|
function classifyFile(repoPath, file) {
|
|
29600
|
-
const absolutePath =
|
|
29601
|
-
if (!
|
|
29766
|
+
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29767
|
+
if (!import_node_fs53.default.existsSync(absolutePath)) {
|
|
29602
29768
|
return {
|
|
29603
29769
|
path: file.relativePath,
|
|
29604
29770
|
action: "create",
|
|
@@ -29606,7 +29772,7 @@ function classifyFile(repoPath, file) {
|
|
|
29606
29772
|
bytes: Buffer.byteLength(file.content)
|
|
29607
29773
|
};
|
|
29608
29774
|
}
|
|
29609
|
-
const current =
|
|
29775
|
+
const current = import_node_fs53.default.readFileSync(absolutePath, "utf-8");
|
|
29610
29776
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
29611
29777
|
return {
|
|
29612
29778
|
path: file.relativePath,
|
|
@@ -29663,11 +29829,11 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
29663
29829
|
};
|
|
29664
29830
|
}
|
|
29665
29831
|
function writeFile(repoPath, file) {
|
|
29666
|
-
const absolutePath =
|
|
29667
|
-
|
|
29668
|
-
|
|
29832
|
+
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29833
|
+
import_node_fs53.default.mkdirSync(import_node_path66.default.dirname(absolutePath), { recursive: true });
|
|
29834
|
+
import_node_fs53.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
29669
29835
|
if (file.executable) {
|
|
29670
|
-
|
|
29836
|
+
import_node_fs53.default.chmodSync(absolutePath, 493);
|
|
29671
29837
|
}
|
|
29672
29838
|
}
|
|
29673
29839
|
function writeDevcontainer(options = {}) {
|
|
@@ -29705,12 +29871,12 @@ function writeDevcontainer(options = {}) {
|
|
|
29705
29871
|
nextSteps: postWriteNextSteps(repoPath)
|
|
29706
29872
|
};
|
|
29707
29873
|
}
|
|
29708
|
-
var
|
|
29874
|
+
var import_node_fs53, import_node_path66, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
29709
29875
|
var init_devcontainer_write = __esm({
|
|
29710
29876
|
"src/core/devcontainer-write.ts"() {
|
|
29711
29877
|
"use strict";
|
|
29712
|
-
|
|
29713
|
-
|
|
29878
|
+
import_node_fs53 = __toESM(require("fs"));
|
|
29879
|
+
import_node_path66 = __toESM(require("path"));
|
|
29714
29880
|
init_repo_config();
|
|
29715
29881
|
init_repo_inspect();
|
|
29716
29882
|
MANAGED_MARKER2 = "devrouter:managed devcontainer";
|
|
@@ -29895,7 +30061,7 @@ function parseMappings(value) {
|
|
|
29895
30061
|
return Object.fromEntries(mappings);
|
|
29896
30062
|
}
|
|
29897
30063
|
function parseProfilePlanContract(source) {
|
|
29898
|
-
const document = (0,
|
|
30064
|
+
const document = (0, import_yaml9.parseDocument)(source, {
|
|
29899
30065
|
merge: false,
|
|
29900
30066
|
schema: "core",
|
|
29901
30067
|
uniqueKeys: true
|
|
@@ -30044,13 +30210,13 @@ function buildProfilePlanReport(options) {
|
|
|
30044
30210
|
return { ...report, contractPath, bindings: bindings2 };
|
|
30045
30211
|
}
|
|
30046
30212
|
function loadContract(repoPath, contractPath) {
|
|
30047
|
-
if (
|
|
30213
|
+
if (import_node_path67.default.isAbsolute(contractPath)) {
|
|
30048
30214
|
fail3("profile plan contract path must be relative to the repository.");
|
|
30049
30215
|
}
|
|
30050
30216
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
30051
30217
|
let metadata;
|
|
30052
30218
|
try {
|
|
30053
|
-
metadata =
|
|
30219
|
+
metadata = import_node_fs54.default.lstatSync(absolutePath);
|
|
30054
30220
|
} catch (error) {
|
|
30055
30221
|
fail3(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
30056
30222
|
}
|
|
@@ -30060,16 +30226,16 @@ function loadContract(repoPath, contractPath) {
|
|
|
30060
30226
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
30061
30227
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30062
30228
|
}
|
|
30063
|
-
const realRepo =
|
|
30064
|
-
const realContract =
|
|
30229
|
+
const realRepo = import_node_fs54.default.realpathSync(repoPath);
|
|
30230
|
+
const realContract = import_node_fs54.default.realpathSync(absolutePath);
|
|
30065
30231
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
30066
|
-
const source =
|
|
30232
|
+
const source = import_node_fs54.default.readFileSync(absolutePath, "utf-8");
|
|
30067
30233
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
30068
30234
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30069
30235
|
}
|
|
30070
30236
|
return {
|
|
30071
30237
|
contract: parseProfilePlanContract(source),
|
|
30072
|
-
contractPath:
|
|
30238
|
+
contractPath: import_node_path67.default.relative(repoPath, absolutePath).split(import_node_path67.default.sep).join("/")
|
|
30073
30239
|
};
|
|
30074
30240
|
}
|
|
30075
30241
|
function resolveProfilePlan(options) {
|
|
@@ -30083,13 +30249,13 @@ function resolveProfilePlan(options) {
|
|
|
30083
30249
|
contractPath: loaded.contractPath
|
|
30084
30250
|
});
|
|
30085
30251
|
}
|
|
30086
|
-
var
|
|
30252
|
+
var import_node_fs54, import_node_path67, import_yaml9, CONTRACT_VERSION, MAX_CONTRACT_BYTES, MAX_APP_MAPPINGS, MAX_BINDING_KEYS, MAX_BINDING_VALUES, MAX_LITERAL_LENGTH, BINDING_KEY;
|
|
30087
30253
|
var init_profile_plan = __esm({
|
|
30088
30254
|
"src/core/profile-plan.ts"() {
|
|
30089
30255
|
"use strict";
|
|
30090
|
-
|
|
30091
|
-
|
|
30092
|
-
|
|
30256
|
+
import_node_fs54 = __toESM(require("fs"));
|
|
30257
|
+
import_node_path67 = __toESM(require("path"));
|
|
30258
|
+
import_yaml9 = require("yaml");
|
|
30093
30259
|
init_paths();
|
|
30094
30260
|
init_profile_resolution();
|
|
30095
30261
|
init_repo_config();
|
|
@@ -30120,7 +30286,7 @@ async function runProfileResolveCommand(options) {
|
|
|
30120
30286
|
async function runProfilePlanCommand(options) {
|
|
30121
30287
|
const report = resolveProfilePlan(options);
|
|
30122
30288
|
if (options.output) {
|
|
30123
|
-
writeFileAtomically(
|
|
30289
|
+
writeFileAtomically(import_node_path68.default.resolve(options.output), `${JSON.stringify(report, null, 2)}
|
|
30124
30290
|
`);
|
|
30125
30291
|
}
|
|
30126
30292
|
if (options.json) {
|
|
@@ -30167,14 +30333,14 @@ function printProfilePlanSummary(report, output2) {
|
|
|
30167
30333
|
process.stdout.write(`Binding ${key}: ${renderValues(report.bindings[key] ?? [])}
|
|
30168
30334
|
`);
|
|
30169
30335
|
}
|
|
30170
|
-
if (output2) process.stdout.write(`Output: ${
|
|
30336
|
+
if (output2) process.stdout.write(`Output: ${import_node_path68.default.resolve(output2)}
|
|
30171
30337
|
`);
|
|
30172
30338
|
}
|
|
30173
|
-
var
|
|
30339
|
+
var import_node_path68;
|
|
30174
30340
|
var init_profile = __esm({
|
|
30175
30341
|
"src/commands/profile.ts"() {
|
|
30176
30342
|
"use strict";
|
|
30177
|
-
|
|
30343
|
+
import_node_path68 = __toESM(require("path"));
|
|
30178
30344
|
init_atomic_file();
|
|
30179
30345
|
init_output();
|
|
30180
30346
|
init_profile_plan();
|
|
@@ -30524,7 +30690,7 @@ function assertResourceGraph(resources) {
|
|
|
30524
30690
|
for (const id5 of Object.keys(resources).sort()) visit(id5);
|
|
30525
30691
|
}
|
|
30526
30692
|
function parsePreviewManifest(source) {
|
|
30527
|
-
const document = (0,
|
|
30693
|
+
const document = (0, import_yaml10.parseDocument)(source, {
|
|
30528
30694
|
merge: false,
|
|
30529
30695
|
schema: "core",
|
|
30530
30696
|
uniqueKeys: true
|
|
@@ -30557,11 +30723,11 @@ function parsePreviewManifest(source) {
|
|
|
30557
30723
|
return { version: 1, aliases, bindings: bindings2, resources, selection };
|
|
30558
30724
|
}
|
|
30559
30725
|
function loadPreviewManifest(repoPath) {
|
|
30560
|
-
const resolvedRepo =
|
|
30726
|
+
const resolvedRepo = import_node_path69.default.resolve(repoPath);
|
|
30561
30727
|
const manifestPath = assertPathWithinRepo(MANIFEST_FILE_NAME, resolvedRepo, "Preview manifest");
|
|
30562
30728
|
let metadata;
|
|
30563
30729
|
try {
|
|
30564
|
-
metadata =
|
|
30730
|
+
metadata = import_node_fs55.default.lstatSync(manifestPath);
|
|
30565
30731
|
} catch (error) {
|
|
30566
30732
|
fail4(`could not inspect preview manifest '${MANIFEST_FILE_NAME}': ${error.message}`);
|
|
30567
30733
|
}
|
|
@@ -30571,26 +30737,26 @@ function loadPreviewManifest(repoPath) {
|
|
|
30571
30737
|
if (metadata.size > MAX_MANIFEST_BYTES) {
|
|
30572
30738
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30573
30739
|
}
|
|
30574
|
-
const realRepo =
|
|
30575
|
-
const realManifest =
|
|
30740
|
+
const realRepo = import_node_fs55.default.realpathSync(resolvedRepo);
|
|
30741
|
+
const realManifest = import_node_fs55.default.realpathSync(manifestPath);
|
|
30576
30742
|
assertPathWithinRepo(realManifest, realRepo, "Preview manifest");
|
|
30577
|
-
const source =
|
|
30743
|
+
const source = import_node_fs55.default.readFileSync(manifestPath, "utf-8");
|
|
30578
30744
|
if (Buffer.byteLength(source, "utf-8") > MAX_MANIFEST_BYTES) {
|
|
30579
30745
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30580
30746
|
}
|
|
30581
30747
|
return {
|
|
30582
30748
|
manifest: parsePreviewManifest(source),
|
|
30583
|
-
digest: (0,
|
|
30749
|
+
digest: (0, import_node_crypto32.createHash)("sha256").update(source, "utf-8").digest("hex")
|
|
30584
30750
|
};
|
|
30585
30751
|
}
|
|
30586
|
-
var
|
|
30752
|
+
var import_node_crypto32, import_node_fs55, 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;
|
|
30587
30753
|
var init_manifest = __esm({
|
|
30588
30754
|
"src/core/preview/manifest.ts"() {
|
|
30589
30755
|
"use strict";
|
|
30590
|
-
|
|
30591
|
-
|
|
30592
|
-
|
|
30593
|
-
|
|
30756
|
+
import_node_crypto32 = require("crypto");
|
|
30757
|
+
import_node_fs55 = __toESM(require("fs"));
|
|
30758
|
+
import_node_path69 = __toESM(require("path"));
|
|
30759
|
+
import_yaml10 = require("yaml");
|
|
30594
30760
|
init_paths();
|
|
30595
30761
|
MANIFEST_FILE_NAME = ".devrouter.preview.yml";
|
|
30596
30762
|
MAX_MANIFEST_BYTES = 1024 * 1024;
|
|
@@ -31385,7 +31551,7 @@ function createPreviewPool(installationId) {
|
|
|
31385
31551
|
processedCommands: []
|
|
31386
31552
|
});
|
|
31387
31553
|
}
|
|
31388
|
-
function
|
|
31554
|
+
function object5(value, required, optional = []) {
|
|
31389
31555
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
31390
31556
|
throw new Error("Invalid preview state object.");
|
|
31391
31557
|
const record6 = value;
|
|
@@ -31412,7 +31578,7 @@ function oneOf3(value, allowed) {
|
|
|
31412
31578
|
if (!allowed.includes(value)) throw new Error("Invalid preview state enum.");
|
|
31413
31579
|
}
|
|
31414
31580
|
function decodeSession(value) {
|
|
31415
|
-
const row =
|
|
31581
|
+
const row = object5(
|
|
31416
31582
|
value,
|
|
31417
31583
|
[
|
|
31418
31584
|
"generation",
|
|
@@ -31463,7 +31629,7 @@ function decodeSession(value) {
|
|
|
31463
31629
|
if (row.stopReason !== void 0)
|
|
31464
31630
|
oneOf3(row.stopReason, ["stop", "closed", "expiry", "setup-timeout"]);
|
|
31465
31631
|
if (row.pendingDeadline !== void 0) {
|
|
31466
|
-
const pending =
|
|
31632
|
+
const pending = object5(row.pendingDeadline, ["target", "commandId"]);
|
|
31467
31633
|
integer(pending.target);
|
|
31468
31634
|
text4(pending.commandId);
|
|
31469
31635
|
}
|
|
@@ -31491,7 +31657,7 @@ function decodeSession(value) {
|
|
|
31491
31657
|
return session;
|
|
31492
31658
|
}
|
|
31493
31659
|
function decodePlan(value) {
|
|
31494
|
-
const row =
|
|
31660
|
+
const row = object5(
|
|
31495
31661
|
value,
|
|
31496
31662
|
[
|
|
31497
31663
|
"schemaVersion",
|
|
@@ -31520,7 +31686,7 @@ function decodePlan(value) {
|
|
|
31520
31686
|
if (!/^[a-f0-9]{64}$/.test(row[key]))
|
|
31521
31687
|
throw new Error("Invalid preview config digest.");
|
|
31522
31688
|
}
|
|
31523
|
-
const source =
|
|
31689
|
+
const source = object5(row.source, ["head", "target", "mergeBase", "complete", "changes"]);
|
|
31524
31690
|
for (const key of ["head", "target", "mergeBase"]) {
|
|
31525
31691
|
text4(source[key], 64);
|
|
31526
31692
|
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(source[key]))
|
|
@@ -31529,7 +31695,7 @@ function decodePlan(value) {
|
|
|
31529
31695
|
if (source.complete !== true || !Array.isArray(source.changes) || source.changes.length > 1e4)
|
|
31530
31696
|
throw new Error("Incomplete stored preview source.");
|
|
31531
31697
|
for (const change of source.changes) {
|
|
31532
|
-
const item =
|
|
31698
|
+
const item = object5(change, ["status", "path"], ["oldPath"]);
|
|
31533
31699
|
oneOf3(item.status, ["A", "M", "D", "R", "C", "T"]);
|
|
31534
31700
|
for (const key of ["path", ...item.oldPath === void 0 ? [] : ["oldPath"]]) {
|
|
31535
31701
|
text4(item[key], 4096);
|
|
@@ -31543,7 +31709,7 @@ function decodePlan(value) {
|
|
|
31543
31709
|
throw new Error("Invalid stored preview graph.");
|
|
31544
31710
|
const resources = {};
|
|
31545
31711
|
for (const resource of row.resources) {
|
|
31546
|
-
const item =
|
|
31712
|
+
const item = object5(
|
|
31547
31713
|
resource,
|
|
31548
31714
|
["id", "kind"],
|
|
31549
31715
|
["dependsOn", "image", "imageTarget", "build", "ports", "command"]
|
|
@@ -31559,7 +31725,7 @@ function decodePlan(value) {
|
|
|
31559
31725
|
if (!aliases.length || row.reasons.includes("source-unbound"))
|
|
31560
31726
|
throw new Error("Unbound stored preview plan.");
|
|
31561
31727
|
parsePreviewManifest(
|
|
31562
|
-
(0,
|
|
31728
|
+
(0, import_yaml11.stringify)({
|
|
31563
31729
|
version: 1,
|
|
31564
31730
|
aliases: Object.fromEntries(
|
|
31565
31731
|
aliases.map((alias) => [alias, { resources: Object.keys(resources) }])
|
|
@@ -31574,7 +31740,7 @@ function decodePlan(value) {
|
|
|
31574
31740
|
function decodePreviewPool(value) {
|
|
31575
31741
|
if (Buffer.byteLength(JSON.stringify(value) ?? "") > 1024 * 1024)
|
|
31576
31742
|
throw new Error("Preview pool exceeds its bound.");
|
|
31577
|
-
const root =
|
|
31743
|
+
const root = object5(value, [
|
|
31578
31744
|
"schemaVersion",
|
|
31579
31745
|
"installationId",
|
|
31580
31746
|
"sessions",
|
|
@@ -31588,7 +31754,7 @@ function decodePreviewPool(value) {
|
|
|
31588
31754
|
throw new Error("Invalid preview command window.");
|
|
31589
31755
|
const receiptIds = /* @__PURE__ */ new Set();
|
|
31590
31756
|
for (const receipt of root.processedCommands) {
|
|
31591
|
-
const item =
|
|
31757
|
+
const item = object5(receipt, ["id", "admittedAt"]);
|
|
31592
31758
|
text4(item.id, 512);
|
|
31593
31759
|
integer(item.admittedAt);
|
|
31594
31760
|
if (receiptIds.has(item.id)) throw new Error("Duplicate preview command receipt.");
|
|
@@ -31599,7 +31765,7 @@ function decodePreviewPool(value) {
|
|
|
31599
31765
|
throw new Error("Invalid preview stop fence window.");
|
|
31600
31766
|
for (const [key, raw] of Object.entries(fences)) {
|
|
31601
31767
|
if (!/^[a-f0-9]{64}$/.test(key)) throw new Error("Invalid stop fence identity.");
|
|
31602
|
-
const fence =
|
|
31768
|
+
const fence = object5(raw, ["createdAt", "recordedAt", "commandId"]);
|
|
31603
31769
|
text4(fence.commandId, 128);
|
|
31604
31770
|
integer(fence.createdAt);
|
|
31605
31771
|
integer(fence.recordedAt);
|
|
@@ -31609,7 +31775,7 @@ function decodePreviewPool(value) {
|
|
|
31609
31775
|
throw new Error("Preview pool session bound exceeded.");
|
|
31610
31776
|
for (const [id5, value2] of Object.entries(sessions)) {
|
|
31611
31777
|
if (!/^[a-f0-9]{64}$/.test(id5)) throw new Error("Invalid preview identity key.");
|
|
31612
|
-
const entry =
|
|
31778
|
+
const entry = object5(
|
|
31613
31779
|
value2,
|
|
31614
31780
|
["session", "plan", "reservedCents", "hourlyCents", "operations", "effectSequence"],
|
|
31615
31781
|
[
|
|
@@ -31623,7 +31789,7 @@ function decodePreviewPool(value) {
|
|
|
31623
31789
|
]
|
|
31624
31790
|
);
|
|
31625
31791
|
if (entry.identity !== void 0) {
|
|
31626
|
-
const identity2 =
|
|
31792
|
+
const identity2 = object5(entry.identity, ["forgeHost", "projectId", "change"]);
|
|
31627
31793
|
text4(identity2.forgeHost, 253);
|
|
31628
31794
|
text4(identity2.projectId, 128);
|
|
31629
31795
|
integer(identity2.change, 1);
|
|
@@ -31649,7 +31815,7 @@ function decodePreviewPool(value) {
|
|
|
31649
31815
|
if (!entry.operations || typeof entry.operations !== "object" || Array.isArray(entry.operations) || Object.keys(entry.operations).length > 1024)
|
|
31650
31816
|
throw new Error("Invalid preview operation registry.");
|
|
31651
31817
|
for (const [operationId, raw] of Object.entries(entry.operations)) {
|
|
31652
|
-
const effect2 =
|
|
31818
|
+
const effect2 = object5(
|
|
31653
31819
|
raw,
|
|
31654
31820
|
[
|
|
31655
31821
|
"id",
|
|
@@ -31687,7 +31853,7 @@ function decodePreviewPool(value) {
|
|
|
31687
31853
|
throw new Error("Preview provider step journal exceeds its bound.");
|
|
31688
31854
|
const names = /* @__PURE__ */ new Set();
|
|
31689
31855
|
for (const rawStep of effect2.steps) {
|
|
31690
|
-
const step =
|
|
31856
|
+
const step = object5(rawStep, ["name", "mode", "state", "at"], ["ref", "fingerprint"]);
|
|
31691
31857
|
text4(step.name, 64);
|
|
31692
31858
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(step.name) || names.has(step.name))
|
|
31693
31859
|
throw new Error("Invalid preview provider step identity.");
|
|
@@ -31713,11 +31879,11 @@ function decodePreviewPool(value) {
|
|
|
31713
31879
|
}
|
|
31714
31880
|
return structuredClone(root);
|
|
31715
31881
|
}
|
|
31716
|
-
var
|
|
31882
|
+
var import_yaml11, PreviewStateConflict;
|
|
31717
31883
|
var init_state = __esm({
|
|
31718
31884
|
"src/core/preview/state.ts"() {
|
|
31719
31885
|
"use strict";
|
|
31720
|
-
|
|
31886
|
+
import_yaml11 = require("yaml");
|
|
31721
31887
|
init_manifest();
|
|
31722
31888
|
PreviewStateConflict = class extends Error {
|
|
31723
31889
|
constructor() {
|
|
@@ -31732,7 +31898,7 @@ var init_state = __esm({
|
|
|
31732
31898
|
function previewIdentityKey(identity2) {
|
|
31733
31899
|
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)
|
|
31734
31900
|
throw new Error("Invalid immutable preview identity.");
|
|
31735
|
-
return (0,
|
|
31901
|
+
return (0, import_node_crypto33.createHash)("sha256").update(JSON.stringify([identity2.forgeHost, identity2.projectId, identity2.change])).digest("hex");
|
|
31736
31902
|
}
|
|
31737
31903
|
function costs(pool) {
|
|
31738
31904
|
return Object.values(pool.sessions).reduce((total, entry) => total + entry.reservedCents, 0);
|
|
@@ -31788,11 +31954,11 @@ function sessionReady(entry, now, expiresAt) {
|
|
|
31788
31954
|
...expiresAt === void 0 ? {} : { expiresAt }
|
|
31789
31955
|
});
|
|
31790
31956
|
}
|
|
31791
|
-
var
|
|
31957
|
+
var import_node_crypto33, PreviewAdmissionSuperseded, PreviewEngine;
|
|
31792
31958
|
var init_engine = __esm({
|
|
31793
31959
|
"src/core/preview/engine.ts"() {
|
|
31794
31960
|
"use strict";
|
|
31795
|
-
|
|
31961
|
+
import_node_crypto33 = require("crypto");
|
|
31796
31962
|
init_command();
|
|
31797
31963
|
init_lifecycle();
|
|
31798
31964
|
init_state();
|
|
@@ -31926,7 +32092,7 @@ var init_engine = __esm({
|
|
|
31926
32092
|
} else {
|
|
31927
32093
|
if (current && current.session.status !== "stopped" && current.session.status !== "expired")
|
|
31928
32094
|
throw new Error("Previous generation cleanup is incomplete.");
|
|
31929
|
-
const generation = (0,
|
|
32095
|
+
const generation = (0, import_node_crypto33.createHash)("sha256").update(receipt).digest("hex").slice(0, 24);
|
|
31930
32096
|
pool2.sessions[id5] = {
|
|
31931
32097
|
identity: input2.identity,
|
|
31932
32098
|
session: createPreviewSession({
|
|
@@ -32459,10 +32625,10 @@ var init_status3 = __esm({
|
|
|
32459
32625
|
throw new Error("Forge requires a trusted HTTPS API base.");
|
|
32460
32626
|
}
|
|
32461
32627
|
base;
|
|
32462
|
-
async request(method,
|
|
32463
|
-
if (!
|
|
32628
|
+
async request(method, path80, body, maxBytes) {
|
|
32629
|
+
if (!path80 || path80.startsWith("/") || path80.split("?")[0].split("/").some((part) => [".", ".."].includes(decodeURIComponent(part))) || path80.includes("\\") || path80.includes("#"))
|
|
32464
32630
|
throw new Error("Invalid forge API path.");
|
|
32465
|
-
const url = new URL(
|
|
32631
|
+
const url = new URL(path80, this.base);
|
|
32466
32632
|
if (url.origin !== this.base.origin || !url.pathname.startsWith(this.base.pathname))
|
|
32467
32633
|
throw new Error("Forge request escaped its configured API.");
|
|
32468
32634
|
let token;
|
|
@@ -32502,13 +32668,13 @@ var init_status3 = __esm({
|
|
|
32502
32668
|
throw new Error("Preview forge response is unreadable or exceeds its bound.");
|
|
32503
32669
|
}
|
|
32504
32670
|
}
|
|
32505
|
-
async pages(
|
|
32671
|
+
async pages(path80, options = {}) {
|
|
32506
32672
|
const rows2 = [];
|
|
32507
32673
|
for (let page = 1; page <= 100; page++) {
|
|
32508
|
-
const separator =
|
|
32674
|
+
const separator = path80.includes("?") ? "&" : "?";
|
|
32509
32675
|
const result = await this.request(
|
|
32510
32676
|
"GET",
|
|
32511
|
-
`${
|
|
32677
|
+
`${path80}${separator}per_page=100&page=${page}`,
|
|
32512
32678
|
void 0,
|
|
32513
32679
|
options.maxBytes
|
|
32514
32680
|
);
|
|
@@ -32534,14 +32700,14 @@ var init_status3 = __esm({
|
|
|
32534
32700
|
|
|
32535
32701
|
// src/core/preview/controller.ts
|
|
32536
32702
|
function decodeInbox(raw) {
|
|
32537
|
-
const row =
|
|
32703
|
+
const row = object5(
|
|
32538
32704
|
raw,
|
|
32539
32705
|
["schemaVersion", "identity", "scannedThrough", "closedThrough", "processed"],
|
|
32540
32706
|
["status", "selection", "needsStatus", "refusal"]
|
|
32541
32707
|
);
|
|
32542
32708
|
if (row.schemaVersion !== 1 || Buffer.byteLength(JSON.stringify(raw)) > 128 * 1024)
|
|
32543
32709
|
throw new Error("Invalid preview inbox.");
|
|
32544
|
-
const identity2 =
|
|
32710
|
+
const identity2 = object5(row.identity, ["forgeHost", "projectId", "change"]);
|
|
32545
32711
|
previewIdentityKey(identity2);
|
|
32546
32712
|
for (const key of ["scannedThrough", "closedThrough"])
|
|
32547
32713
|
if (!Number.isSafeInteger(row[key]) || row[key] < 0)
|
|
@@ -32550,7 +32716,7 @@ function decodeInbox(raw) {
|
|
|
32550
32716
|
throw new Error("Preview inbox exceeds its command bound.");
|
|
32551
32717
|
const ids2 = /* @__PURE__ */ new Set();
|
|
32552
32718
|
for (const item of row.processed) {
|
|
32553
|
-
const receipt =
|
|
32719
|
+
const receipt = object5(item, ["id", "at"]);
|
|
32554
32720
|
forgeId(receipt.id);
|
|
32555
32721
|
if (ids2.has(receipt.id) || !Number.isSafeInteger(receipt.at) || receipt.at < 0)
|
|
32556
32722
|
throw new Error("Invalid preview inbox receipt.");
|
|
@@ -32565,7 +32731,7 @@ function decodeInbox(raw) {
|
|
|
32565
32731
|
if (row.refusal !== void 0 && !previewRefusalReasons.includes(row.refusal))
|
|
32566
32732
|
throw new Error("Invalid preview refusal outcome.");
|
|
32567
32733
|
if (row.status) {
|
|
32568
|
-
const status =
|
|
32734
|
+
const status = object5(
|
|
32569
32735
|
row.status,
|
|
32570
32736
|
["intentAt"],
|
|
32571
32737
|
["commentId", "bodyDigest", "publishedAt", "intentId"]
|
|
@@ -32582,11 +32748,11 @@ function decodeInbox(raw) {
|
|
|
32582
32748
|
}
|
|
32583
32749
|
return structuredClone(row);
|
|
32584
32750
|
}
|
|
32585
|
-
var
|
|
32751
|
+
var import_node_crypto34, PreviewController;
|
|
32586
32752
|
var init_controller2 = __esm({
|
|
32587
32753
|
"src/core/preview/controller.ts"() {
|
|
32588
32754
|
"use strict";
|
|
32589
|
-
|
|
32755
|
+
import_node_crypto34 = require("crypto");
|
|
32590
32756
|
init_command();
|
|
32591
32757
|
init_engine();
|
|
32592
32758
|
init_status3();
|
|
@@ -32793,7 +32959,7 @@ Command refused: ${inbox.refusal}. Post a new command when the condition is reso
|
|
|
32793
32959
|
Available profiles: ${this.options.aliases.map((alias) => `\`${alias}\``).join(", ")}.` : ""}
|
|
32794
32960
|
|
|
32795
32961
|
${marker}`;
|
|
32796
|
-
const fingerprint = (0,
|
|
32962
|
+
const fingerprint = (0, import_node_crypto34.createHash)("sha256").update(body).digest("hex"), now = this.options.now();
|
|
32797
32963
|
if (inbox.status?.bodyDigest === fingerprint) {
|
|
32798
32964
|
if (inbox.needsStatus) await this.update(change, (row) => ({ ...row, needsStatus: false }));
|
|
32799
32965
|
return;
|
|
@@ -32804,7 +32970,7 @@ ${marker}`;
|
|
|
32804
32970
|
let commentId = inbox.status?.commentId;
|
|
32805
32971
|
if (!commentId) commentId = await this.options.forge.findStatus(change, marker) ?? void 0;
|
|
32806
32972
|
let create = false;
|
|
32807
|
-
const intentId = (0,
|
|
32973
|
+
const intentId = (0, import_node_crypto34.randomUUID)();
|
|
32808
32974
|
if (!inbox.status)
|
|
32809
32975
|
inbox = await this.update(change, (row) => {
|
|
32810
32976
|
create = !row.status;
|
|
@@ -33140,11 +33306,11 @@ var init_github = __esm({
|
|
|
33140
33306
|
throw new Error("Preview status has no ownership marker.");
|
|
33141
33307
|
if (Buffer.byteLength(body) > 32 * 1024) throw new Error("Preview status exceeds its bound.");
|
|
33142
33308
|
if (previousId) {
|
|
33143
|
-
const
|
|
33144
|
-
const comment = forgeObject((await this.http.request("GET",
|
|
33309
|
+
const path80 = `${this.repo}/issues/comments/${forgeId(previousId)}`;
|
|
33310
|
+
const comment = forgeObject((await this.http.request("GET", path80)).data);
|
|
33145
33311
|
if (forgeId(forgeObject(comment.user).id) !== this.options.botId || typeof comment.body !== "string" || !comment.body.startsWith(PREVIEW_STATUS_MARKER) || comment.issue_url !== `${this.issues}${forgeId(change)}`)
|
|
33146
33312
|
throw new Error("Preview status comment ownership differs.");
|
|
33147
|
-
await this.http.request("PATCH",
|
|
33313
|
+
await this.http.request("PATCH", path80, { body });
|
|
33148
33314
|
return previousId;
|
|
33149
33315
|
}
|
|
33150
33316
|
const created = forgeObject(
|
|
@@ -33320,11 +33486,11 @@ var init_gitlab = __esm({
|
|
|
33320
33486
|
const row = forgeObject(raw);
|
|
33321
33487
|
if (row.collapsed !== false || row.too_large !== false || ["new_file", "deleted_file", "renamed_file"].some((key) => typeof row[key] !== "boolean"))
|
|
33322
33488
|
throw new Error("GitLab file diff is incomplete.");
|
|
33323
|
-
const
|
|
33324
|
-
if (row.renamed_file) return { status: "R", path:
|
|
33489
|
+
const path80 = assertRepoRelativePath(row.new_path, "GitLab changed file"), oldPath = assertRepoRelativePath(row.old_path, "GitLab old file");
|
|
33490
|
+
if (row.renamed_file) return { status: "R", path: path80, oldPath };
|
|
33325
33491
|
return {
|
|
33326
33492
|
status: row.new_file ? "A" : row.deleted_file ? "D" : row.a_mode !== row.b_mode ? "T" : "M",
|
|
33327
|
-
path:
|
|
33493
|
+
path: path80
|
|
33328
33494
|
};
|
|
33329
33495
|
});
|
|
33330
33496
|
const current = await this.merge(change);
|
|
@@ -33554,7 +33720,7 @@ function canonicalizeImageConfiguration(configuration) {
|
|
|
33554
33720
|
return JSON.stringify(normalizeConfiguration(configuration, "image configuration"));
|
|
33555
33721
|
}
|
|
33556
33722
|
function imageConfigurationDigest(configuration) {
|
|
33557
|
-
return `sha256:${(0,
|
|
33723
|
+
return `sha256:${(0, import_node_crypto35.createHash)("sha256").update(canonicalizeImageConfiguration(configuration), "utf-8").digest("hex")}`;
|
|
33558
33724
|
}
|
|
33559
33725
|
function targetKey(target, configurationDigest) {
|
|
33560
33726
|
return `${target}\0${configurationDigest}`;
|
|
@@ -33809,11 +33975,11 @@ function resolvePreviewImages(plan, prepared, expectedProducer, value) {
|
|
|
33809
33975
|
images: Object.fromEntries(resourceReceipts)
|
|
33810
33976
|
};
|
|
33811
33977
|
}
|
|
33812
|
-
var
|
|
33978
|
+
var import_node_crypto35, 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;
|
|
33813
33979
|
var init_images = __esm({
|
|
33814
33980
|
"src/core/preview/images.ts"() {
|
|
33815
33981
|
"use strict";
|
|
33816
|
-
|
|
33982
|
+
import_node_crypto35 = require("crypto");
|
|
33817
33983
|
MAX_COLLECTION_ENTRIES2 = 256;
|
|
33818
33984
|
MAX_CONFIGURATION_ENTRIES = 128;
|
|
33819
33985
|
MAX_CONFIGURATION_KEY_LENGTH = 128;
|
|
@@ -33847,8 +34013,8 @@ function commandImageBackend(options) {
|
|
|
33847
34013
|
throw new Error("Invalid installed image resolver command.");
|
|
33848
34014
|
const verify = () => {
|
|
33849
34015
|
for (const file of options.files) {
|
|
33850
|
-
const stat =
|
|
33851
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0,
|
|
34016
|
+
const stat = import_node_fs56.default.lstatSync(file.path);
|
|
34017
|
+
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0, import_node_crypto36.createHash)("sha256").update(import_node_fs56.default.readFileSync(file.path)).digest("hex") !== file.sha256)
|
|
33852
34018
|
throw new Error("Installed image resolver fingerprint differs.");
|
|
33853
34019
|
}
|
|
33854
34020
|
};
|
|
@@ -33860,7 +34026,7 @@ function commandImageBackend(options) {
|
|
|
33860
34026
|
platform: options.platform,
|
|
33861
34027
|
configurations: options.context(entry)
|
|
33862
34028
|
});
|
|
33863
|
-
const correlation = (0,
|
|
34029
|
+
const correlation = (0, import_node_crypto36.createHash)("sha256").update(
|
|
33864
34030
|
JSON.stringify([
|
|
33865
34031
|
entry.identity,
|
|
33866
34032
|
entry.session.generation,
|
|
@@ -33884,7 +34050,7 @@ function commandImageBackend(options) {
|
|
|
33884
34050
|
});
|
|
33885
34051
|
if (Buffer.byteLength(input2) > 1024 * 1024)
|
|
33886
34052
|
throw new Error("Image request exceeds its bound.");
|
|
33887
|
-
const result = (0,
|
|
34053
|
+
const result = (0, import_node_child_process42.spawnSync)(options.command[0], options.command.slice(1), {
|
|
33888
34054
|
shell: false,
|
|
33889
34055
|
cwd: options.cwd,
|
|
33890
34056
|
encoding: "utf8",
|
|
@@ -33897,7 +34063,7 @@ function commandImageBackend(options) {
|
|
|
33897
34063
|
throw new Error("Installed image resolver failed; output suppressed.");
|
|
33898
34064
|
return JSON.parse(result.stdout);
|
|
33899
34065
|
};
|
|
33900
|
-
const resolved2 =
|
|
34066
|
+
const resolved2 = object5(invoke("resolve"), ["receipts"], ["pending"]);
|
|
33901
34067
|
const outcome = resolvePreviewImages(entry.plan, prepared, options.producer, {
|
|
33902
34068
|
receipts: resolved2.receipts
|
|
33903
34069
|
});
|
|
@@ -33922,13 +34088,13 @@ function commandImageBackend(options) {
|
|
|
33922
34088
|
}
|
|
33923
34089
|
};
|
|
33924
34090
|
}
|
|
33925
|
-
var
|
|
34091
|
+
var import_node_child_process42, import_node_crypto36, import_node_fs56;
|
|
33926
34092
|
var init_image_command = __esm({
|
|
33927
34093
|
"src/core/preview/image-command.ts"() {
|
|
33928
34094
|
"use strict";
|
|
33929
|
-
|
|
33930
|
-
|
|
33931
|
-
|
|
34095
|
+
import_node_child_process42 = require("child_process");
|
|
34096
|
+
import_node_crypto36 = require("crypto");
|
|
34097
|
+
import_node_fs56 = __toESM(require("fs"));
|
|
33932
34098
|
init_images();
|
|
33933
34099
|
init_state();
|
|
33934
34100
|
}
|
|
@@ -34621,9 +34787,9 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
34621
34787
|
const resource = resources.get(id5);
|
|
34622
34788
|
if (!resource?.ports?.some((item) => item.name === port && item.public))
|
|
34623
34789
|
throw new Error("Northflank origin binding requires a selected public port.");
|
|
34624
|
-
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0,
|
|
34790
|
+
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0, import_node_crypto37.createHash)("sha256").update(id5).digest("hex").slice(0, 6)}.${policy.baseDomain}`;
|
|
34625
34791
|
};
|
|
34626
|
-
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0,
|
|
34792
|
+
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0, import_node_crypto37.createHash)("sha256").update(id5).digest("hex").slice(0, 10)}`;
|
|
34627
34793
|
const suffix = (value) => {
|
|
34628
34794
|
if (value === void 0) return "";
|
|
34629
34795
|
if (typeof value !== "string" || value.length > 1024 || !value.startsWith("/") || value.startsWith("//") || value.includes("\\") || new RegExp("\\s|\\p{Cc}", "u").test(value))
|
|
@@ -35050,7 +35216,7 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35050
35216
|
]
|
|
35051
35217
|
}
|
|
35052
35218
|
};
|
|
35053
|
-
const digest5 = (0,
|
|
35219
|
+
const digest5 = (0, import_node_crypto37.createHash)("sha256").update(JSON.stringify({ spec, runtimeSecrets })).digest("hex");
|
|
35054
35220
|
return {
|
|
35055
35221
|
spec,
|
|
35056
35222
|
digest: digest5,
|
|
@@ -35061,11 +35227,11 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35061
35227
|
publicBuildEnvironment
|
|
35062
35228
|
};
|
|
35063
35229
|
}
|
|
35064
|
-
var
|
|
35230
|
+
var import_node_crypto37, 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;
|
|
35065
35231
|
var init_northflank_graph = __esm({
|
|
35066
35232
|
"src/core/preview/providers/northflank-graph.ts"() {
|
|
35067
35233
|
"use strict";
|
|
35068
|
-
|
|
35234
|
+
import_node_crypto37 = require("crypto");
|
|
35069
35235
|
import_node_net5 = require("net");
|
|
35070
35236
|
ALLOCATION_PLAN = /^[a-zA-Z0-9-]{3,100}$/;
|
|
35071
35237
|
DATABASE_NAME = /^[a-z][a-z0-9_]{0,62}$/;
|
|
@@ -35090,7 +35256,7 @@ function identifier(value) {
|
|
|
35090
35256
|
function decodeNorthflankOwnership(value) {
|
|
35091
35257
|
if (Buffer.byteLength(JSON.stringify(value) ?? "") > 128 * 1024)
|
|
35092
35258
|
throw new Error("Northflank ownership exceeds its bound.");
|
|
35093
|
-
const row =
|
|
35259
|
+
const row = object5(
|
|
35094
35260
|
value,
|
|
35095
35261
|
["schemaVersion", "generation", "policyDigest", "resources", "absent"],
|
|
35096
35262
|
[
|
|
@@ -35119,7 +35285,7 @@ function decodeNorthflankOwnership(value) {
|
|
|
35119
35285
|
)))
|
|
35120
35286
|
throw new Error("Invalid Northflank completed-job metadata.");
|
|
35121
35287
|
if (row.apiWait !== void 0) {
|
|
35122
|
-
const wait =
|
|
35288
|
+
const wait = object5(row.apiWait, ["until", "exhausted"]);
|
|
35123
35289
|
if (!Number.isSafeInteger(wait.until) || wait.until < 1 || typeof wait.exhausted !== "boolean")
|
|
35124
35290
|
throw new Error("Invalid Northflank API wait metadata.");
|
|
35125
35291
|
}
|
|
@@ -35128,7 +35294,7 @@ function decodeNorthflankOwnership(value) {
|
|
|
35128
35294
|
const references = /* @__PURE__ */ new Set();
|
|
35129
35295
|
const ids2 = /* @__PURE__ */ new Set();
|
|
35130
35296
|
for (const raw of row.resources) {
|
|
35131
|
-
const resource =
|
|
35297
|
+
const resource = object5(raw, ["reference", "kind", "id", "name"], ["uid"]);
|
|
35132
35298
|
identifier(resource.id);
|
|
35133
35299
|
identifier(resource.reference);
|
|
35134
35300
|
identifier(resource.name);
|
|
@@ -35169,7 +35335,7 @@ function specDigest(value) {
|
|
|
35169
35335
|
return digest3(definition(value));
|
|
35170
35336
|
}
|
|
35171
35337
|
function digest3(value) {
|
|
35172
|
-
return (0,
|
|
35338
|
+
return (0, import_node_crypto38.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
35173
35339
|
}
|
|
35174
35340
|
function bindings(owned) {
|
|
35175
35341
|
return {
|
|
@@ -35194,11 +35360,11 @@ function outputNames(graph) {
|
|
|
35194
35360
|
)
|
|
35195
35361
|
].sort();
|
|
35196
35362
|
}
|
|
35197
|
-
var
|
|
35363
|
+
var import_node_crypto38, resourceKinds, NorthflankOwnershipStore, northflankQualificationKeys, NorthflankFailure, NorthflankFenced, NorthflankPreviewProvider, nativeKinds, emptySpec;
|
|
35198
35364
|
var init_northflank = __esm({
|
|
35199
35365
|
"src/core/preview/providers/northflank.ts"() {
|
|
35200
35366
|
"use strict";
|
|
35201
|
-
|
|
35367
|
+
import_node_crypto38 = require("crypto");
|
|
35202
35368
|
init_command();
|
|
35203
35369
|
init_state();
|
|
35204
35370
|
init_northflank_api();
|
|
@@ -35831,7 +35997,7 @@ var init_northflank = __esm({
|
|
|
35831
35997
|
const settings = this.options.graph.generated?.[name];
|
|
35832
35998
|
if (!settings)
|
|
35833
35999
|
throw new NorthflankFailure("Northflank generated value is undeclared.");
|
|
35834
|
-
value = (0,
|
|
36000
|
+
value = (0, import_node_crypto38.randomBytes)(settings.bytes).toString(settings.encoding);
|
|
35835
36001
|
}
|
|
35836
36002
|
if (kind === "output" && value === void 0)
|
|
35837
36003
|
throw new NorthflankFailure("Northflank output has no verified recipient.");
|
|
@@ -35908,10 +36074,10 @@ var init_northflank = __esm({
|
|
|
35908
36074
|
for (const step of steps.filter((item) => item.name.endsWith("-run"))) {
|
|
35909
36075
|
if (!owned.blueprintId) return this.receipt(owned);
|
|
35910
36076
|
const operation = `${step.name.slice(0, -4)}-${digest3(effect2.id).slice(0, 20)}`;
|
|
35911
|
-
const
|
|
35912
|
-
const id5 = step.ref ?? await this.findRun(
|
|
36077
|
+
const path80 = ["preview-blueprints", owned.blueprintId];
|
|
36078
|
+
const id5 = step.ref ?? await this.findRun(path80, operation);
|
|
35913
36079
|
if (!id5) return this.receipt(owned);
|
|
35914
|
-
const result = await this.options.api.request("GET", [...
|
|
36080
|
+
const result = await this.options.api.request("GET", [...path80, "runs", id5]);
|
|
35915
36081
|
if (!result) return this.receipt(owned);
|
|
35916
36082
|
const run = data(result);
|
|
35917
36083
|
if (!run.concluded || specDigest(run.spec) !== step.fingerprint || northflankRecord(run.arguments).devrouterOperation !== operation || run.environmentId !== (owned.previewId ?? `preview-${entry.session.generation}`))
|
|
@@ -35934,11 +36100,11 @@ var init_northflank = __esm({
|
|
|
35934
36100
|
}
|
|
35935
36101
|
};
|
|
35936
36102
|
}
|
|
35937
|
-
async findRun(
|
|
36103
|
+
async findRun(path80, operation) {
|
|
35938
36104
|
let match;
|
|
35939
|
-
for (const summary of await this.options.api.list([...
|
|
36105
|
+
for (const summary of await this.options.api.list([...path80, "runs"], "runs")) {
|
|
35940
36106
|
const id5 = northflankIdentifier(summary.id);
|
|
35941
|
-
const candidate = data(await this.options.api.request("GET", [...
|
|
36107
|
+
const candidate = data(await this.options.api.request("GET", [...path80, "runs", id5]));
|
|
35942
36108
|
if (northflankRecord(candidate.arguments ?? {}).devrouterOperation !== operation) continue;
|
|
35943
36109
|
if (match) throw new NorthflankFailure("Ambiguous Northflank run outcome.");
|
|
35944
36110
|
match = id5;
|
|
@@ -35947,13 +36113,13 @@ var init_northflank = __esm({
|
|
|
35947
36113
|
}
|
|
35948
36114
|
async run(entry, effect2, gate, owned, stage, spec) {
|
|
35949
36115
|
const api = this.options.api;
|
|
35950
|
-
const
|
|
36116
|
+
const path80 = ["preview-blueprints", northflankIdentifier(owned.blueprintId)];
|
|
35951
36117
|
let fingerprint = specDigest(spec);
|
|
35952
36118
|
const operation = `${stage}-${digest3(effect2.id).slice(0, 20)}`;
|
|
35953
36119
|
const recorded = (await gate.read()).find((step2) => step2.name === `${stage}-run`);
|
|
35954
36120
|
if (!recorded) {
|
|
35955
36121
|
if (await begin(gate, `${stage}-spec`, "once", fingerprint) === "write") {
|
|
35956
|
-
await api.request("POST",
|
|
36122
|
+
await api.request("POST", path80, {
|
|
35957
36123
|
name: this.name(entry),
|
|
35958
36124
|
apiVersion: "v1.2",
|
|
35959
36125
|
spec,
|
|
@@ -35962,14 +36128,14 @@ var init_northflank = __esm({
|
|
|
35962
36128
|
});
|
|
35963
36129
|
await gate.record(`${stage}-spec`, "accepted");
|
|
35964
36130
|
}
|
|
35965
|
-
const detail = data(await api.request("GET",
|
|
36131
|
+
const detail = data(await api.request("GET", path80));
|
|
35966
36132
|
if (specDigest(detail.spec) !== fingerprint)
|
|
35967
36133
|
throw new NorthflankFailure("Northflank blueprint specification drifted.");
|
|
35968
36134
|
await gate.record(`${stage}-spec`, "accepted");
|
|
35969
36135
|
if (await begin(gate, `${stage}-run`, "once", fingerprint) === "write") {
|
|
35970
36136
|
try {
|
|
35971
36137
|
const run2 = data(
|
|
35972
|
-
await api.request("POST", [...
|
|
36138
|
+
await api.request("POST", [...path80, "runs"], {
|
|
35973
36139
|
name: owned.previewId ?? `preview-${entry.session.generation}`,
|
|
35974
36140
|
arguments: { devrouterOperation: operation }
|
|
35975
36141
|
})
|
|
@@ -35990,15 +36156,15 @@ var init_northflank = __esm({
|
|
|
35990
36156
|
if (!step) return null;
|
|
35991
36157
|
let id5 = step.ref;
|
|
35992
36158
|
if (!id5) {
|
|
35993
|
-
id5 = await this.findRun(
|
|
36159
|
+
id5 = await this.findRun(path80, operation);
|
|
35994
36160
|
if (!id5) return null;
|
|
35995
36161
|
await gate.record(`${stage}-run`, "accepted", id5);
|
|
35996
36162
|
}
|
|
35997
|
-
const run = data(await api.request("GET", [...
|
|
36163
|
+
const run = data(await api.request("GET", [...path80, "runs", id5]));
|
|
35998
36164
|
if (specDigest(run.spec) !== fingerprint || northflankRecord(run.arguments).devrouterOperation !== operation || run.environmentId !== (owned.previewId ?? `preview-${entry.session.generation}`))
|
|
35999
36165
|
throw new NorthflankFailure("Northflank executed an unexpected specification or operation.");
|
|
36000
36166
|
if (owned.previewId) {
|
|
36001
|
-
const previews = await api.list([...
|
|
36167
|
+
const previews = await api.list([...path80, "previews"], "previewEnvironments");
|
|
36002
36168
|
if (previews.length !== 1 || previews[0].id !== owned.previewId)
|
|
36003
36169
|
throw new NorthflankFailure("Northflank run changed the generation environment.");
|
|
36004
36170
|
}
|
|
@@ -36073,33 +36239,33 @@ var init_northflank = __esm({
|
|
|
36073
36239
|
const candidates = await this.namedBlueprints(entry);
|
|
36074
36240
|
return this.receipt(owned, candidates.length === 0);
|
|
36075
36241
|
}
|
|
36076
|
-
const
|
|
36077
|
-
const blueprint = await this.options.api.request("GET",
|
|
36242
|
+
const path80 = ["preview-blueprints", owned.blueprintId];
|
|
36243
|
+
const blueprint = await this.options.api.request("GET", path80);
|
|
36078
36244
|
if (!blueprint && !owned.blueprintObserved && !owned.blueprintRejected)
|
|
36079
36245
|
return this.receipt(owned);
|
|
36080
36246
|
if (blueprint) {
|
|
36081
36247
|
if (!owned.blueprintObserved)
|
|
36082
36248
|
owned = await store.update((current) => ({ ...current, blueprintObserved: true }));
|
|
36083
|
-
const runs = await this.options.api.list([...
|
|
36249
|
+
const runs = await this.options.api.list([...path80, "runs"], "runs");
|
|
36084
36250
|
for (const run of runs.filter((row) => row.concluded !== true)) {
|
|
36085
36251
|
const id5 = northflankIdentifier(run.id);
|
|
36086
36252
|
const step = `abort-${digest3(id5).slice(0, 12)}`;
|
|
36087
36253
|
if (await begin(gate, step, "convergent") === "write") {
|
|
36088
|
-
await this.options.api.request("POST", [...
|
|
36254
|
+
await this.options.api.request("POST", [...path80, "runs", id5, "abort"]);
|
|
36089
36255
|
await gate.record(step, "accepted", id5);
|
|
36090
36256
|
}
|
|
36091
36257
|
}
|
|
36092
36258
|
if (effect2.kind === "cancel") return this.receipt(owned, true);
|
|
36093
|
-
const previews = await this.options.api.list([...
|
|
36259
|
+
const previews = await this.options.api.list([...path80, "previews"], "previewEnvironments");
|
|
36094
36260
|
for (const preview of previews) {
|
|
36095
36261
|
const id5 = northflankIdentifier(preview.id);
|
|
36096
36262
|
const step = `delete-${digest3(id5).slice(0, 12)}`;
|
|
36097
36263
|
if (await begin(gate, step, "convergent") === "write") {
|
|
36098
|
-
await this.options.api.request("DELETE", [...
|
|
36264
|
+
await this.options.api.request("DELETE", [...path80, "previews", id5]);
|
|
36099
36265
|
await gate.record(step, "accepted", id5);
|
|
36100
36266
|
}
|
|
36101
36267
|
}
|
|
36102
|
-
if ((await this.options.api.list([...
|
|
36268
|
+
if ((await this.options.api.list([...path80, "previews"], "previewEnvironments")).length)
|
|
36103
36269
|
return this.receipt(owned);
|
|
36104
36270
|
let cleanedDomains = 0;
|
|
36105
36271
|
for (const resource of owned.resources.filter((item) => item.kind === "domains")) {
|
|
@@ -36112,7 +36278,7 @@ var init_northflank = __esm({
|
|
|
36112
36278
|
}
|
|
36113
36279
|
}
|
|
36114
36280
|
if (await begin(gate, "delete-blueprint", "convergent") === "write") {
|
|
36115
|
-
await this.options.api.request("DELETE",
|
|
36281
|
+
await this.options.api.request("DELETE", path80);
|
|
36116
36282
|
await gate.record("delete-blueprint", "accepted");
|
|
36117
36283
|
}
|
|
36118
36284
|
}
|
|
@@ -36334,10 +36500,10 @@ __export(installation_exports, {
|
|
|
36334
36500
|
loadPreviewInstallation: () => loadPreviewInstallation
|
|
36335
36501
|
});
|
|
36336
36502
|
function readFile(file) {
|
|
36337
|
-
const stat =
|
|
36503
|
+
const stat = import_node_fs57.default.lstatSync(file);
|
|
36338
36504
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
|
|
36339
36505
|
throw new Error("Preview control files must be regular files of at most 1 MiB.");
|
|
36340
|
-
return
|
|
36506
|
+
return import_node_fs57.default.readFileSync(file, "utf8");
|
|
36341
36507
|
}
|
|
36342
36508
|
function text5(value, pattern) {
|
|
36343
36509
|
if (typeof value !== "string" || !pattern.test(value))
|
|
@@ -36350,8 +36516,8 @@ function integer2(value, min, max) {
|
|
|
36350
36516
|
return value;
|
|
36351
36517
|
}
|
|
36352
36518
|
function loadPreviewInstallation(filename, options = {}) {
|
|
36353
|
-
const root =
|
|
36354
|
-
const raw =
|
|
36519
|
+
const root = import_node_path70.default.dirname(import_node_fs57.default.realpathSync(filename));
|
|
36520
|
+
const raw = object5(JSON.parse(readFile(filename)), [
|
|
36355
36521
|
"version",
|
|
36356
36522
|
"installationId",
|
|
36357
36523
|
"state",
|
|
@@ -36386,10 +36552,10 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36386
36552
|
return value;
|
|
36387
36553
|
};
|
|
36388
36554
|
};
|
|
36389
|
-
const statePolicy =
|
|
36555
|
+
const statePolicy = object5(raw.state, ["containerUrl"], ["tokenEnv", "federated"]);
|
|
36390
36556
|
if (statePolicy.tokenEnv === void 0 === (statePolicy.federated === void 0))
|
|
36391
36557
|
throw new Error("Preview state requires exactly one installed authentication method.");
|
|
36392
|
-
const federated = statePolicy.federated === void 0 ? void 0 :
|
|
36558
|
+
const federated = statePolicy.federated === void 0 ? void 0 : object5(statePolicy.federated, ["tenantIdEnv", "clientIdEnv", "assertionEnv"]);
|
|
36393
36559
|
const accessToken = federated ? azureFederatedPreviewToken({
|
|
36394
36560
|
tenantId: credential(federated.tenantIdEnv),
|
|
36395
36561
|
clientId: credential(federated.clientIdEnv),
|
|
@@ -36405,13 +36571,13 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36405
36571
|
if (!Array.isArray(raw.projects) || raw.projects.length < 1 || raw.projects.length > 16)
|
|
36406
36572
|
throw new Error("Preview installation requires 1-16 registered projects.");
|
|
36407
36573
|
const projects = raw.projects.map((input2) => {
|
|
36408
|
-
const row =
|
|
36574
|
+
const row = object5(
|
|
36409
36575
|
input2,
|
|
36410
36576
|
["key", "forge", "config", "manifest", "northflank", "hourlyCents", "acceptance"],
|
|
36411
36577
|
["images"]
|
|
36412
36578
|
);
|
|
36413
36579
|
const key = text5(row.key, /^[a-z][a-z0-9-]{0,62}$/);
|
|
36414
|
-
const forgePolicy =
|
|
36580
|
+
const forgePolicy = object5(
|
|
36415
36581
|
row.forge,
|
|
36416
36582
|
["kind", "host", "apiUrl", "repository", "projectId", "botId", "tokenEnv"],
|
|
36417
36583
|
["controllerProjectId"]
|
|
@@ -36431,10 +36597,10 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36431
36597
|
fetch: options.fetch
|
|
36432
36598
|
});
|
|
36433
36599
|
const control = (input3) => {
|
|
36434
|
-
const ref2 =
|
|
36600
|
+
const ref2 = object5(input3, ["file", "sha256"]);
|
|
36435
36601
|
const filename2 = text5(ref2.file, /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/);
|
|
36436
|
-
const file =
|
|
36437
|
-
if (!file.startsWith(`${root}${
|
|
36602
|
+
const file = import_node_fs57.default.realpathSync(import_node_path70.default.join(root, filename2));
|
|
36603
|
+
if (!file.startsWith(`${root}${import_node_path70.default.sep}`))
|
|
36438
36604
|
throw new Error("Preview control file escapes installation directory.");
|
|
36439
36605
|
const source = readFile(file), expected = text5(ref2.sha256, /^[a-f0-9]{64}$/);
|
|
36440
36606
|
if (digest4(source) !== expected)
|
|
@@ -36442,7 +36608,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36442
36608
|
return { source, digest: expected };
|
|
36443
36609
|
};
|
|
36444
36610
|
const local = control(row.config), remote = control(row.manifest), config = parseRepoConfigSource(local.source, ".devrouter.yml"), manifest = parsePreviewManifest(remote.source);
|
|
36445
|
-
const northflank =
|
|
36611
|
+
const northflank = object5(row.northflank, [
|
|
36446
36612
|
"projectId",
|
|
36447
36613
|
"tokenEnv",
|
|
36448
36614
|
"graph",
|
|
@@ -36450,7 +36616,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36450
36616
|
"runtimeSecrets"
|
|
36451
36617
|
]);
|
|
36452
36618
|
const graph = northflank.graph;
|
|
36453
|
-
const qualifications =
|
|
36619
|
+
const qualifications = object5(
|
|
36454
36620
|
northflank.qualification,
|
|
36455
36621
|
[...northflankQualificationKeys],
|
|
36456
36622
|
["outputExec"]
|
|
@@ -36470,7 +36636,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36470
36636
|
for (const id5 of Object.keys(manifest.resources)) integer2(rates[id5], 1, 1e5);
|
|
36471
36637
|
if (Object.keys(rates).some((id5) => !manifest.resources[id5]))
|
|
36472
36638
|
throw new Error("Preview cost names an unknown resource.");
|
|
36473
|
-
const acceptance =
|
|
36639
|
+
const acceptance = object5(row.acceptance, ["command", "environment"]);
|
|
36474
36640
|
if (!Array.isArray(acceptance.command) || acceptance.command.length < 1 || acceptance.command.length > 32 || acceptance.command.some(
|
|
36475
36641
|
(arg) => typeof arg !== "string" || !arg || arg.length > 4096 || arg.includes("\0")
|
|
36476
36642
|
))
|
|
@@ -36496,7 +36662,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36496
36662
|
return credential(secrets[ref2])();
|
|
36497
36663
|
},
|
|
36498
36664
|
accept: async (entry, urls) => {
|
|
36499
|
-
const result = (0,
|
|
36665
|
+
const result = (0, import_node_child_process43.spawnSync)(command[0], command.slice(1), {
|
|
36500
36666
|
cwd: root,
|
|
36501
36667
|
shell: false,
|
|
36502
36668
|
timeout: 3e4,
|
|
@@ -36514,7 +36680,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36514
36680
|
});
|
|
36515
36681
|
if (result.error || result.status !== 0) return false;
|
|
36516
36682
|
try {
|
|
36517
|
-
const proof =
|
|
36683
|
+
const proof = object5(JSON.parse(result.stdout), [
|
|
36518
36684
|
"generation",
|
|
36519
36685
|
"revision",
|
|
36520
36686
|
"urls",
|
|
@@ -36537,7 +36703,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36537
36703
|
source,
|
|
36538
36704
|
...aliases2?.length ? { aliases: aliases2 } : {}
|
|
36539
36705
|
});
|
|
36540
|
-
const imagePolicy = row.images === void 0 ? void 0 :
|
|
36706
|
+
const imagePolicy = row.images === void 0 ? void 0 : object5(row.images, [
|
|
36541
36707
|
"platform",
|
|
36542
36708
|
"platformQualified",
|
|
36543
36709
|
"producer",
|
|
@@ -36551,14 +36717,14 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36551
36717
|
if (!Array.isArray(imageEnvironment) || imageEnvironment.length > 32)
|
|
36552
36718
|
throw new Error("Invalid image resolver environment.");
|
|
36553
36719
|
const imageEnvNames = imageEnvironment.map(envName);
|
|
36554
|
-
const producer = imagePolicy ?
|
|
36720
|
+
const producer = imagePolicy ? object5(imagePolicy.producer, ["repository", "workflow", "controlRevision"]) : void 0;
|
|
36555
36721
|
if (imagePolicy && (!Array.isArray(imagePolicy.files) || imagePolicy.files.length > 32))
|
|
36556
36722
|
throw new Error("Invalid reviewed image resolver files.");
|
|
36557
36723
|
const imageFiles = imagePolicy ? imagePolicy.files.map((input3) => {
|
|
36558
|
-
const item =
|
|
36724
|
+
const item = object5(input3, ["file", "sha256"]);
|
|
36559
36725
|
const verified = control(input3);
|
|
36560
36726
|
return {
|
|
36561
|
-
path:
|
|
36727
|
+
path: import_node_fs57.default.realpathSync(import_node_path70.default.join(root, item.file)),
|
|
36562
36728
|
sha256: verified.digest
|
|
36563
36729
|
};
|
|
36564
36730
|
}) : [];
|
|
@@ -36673,7 +36839,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36673
36839
|
}
|
|
36674
36840
|
},
|
|
36675
36841
|
now,
|
|
36676
|
-
workerId: (0,
|
|
36842
|
+
workerId: (0, import_node_crypto39.randomUUID)(),
|
|
36677
36843
|
policy: {
|
|
36678
36844
|
installationId,
|
|
36679
36845
|
maxActive,
|
|
@@ -36780,7 +36946,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36780
36946
|
}
|
|
36781
36947
|
async function initializePreviewInstallation(installationId, store) {
|
|
36782
36948
|
const poolKey = `installations/${installationId}/pool`, witnessKey = `installations/${installationId}/initialized`;
|
|
36783
|
-
if (await store.read(witnessKey, (raw) =>
|
|
36949
|
+
if (await store.read(witnessKey, (raw) => object5(raw, ["installationId"])))
|
|
36784
36950
|
throw new Error(
|
|
36785
36951
|
"Preview installation is already initialized; missing state requires operator recovery."
|
|
36786
36952
|
);
|
|
@@ -36789,14 +36955,14 @@ async function initializePreviewInstallation(installationId, store) {
|
|
|
36789
36955
|
await store.compareAndSwap(witnessKey, null, { installationId });
|
|
36790
36956
|
await store.compareAndSwap(poolKey, null, createPreviewPool(installationId));
|
|
36791
36957
|
}
|
|
36792
|
-
var
|
|
36958
|
+
var import_node_child_process43, import_node_crypto39, import_node_fs57, import_node_path70, MAX_COMMAND_AGE_MS, digest4, envName;
|
|
36793
36959
|
var init_installation = __esm({
|
|
36794
36960
|
"src/core/preview/installation.ts"() {
|
|
36795
36961
|
"use strict";
|
|
36796
|
-
|
|
36797
|
-
|
|
36798
|
-
|
|
36799
|
-
|
|
36962
|
+
import_node_child_process43 = require("child_process");
|
|
36963
|
+
import_node_crypto39 = require("crypto");
|
|
36964
|
+
import_node_fs57 = __toESM(require("fs"));
|
|
36965
|
+
import_node_path70 = __toESM(require("path"));
|
|
36800
36966
|
init_repo_config();
|
|
36801
36967
|
init_command();
|
|
36802
36968
|
init_controller2();
|
|
@@ -36813,7 +36979,7 @@ var init_installation = __esm({
|
|
|
36813
36979
|
init_state();
|
|
36814
36980
|
init_azure_blob();
|
|
36815
36981
|
MAX_COMMAND_AGE_MS = 15 * 6e4;
|
|
36816
|
-
digest4 = (source) => (0,
|
|
36982
|
+
digest4 = (source) => (0, import_node_crypto39.createHash)("sha256").update(source).digest("hex");
|
|
36817
36983
|
envName = (value) => {
|
|
36818
36984
|
if (typeof value !== "string" || !/^DEVROUTER_PREVIEW_[A-Z0-9_]+$/.test(value))
|
|
36819
36985
|
throw new Error("Preview credential references require scoped environment names.");
|
|
@@ -36830,16 +36996,16 @@ __export(preview_exports, {
|
|
|
36830
36996
|
runPreviewPlanCommand: () => runPreviewPlanCommand
|
|
36831
36997
|
});
|
|
36832
36998
|
function readSource(repoPath, filename) {
|
|
36833
|
-
if (
|
|
36999
|
+
if (import_node_path71.default.isAbsolute(filename))
|
|
36834
37000
|
throw new Error("Preview source path must be repository-relative.");
|
|
36835
|
-
const root =
|
|
37001
|
+
const root = import_node_fs58.default.realpathSync(repoPath);
|
|
36836
37002
|
const file = assertPathWithinRepo(filename, root, "preview source");
|
|
36837
|
-
const stat =
|
|
37003
|
+
const stat = import_node_fs58.default.lstatSync(file);
|
|
36838
37004
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 1024 * 1024) {
|
|
36839
37005
|
throw new Error("Preview source must be a regular file of at most 1 MiB.");
|
|
36840
37006
|
}
|
|
36841
|
-
assertPathWithinRepo(
|
|
36842
|
-
return JSON.parse(
|
|
37007
|
+
assertPathWithinRepo(import_node_fs58.default.realpathSync(file), root, "preview source");
|
|
37008
|
+
return JSON.parse(import_node_fs58.default.readFileSync(file, "utf8"));
|
|
36843
37009
|
}
|
|
36844
37010
|
async function runPreviewPlanCommand(options) {
|
|
36845
37011
|
const repoPath = resolveRepoPath(options.repo);
|
|
@@ -36854,13 +37020,13 @@ async function runPreviewPlanCommand(options) {
|
|
|
36854
37020
|
`);
|
|
36855
37021
|
return;
|
|
36856
37022
|
}
|
|
36857
|
-
const localConfig =
|
|
37023
|
+
const localConfig = import_node_fs58.default.readFileSync(import_node_path71.default.join(repoPath, ".devrouter.yml"), "utf8");
|
|
36858
37024
|
const report = buildPreviewPlan({
|
|
36859
37025
|
repoPath,
|
|
36860
37026
|
config: loadRepoConfig(repoPath, () => localConfig),
|
|
36861
37027
|
manifest,
|
|
36862
37028
|
manifestDigest: digest5,
|
|
36863
|
-
localConfigDigest: (0,
|
|
37029
|
+
localConfigDigest: (0, import_node_crypto40.createHash)("sha256").update(localConfig).digest("hex"),
|
|
36864
37030
|
...options.alias === void 0 ? {} : { aliases: options.alias.split(",") },
|
|
36865
37031
|
...options.source === void 0 ? {} : { source: readSource(repoPath, options.source) }
|
|
36866
37032
|
});
|
|
@@ -36879,7 +37045,7 @@ async function runPreviewPlanCommand(options) {
|
|
|
36879
37045
|
}
|
|
36880
37046
|
}
|
|
36881
37047
|
async function runPreviewInitCommand(options) {
|
|
36882
|
-
const repoPath =
|
|
37048
|
+
const repoPath = import_node_fs58.default.realpathSync(resolveRepoPath(options.repo));
|
|
36883
37049
|
if (options.integration === "gitlab") return renderGitLabPreviewIntegration(repoPath, options);
|
|
36884
37050
|
if (options.integration) return renderPreviewIntegration(repoPath, options);
|
|
36885
37051
|
loadRepoConfig(repoPath);
|
|
@@ -36902,10 +37068,10 @@ async function runPreviewInitCommand(options) {
|
|
|
36902
37068
|
allowedUnions: []
|
|
36903
37069
|
}
|
|
36904
37070
|
};
|
|
36905
|
-
const content = (0,
|
|
37071
|
+
const content = (0, import_yaml12.stringify)(manifest);
|
|
36906
37072
|
if (options.write) {
|
|
36907
|
-
const file =
|
|
36908
|
-
|
|
37073
|
+
const file = import_node_path71.default.join(repoPath, ".devrouter.preview.yml");
|
|
37074
|
+
import_node_fs58.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
36909
37075
|
}
|
|
36910
37076
|
if (options.json) {
|
|
36911
37077
|
printJSON({
|
|
@@ -36970,12 +37136,12 @@ async function runPreviewInstallationCommand(action2, options) {
|
|
|
36970
37136
|
}
|
|
36971
37137
|
function previewAsset(name) {
|
|
36972
37138
|
const candidates = [
|
|
36973
|
-
|
|
36974
|
-
|
|
37139
|
+
import_node_path71.default.resolve(__dirname, "..", "assets", "preview", name),
|
|
37140
|
+
import_node_path71.default.resolve(__dirname, "..", "..", "assets", "preview", name)
|
|
36975
37141
|
];
|
|
36976
|
-
const file = candidates.find((file2) =>
|
|
37142
|
+
const file = candidates.find((file2) => import_node_fs58.default.existsSync(file2));
|
|
36977
37143
|
if (!file) throw new Error("Installed preview integration asset is missing.");
|
|
36978
|
-
return
|
|
37144
|
+
return import_node_fs58.default.readFileSync(file, "utf8");
|
|
36979
37145
|
}
|
|
36980
37146
|
function renderPreviewAsset(name, replacements) {
|
|
36981
37147
|
return previewAsset(name).replace(/__([A-Z_]+)__/g, (_match, key) => {
|
|
@@ -37010,9 +37176,9 @@ async function renderPreviewIntegration(repoPath, options) {
|
|
|
37010
37176
|
const filename = `.github/workflows/devrouter-preview${options.sweeper ? "-sweep" : ""}.yml`;
|
|
37011
37177
|
if (options.write) {
|
|
37012
37178
|
const file = assertPathWithinRepo(filename, repoPath, "preview workflow");
|
|
37013
|
-
|
|
37014
|
-
assertPathWithinRepo(
|
|
37015
|
-
|
|
37179
|
+
import_node_fs58.default.mkdirSync(import_node_path71.default.dirname(file), { recursive: true });
|
|
37180
|
+
assertPathWithinRepo(import_node_fs58.default.realpathSync(import_node_path71.default.dirname(file)), repoPath, "preview workflow parent");
|
|
37181
|
+
import_node_fs58.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37016
37182
|
}
|
|
37017
37183
|
if (options.json)
|
|
37018
37184
|
printJSON({
|
|
@@ -37030,7 +37196,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37030
37196
|
throw new Error(
|
|
37031
37197
|
"GitLab integration requires reviewed --controller-ref and --controller-image digest."
|
|
37032
37198
|
);
|
|
37033
|
-
const integrity = `sha256-${(0,
|
|
37199
|
+
const integrity = `sha256-${(0, import_node_crypto40.createHash)("sha256").update(previewAsset("gitlab-template.yml")).digest("base64")}`;
|
|
37034
37200
|
const replacements = {
|
|
37035
37201
|
CONTROLLER_REF: String(options.controllerRef),
|
|
37036
37202
|
CONTROLLER_IMAGE: String(options.controllerImage),
|
|
@@ -37039,7 +37205,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37039
37205
|
const content = renderPreviewAsset("gitlab.yml", replacements);
|
|
37040
37206
|
const filename = ".gitlab-ci.yml";
|
|
37041
37207
|
if (options.write)
|
|
37042
|
-
|
|
37208
|
+
import_node_fs58.default.writeFileSync(assertPathWithinRepo(filename, repoPath, "GitLab preview caller"), content, {
|
|
37043
37209
|
flag: "wx",
|
|
37044
37210
|
mode: 384
|
|
37045
37211
|
});
|
|
@@ -37054,14 +37220,14 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37054
37220
|
});
|
|
37055
37221
|
else process.stdout.write(content);
|
|
37056
37222
|
}
|
|
37057
|
-
var
|
|
37223
|
+
var import_node_crypto40, import_node_fs58, import_node_path71, import_yaml12;
|
|
37058
37224
|
var init_preview = __esm({
|
|
37059
37225
|
"src/commands/preview.ts"() {
|
|
37060
37226
|
"use strict";
|
|
37061
|
-
|
|
37062
|
-
|
|
37063
|
-
|
|
37064
|
-
|
|
37227
|
+
import_node_crypto40 = require("crypto");
|
|
37228
|
+
import_node_fs58 = __toESM(require("fs"));
|
|
37229
|
+
import_node_path71 = __toESM(require("path"));
|
|
37230
|
+
import_yaml12 = require("yaml");
|
|
37065
37231
|
init_output();
|
|
37066
37232
|
init_paths();
|
|
37067
37233
|
init_manifest();
|
|
@@ -37352,7 +37518,7 @@ function sanitizeRouterId(value) {
|
|
|
37352
37518
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
37353
37519
|
}
|
|
37354
37520
|
function repoHash(repoPath) {
|
|
37355
|
-
return (0,
|
|
37521
|
+
return (0, import_node_crypto41.createHash)("sha1").update(import_node_path72.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
37356
37522
|
}
|
|
37357
37523
|
function asDockerApp(app) {
|
|
37358
37524
|
return app.runtime === "docker";
|
|
@@ -37431,11 +37597,11 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
37431
37597
|
if (dockerApps.length === 0) {
|
|
37432
37598
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
37433
37599
|
}
|
|
37434
|
-
const cachePath =
|
|
37435
|
-
|
|
37436
|
-
const overlayPath =
|
|
37600
|
+
const cachePath = import_node_path72.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
37601
|
+
import_node_fs59.default.mkdirSync(cachePath, { recursive: true });
|
|
37602
|
+
const overlayPath = import_node_path72.default.join(cachePath, "compose.devrouter.yml");
|
|
37437
37603
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
37438
|
-
|
|
37604
|
+
import_node_fs59.default.writeFileSync(overlayPath, import_yaml13.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
37439
37605
|
return {
|
|
37440
37606
|
overlayPath,
|
|
37441
37607
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -37449,7 +37615,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37449
37615
|
fileArgs.push("-f", resolved2);
|
|
37450
37616
|
}
|
|
37451
37617
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
37452
|
-
const result = (0,
|
|
37618
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37453
37619
|
encoding: "utf-8",
|
|
37454
37620
|
cwd: repoPath
|
|
37455
37621
|
});
|
|
@@ -37477,7 +37643,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
37477
37643
|
"--services",
|
|
37478
37644
|
...services
|
|
37479
37645
|
];
|
|
37480
|
-
const result = (0,
|
|
37646
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37481
37647
|
encoding: "utf-8",
|
|
37482
37648
|
cwd: repoPath
|
|
37483
37649
|
});
|
|
@@ -37503,7 +37669,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37503
37669
|
fileArgs.push("-f", resolved2);
|
|
37504
37670
|
}
|
|
37505
37671
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
37506
|
-
const result = (0,
|
|
37672
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37507
37673
|
encoding: "utf-8",
|
|
37508
37674
|
cwd: repoPath
|
|
37509
37675
|
});
|
|
@@ -37529,7 +37695,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
37529
37695
|
String(tail),
|
|
37530
37696
|
...services
|
|
37531
37697
|
];
|
|
37532
|
-
(0,
|
|
37698
|
+
(0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37533
37699
|
stdio: "inherit",
|
|
37534
37700
|
cwd: repoPath
|
|
37535
37701
|
});
|
|
@@ -37541,7 +37707,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37541
37707
|
fileArgs.push("-f", resolved2);
|
|
37542
37708
|
}
|
|
37543
37709
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
37544
|
-
const result = (0,
|
|
37710
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37545
37711
|
encoding: "utf-8",
|
|
37546
37712
|
cwd: repoPath
|
|
37547
37713
|
});
|
|
@@ -37555,15 +37721,15 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37555
37721
|
const port = Number(match[1]);
|
|
37556
37722
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
37557
37723
|
}
|
|
37558
|
-
var
|
|
37724
|
+
var import_node_child_process44, import_node_crypto41, import_node_fs59, import_node_path72, import_yaml13;
|
|
37559
37725
|
var init_docker_run = __esm({
|
|
37560
37726
|
"src/core/docker-run.ts"() {
|
|
37561
37727
|
"use strict";
|
|
37562
|
-
|
|
37563
|
-
|
|
37564
|
-
|
|
37565
|
-
|
|
37566
|
-
|
|
37728
|
+
import_node_child_process44 = require("child_process");
|
|
37729
|
+
import_node_crypto41 = require("crypto");
|
|
37730
|
+
import_node_fs59 = __toESM(require("fs"));
|
|
37731
|
+
import_node_path72 = __toESM(require("path"));
|
|
37732
|
+
import_yaml13 = __toESM(require("yaml"));
|
|
37567
37733
|
init_docker_error_guidance();
|
|
37568
37734
|
init_paths();
|
|
37569
37735
|
init_router();
|
|
@@ -37652,7 +37818,7 @@ function isProcessRunning(pid) {
|
|
|
37652
37818
|
}
|
|
37653
37819
|
}
|
|
37654
37820
|
function readProcessTree(rootPid) {
|
|
37655
|
-
const result = (0,
|
|
37821
|
+
const result = (0, import_node_child_process45.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
37656
37822
|
if (result.status !== 0) {
|
|
37657
37823
|
return [rootPid];
|
|
37658
37824
|
}
|
|
@@ -37763,12 +37929,12 @@ function detectListeningPorts(pids) {
|
|
|
37763
37929
|
if (pids.length === 0) {
|
|
37764
37930
|
return [];
|
|
37765
37931
|
}
|
|
37766
|
-
const result = (0,
|
|
37932
|
+
const result = (0, import_node_child_process45.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
37767
37933
|
encoding: "utf-8"
|
|
37768
37934
|
});
|
|
37769
37935
|
if (result.error && result.error.code === "ENOENT") {
|
|
37770
37936
|
if (process.platform === "linux") {
|
|
37771
|
-
const ssResult = (0,
|
|
37937
|
+
const ssResult = (0, import_node_child_process45.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
37772
37938
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
37773
37939
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
37774
37940
|
}
|
|
@@ -37827,7 +37993,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
37827
37993
|
app.hostRun.command,
|
|
37828
37994
|
true
|
|
37829
37995
|
) : app.hostRun.command;
|
|
37830
|
-
const child = (0,
|
|
37996
|
+
const child = (0, import_node_child_process45.spawn)(spawnCommand, {
|
|
37831
37997
|
cwd: commandCwd,
|
|
37832
37998
|
stdio: "inherit",
|
|
37833
37999
|
shell: true,
|
|
@@ -38195,7 +38361,7 @@ async function execWithAppEnv(options) {
|
|
|
38195
38361
|
options.command[0],
|
|
38196
38362
|
true
|
|
38197
38363
|
);
|
|
38198
|
-
child = (0,
|
|
38364
|
+
child = (0, import_node_child_process45.spawn)(wrapped, {
|
|
38199
38365
|
cwd: deps.repoPath,
|
|
38200
38366
|
stdio: "inherit",
|
|
38201
38367
|
shell: true,
|
|
@@ -38209,7 +38375,7 @@ async function execWithAppEnv(options) {
|
|
|
38209
38375
|
false
|
|
38210
38376
|
);
|
|
38211
38377
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
38212
|
-
child = (0,
|
|
38378
|
+
child = (0, import_node_child_process45.spawn)(cmd, wrappedArgs, {
|
|
38213
38379
|
cwd: deps.repoPath,
|
|
38214
38380
|
stdio: "inherit",
|
|
38215
38381
|
shell: false,
|
|
@@ -38217,7 +38383,7 @@ async function execWithAppEnv(options) {
|
|
|
38217
38383
|
});
|
|
38218
38384
|
}
|
|
38219
38385
|
} else if (options.shell) {
|
|
38220
|
-
child = (0,
|
|
38386
|
+
child = (0, import_node_child_process45.spawn)(options.command[0], {
|
|
38221
38387
|
cwd: deps.repoPath,
|
|
38222
38388
|
stdio: "inherit",
|
|
38223
38389
|
shell: true,
|
|
@@ -38225,7 +38391,7 @@ async function execWithAppEnv(options) {
|
|
|
38225
38391
|
});
|
|
38226
38392
|
} else {
|
|
38227
38393
|
const [command, ...args] = options.command;
|
|
38228
|
-
child = (0,
|
|
38394
|
+
child = (0, import_node_child_process45.spawn)(command, args, {
|
|
38229
38395
|
cwd: deps.repoPath,
|
|
38230
38396
|
stdio: "inherit",
|
|
38231
38397
|
shell: false,
|
|
@@ -38246,11 +38412,11 @@ async function execWithAppEnv(options) {
|
|
|
38246
38412
|
deps.stopDeps();
|
|
38247
38413
|
}
|
|
38248
38414
|
}
|
|
38249
|
-
var
|
|
38415
|
+
var import_node_child_process45, import_node_net6, import_node_process, import_promises, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
|
|
38250
38416
|
var init_app_run = __esm({
|
|
38251
38417
|
"src/core/app-run.ts"() {
|
|
38252
38418
|
"use strict";
|
|
38253
|
-
|
|
38419
|
+
import_node_child_process45 = require("child_process");
|
|
38254
38420
|
import_node_net6 = __toESM(require("net"));
|
|
38255
38421
|
import_node_process = require("process");
|
|
38256
38422
|
import_promises = require("readline/promises");
|
|
@@ -38396,7 +38562,7 @@ function canonicalJson(value) {
|
|
|
38396
38562
|
`;
|
|
38397
38563
|
}
|
|
38398
38564
|
function sha256Hex(raw) {
|
|
38399
|
-
return (0,
|
|
38565
|
+
return (0, import_node_crypto42.createHash)("sha256").update(raw).digest("hex");
|
|
38400
38566
|
}
|
|
38401
38567
|
function candidateId(candidate) {
|
|
38402
38568
|
const identity2 = {
|
|
@@ -38458,7 +38624,7 @@ function validateCandidate(value, index, action2, legacy) {
|
|
|
38458
38624
|
}
|
|
38459
38625
|
}
|
|
38460
38626
|
for (const key of ["repo", "path", "commonDir", "gitDir"]) {
|
|
38461
|
-
if (!
|
|
38627
|
+
if (!import_node_path73.default.isAbsolute(candidate[key])) {
|
|
38462
38628
|
throw new Error(`${label2}.${key} must be an absolute path`);
|
|
38463
38629
|
}
|
|
38464
38630
|
}
|
|
@@ -38564,7 +38730,7 @@ function validateManifest(value) {
|
|
|
38564
38730
|
return root;
|
|
38565
38731
|
}
|
|
38566
38732
|
function readManifest(file) {
|
|
38567
|
-
const raw =
|
|
38733
|
+
const raw = import_node_fs60.default.readFileSync(file);
|
|
38568
38734
|
let parsed;
|
|
38569
38735
|
try {
|
|
38570
38736
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -38603,7 +38769,7 @@ function selectManifest(file, expectedSha256, ids2) {
|
|
|
38603
38769
|
return canonicalJson(subset);
|
|
38604
38770
|
}
|
|
38605
38771
|
function gitLine(cwd, args) {
|
|
38606
|
-
const result = (0,
|
|
38772
|
+
const result = (0, import_node_child_process46.spawnSync)("git", ["-C", cwd, ...args], {
|
|
38607
38773
|
encoding: "utf-8",
|
|
38608
38774
|
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
38609
38775
|
});
|
|
@@ -38611,7 +38777,7 @@ function gitLine(cwd, args) {
|
|
|
38611
38777
|
return result.status === 0 && !result.error && output2 ? output2 : void 0;
|
|
38612
38778
|
}
|
|
38613
38779
|
function readWorktreeIdentity(worktreePath) {
|
|
38614
|
-
if (!
|
|
38780
|
+
if (!import_node_fs60.default.existsSync(worktreePath)) return void 0;
|
|
38615
38781
|
const real = comparableWorkspacePath(worktreePath);
|
|
38616
38782
|
const commonDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
38617
38783
|
const gitDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-dir"]);
|
|
@@ -38631,13 +38797,13 @@ function identityMismatch(expected, actual) {
|
|
|
38631
38797
|
function unmanagedActivityEpoch(worktreePath, gitDir) {
|
|
38632
38798
|
let latest;
|
|
38633
38799
|
for (const file of [
|
|
38634
|
-
|
|
38635
|
-
|
|
38636
|
-
|
|
38800
|
+
import_node_path73.default.join(gitDir, "index"),
|
|
38801
|
+
import_node_path73.default.join(gitDir, "HEAD"),
|
|
38802
|
+
import_node_path73.default.join(gitDir, "logs", "HEAD"),
|
|
38637
38803
|
worktreePath
|
|
38638
38804
|
]) {
|
|
38639
38805
|
try {
|
|
38640
|
-
const seconds = Math.floor(
|
|
38806
|
+
const seconds = Math.floor(import_node_fs60.default.statSync(file).mtimeMs / 1e3);
|
|
38641
38807
|
latest = latest === void 0 ? seconds : Math.max(latest, seconds);
|
|
38642
38808
|
} catch {
|
|
38643
38809
|
}
|
|
@@ -38691,12 +38857,12 @@ function buildReclaimManifest(report, createdAtEpoch) {
|
|
|
38691
38857
|
return canonicalJson(manifest);
|
|
38692
38858
|
}
|
|
38693
38859
|
function receiptPath(commonDir, manifestSha256, id5) {
|
|
38694
|
-
return
|
|
38860
|
+
return import_node_path73.default.join(commonDir, "worktree-reclaim", "receipts", manifestSha256, `${id5}.json`);
|
|
38695
38861
|
}
|
|
38696
38862
|
function matchingReceipt(candidate, manifestSha256) {
|
|
38697
38863
|
try {
|
|
38698
38864
|
const receipt = JSON.parse(
|
|
38699
|
-
|
|
38865
|
+
import_node_fs60.default.readFileSync(receiptPath(candidate.commonDir, manifestSha256, candidate.id), "utf-8")
|
|
38700
38866
|
);
|
|
38701
38867
|
return receipt.kind === RECEIPT_KIND && receipt.schemaVersion === SCHEMA_VERSION && receipt.manifestSha256 === manifestSha256 && receipt.candidateId === candidate.id && receipt.path === candidate.path && receipt.head === candidate.head;
|
|
38702
38868
|
} catch {
|
|
@@ -38705,7 +38871,7 @@ function matchingReceipt(candidate, manifestSha256) {
|
|
|
38705
38871
|
}
|
|
38706
38872
|
function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
38707
38873
|
const file = receiptPath(candidate.commonDir, manifestSha256, candidate.id);
|
|
38708
|
-
|
|
38874
|
+
import_node_fs60.default.mkdirSync(import_node_path73.default.dirname(file), { recursive: true });
|
|
38709
38875
|
writeFileAtomically(
|
|
38710
38876
|
file,
|
|
38711
38877
|
canonicalJson({
|
|
@@ -38723,7 +38889,7 @@ function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
|
38723
38889
|
);
|
|
38724
38890
|
}
|
|
38725
38891
|
function runVetoCommand(command, worktreePath) {
|
|
38726
|
-
const result = (0,
|
|
38892
|
+
const result = (0, import_node_child_process46.spawnSync)(command, [worktreePath], {
|
|
38727
38893
|
stdio: ["ignore", "ignore", "inherit"],
|
|
38728
38894
|
timeout: VETO_TIMEOUT_MS
|
|
38729
38895
|
});
|
|
@@ -38736,9 +38902,9 @@ function runVetoCommand(command, worktreePath) {
|
|
|
38736
38902
|
return result.status === 0 && !result.error && result.signal === null;
|
|
38737
38903
|
}
|
|
38738
38904
|
function assertVetoCommand(command) {
|
|
38739
|
-
if (!
|
|
38905
|
+
if (!import_node_path73.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
|
|
38740
38906
|
try {
|
|
38741
|
-
|
|
38907
|
+
import_node_fs60.default.accessSync(command, import_node_fs60.default.constants.X_OK);
|
|
38742
38908
|
} catch {
|
|
38743
38909
|
throw new Error(`--veto-command '${command}' is missing or not executable`);
|
|
38744
38910
|
}
|
|
@@ -38764,7 +38930,7 @@ function preflightManifestApply(options, action2, nowEpoch) {
|
|
|
38764
38930
|
return { manifest, manifestSha256, now };
|
|
38765
38931
|
}
|
|
38766
38932
|
function deleteBranchIfUnmoved(candidate, steps) {
|
|
38767
|
-
const exists2 = (0,
|
|
38933
|
+
const exists2 = (0, import_node_child_process46.spawnSync)(
|
|
38768
38934
|
"git",
|
|
38769
38935
|
["-C", candidate.repo, "show-ref", "--verify", "--quiet", candidate.branchRef],
|
|
38770
38936
|
{ encoding: "utf-8" }
|
|
@@ -38773,7 +38939,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38773
38939
|
if (exists2.status !== 0) {
|
|
38774
38940
|
throw new Error(`cannot read branch ${candidate.branch}: ${(exists2.stderr ?? "").trim()}`);
|
|
38775
38941
|
}
|
|
38776
|
-
const result = (0,
|
|
38942
|
+
const result = (0, import_node_child_process46.spawnSync)(
|
|
38777
38943
|
"git",
|
|
38778
38944
|
["-C", candidate.repo, "update-ref", "-d", candidate.branchRef, candidate.head],
|
|
38779
38945
|
{ encoding: "utf-8" }
|
|
@@ -38782,7 +38948,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38782
38948
|
return `branch ${candidate.branch} no longer points at the approved HEAD; it was kept for review`;
|
|
38783
38949
|
}
|
|
38784
38950
|
steps.push("branch-deleted");
|
|
38785
|
-
(0,
|
|
38951
|
+
(0, import_node_child_process46.spawnSync)(
|
|
38786
38952
|
"git",
|
|
38787
38953
|
["-C", candidate.repo, "config", "--remove-section", `branch.${candidate.branch}`],
|
|
38788
38954
|
{ encoding: "utf-8" }
|
|
@@ -38820,7 +38986,7 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38820
38986
|
outcome.status = "not-attempted";
|
|
38821
38987
|
continue;
|
|
38822
38988
|
}
|
|
38823
|
-
if (!
|
|
38989
|
+
if (!import_node_fs60.default.existsSync(candidate.path) && matchingReceipt(candidate, manifestSha256)) {
|
|
38824
38990
|
outcome.status = "already-done";
|
|
38825
38991
|
continue;
|
|
38826
38992
|
}
|
|
@@ -38889,14 +39055,14 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38889
39055
|
}
|
|
38890
39056
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
38891
39057
|
}
|
|
38892
|
-
var
|
|
39058
|
+
var import_node_child_process46, import_node_crypto42, import_node_fs60, 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;
|
|
38893
39059
|
var init_worktree_reclaim = __esm({
|
|
38894
39060
|
"src/core/worktree-reclaim.ts"() {
|
|
38895
39061
|
"use strict";
|
|
38896
|
-
|
|
38897
|
-
|
|
38898
|
-
|
|
38899
|
-
|
|
39062
|
+
import_node_child_process46 = require("child_process");
|
|
39063
|
+
import_node_crypto42 = require("crypto");
|
|
39064
|
+
import_node_fs60 = __toESM(require("fs"));
|
|
39065
|
+
import_node_path73 = __toESM(require("path"));
|
|
38900
39066
|
init_atomic_file();
|
|
38901
39067
|
init_workspace();
|
|
38902
39068
|
MANIFEST_KIND = "worktree-reclaim-manifest";
|
|
@@ -39016,8 +39182,8 @@ function checkoutOf(workingDir) {
|
|
|
39016
39182
|
return workingDir.replace(/\/+$/, "").replace(/\/\.devcontainer$/, "");
|
|
39017
39183
|
}
|
|
39018
39184
|
function isInsideOrEqual(parent, child) {
|
|
39019
|
-
const relative2 =
|
|
39020
|
-
return relative2 === "" || !relative2.startsWith("..") && !
|
|
39185
|
+
const relative2 = import_node_path74.default.relative(parent, child);
|
|
39186
|
+
return relative2 === "" || !relative2.startsWith("..") && !import_node_path74.default.isAbsolute(relative2);
|
|
39021
39187
|
}
|
|
39022
39188
|
function isAnonymousVolume(volume) {
|
|
39023
39189
|
return /^[0-9a-f]{64}$/.test(volume.name) && !volume.labels[PROJECT_LABEL];
|
|
@@ -39029,9 +39195,9 @@ function vanishedInsideTrees(checkout, context) {
|
|
|
39029
39195
|
(prefix) => checkout !== prefix && isInsideOrEqual(prefix, checkout)
|
|
39030
39196
|
);
|
|
39031
39197
|
if (!lexical || context.exists(checkout)) return "out-of-scope";
|
|
39032
|
-
let ancestor =
|
|
39198
|
+
let ancestor = import_node_path74.default.dirname(checkout);
|
|
39033
39199
|
while (!context.exists(ancestor)) {
|
|
39034
|
-
const parent =
|
|
39200
|
+
const parent = import_node_path74.default.dirname(ancestor);
|
|
39035
39201
|
if (parent === ancestor) return "out-of-scope";
|
|
39036
39202
|
ancestor = parent;
|
|
39037
39203
|
}
|
|
@@ -39039,16 +39205,16 @@ function vanishedInsideTrees(checkout, context) {
|
|
|
39039
39205
|
if (ancestorReal === void 0 || !isInsideOrEqual(treesReal, ancestorReal)) {
|
|
39040
39206
|
return "out-of-scope";
|
|
39041
39207
|
}
|
|
39042
|
-
for (let current = ancestor; ; current =
|
|
39208
|
+
for (let current = ancestor; ; current = import_node_path74.default.dirname(current)) {
|
|
39043
39209
|
const real = context.realpath(current);
|
|
39044
39210
|
if (real === void 0 || real === treesReal || !isInsideOrEqual(treesReal, real)) break;
|
|
39045
|
-
if (context.exists(
|
|
39211
|
+
if (context.exists(import_node_path74.default.join(current, ".git"))) return "inside-worktree";
|
|
39046
39212
|
}
|
|
39047
39213
|
return "vanished";
|
|
39048
39214
|
}
|
|
39049
39215
|
function resolved(file, context) {
|
|
39050
39216
|
const real = context.realpath(file);
|
|
39051
|
-
return real && real !==
|
|
39217
|
+
return real && real !== import_node_path74.default.resolve(file) ? [import_node_path74.default.resolve(file), real] : [import_node_path74.default.resolve(file)];
|
|
39052
39218
|
}
|
|
39053
39219
|
function relation(entry, checkout, context) {
|
|
39054
39220
|
const entries = resolved(entry, context);
|
|
@@ -39153,21 +39319,21 @@ function readLeftoverContext(repoPath) {
|
|
|
39153
39319
|
resetWorkspaceRuntimeCaches();
|
|
39154
39320
|
const snapshots = getWorkspaceRegistrySnapshots();
|
|
39155
39321
|
return {
|
|
39156
|
-
treesPath:
|
|
39322
|
+
treesPath: import_node_path74.default.join(repoPath, "trees"),
|
|
39157
39323
|
worktreePaths: listGitWorktrees(repoPath).map((worktree) => worktree.path),
|
|
39158
39324
|
ownershipPaths: listWorkspaceOwnership(repoPath).map((record6) => record6.worktreePath),
|
|
39159
39325
|
providerPaths: listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
39160
39326
|
registriesReadable: snapshots.unavailable.length === 0,
|
|
39161
39327
|
realpath: (file) => {
|
|
39162
39328
|
try {
|
|
39163
|
-
return
|
|
39329
|
+
return import_node_fs61.default.realpathSync.native(file);
|
|
39164
39330
|
} catch {
|
|
39165
39331
|
return void 0;
|
|
39166
39332
|
}
|
|
39167
39333
|
},
|
|
39168
39334
|
exists: (file) => {
|
|
39169
39335
|
try {
|
|
39170
|
-
|
|
39336
|
+
import_node_fs61.default.lstatSync(file);
|
|
39171
39337
|
return true;
|
|
39172
39338
|
} catch (error) {
|
|
39173
39339
|
return error.code !== "ENOENT";
|
|
@@ -39231,7 +39397,7 @@ function validateLeftoverManifest(value) {
|
|
|
39231
39397
|
throw new Error(`manifest schemaVersion must be ${SCHEMA_VERSION2}`);
|
|
39232
39398
|
}
|
|
39233
39399
|
requireString(root.repo, "manifest repo");
|
|
39234
|
-
if (!
|
|
39400
|
+
if (!import_node_path74.default.isAbsolute(root.repo)) throw new Error("manifest repo must be an absolute path");
|
|
39235
39401
|
requireString(root.daemonId, "manifest daemonId");
|
|
39236
39402
|
if (!Number.isInteger(root.createdAtEpoch) || root.createdAtEpoch < 0) {
|
|
39237
39403
|
throw new Error("manifest createdAtEpoch must be a non-negative integer");
|
|
@@ -39253,7 +39419,7 @@ function validateLeftoverManifest(value) {
|
|
|
39253
39419
|
);
|
|
39254
39420
|
requireString(candidate.project, `${label2}.project`);
|
|
39255
39421
|
requireString(candidate.checkout, `${label2}.checkout`);
|
|
39256
|
-
if (!
|
|
39422
|
+
if (!import_node_path74.default.isAbsolute(candidate.checkout)) {
|
|
39257
39423
|
throw new Error(`${label2}.checkout must be an absolute path`);
|
|
39258
39424
|
}
|
|
39259
39425
|
const members = [
|
|
@@ -39291,7 +39457,7 @@ function validateLeftoverManifest(value) {
|
|
|
39291
39457
|
return root;
|
|
39292
39458
|
}
|
|
39293
39459
|
function readLeftoverManifest(file) {
|
|
39294
|
-
const raw =
|
|
39460
|
+
const raw = import_node_fs61.default.readFileSync(file);
|
|
39295
39461
|
let parsed;
|
|
39296
39462
|
try {
|
|
39297
39463
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -39305,7 +39471,7 @@ function readLeftoverManifest(file) {
|
|
|
39305
39471
|
return { raw, manifest };
|
|
39306
39472
|
}
|
|
39307
39473
|
function gitCommonDir(repo) {
|
|
39308
|
-
const result = (0,
|
|
39474
|
+
const result = (0, import_node_child_process47.spawnSync)(
|
|
39309
39475
|
"git",
|
|
39310
39476
|
["-C", repo, "rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
39311
39477
|
{ encoding: "utf-8" }
|
|
@@ -39334,7 +39500,7 @@ function currentRemovals(candidate, inventory, context) {
|
|
|
39334
39500
|
throw new LeftoverSkip("changed", "the checkout folder exists again");
|
|
39335
39501
|
}
|
|
39336
39502
|
const mounted = new Set(inventory.containers.flatMap((container) => container.volumes));
|
|
39337
|
-
const ours = (
|
|
39503
|
+
const ours = (object6) => object6.labels[PROJECT_LABEL] === candidate.project && object6.name.startsWith(`${candidate.project}_`);
|
|
39338
39504
|
current = {
|
|
39339
39505
|
project: candidate.project,
|
|
39340
39506
|
checkout: candidate.checkout,
|
|
@@ -39473,11 +39639,11 @@ function applyLeftoverManifest(options, dependencies = {}) {
|
|
|
39473
39639
|
return { manifestSha256, dryRun: !options.yes, targets };
|
|
39474
39640
|
}
|
|
39475
39641
|
function leftoverReceiptPath(commonDir, manifestSha256, id5) {
|
|
39476
|
-
return
|
|
39642
|
+
return import_node_path74.default.join(commonDir, "devrouter-leftovers", "receipts", manifestSha256, `${id5}.json`);
|
|
39477
39643
|
}
|
|
39478
39644
|
function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEpoch) {
|
|
39479
39645
|
const file = leftoverReceiptPath(commonDir, manifestSha256, candidate.id);
|
|
39480
|
-
|
|
39646
|
+
import_node_fs61.default.mkdirSync(import_node_path74.default.dirname(file), { recursive: true });
|
|
39481
39647
|
writeFileAtomically(
|
|
39482
39648
|
file,
|
|
39483
39649
|
canonicalJson({
|
|
@@ -39493,13 +39659,13 @@ function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEp
|
|
|
39493
39659
|
})
|
|
39494
39660
|
);
|
|
39495
39661
|
}
|
|
39496
|
-
var
|
|
39662
|
+
var import_node_child_process47, import_node_fs61, 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;
|
|
39497
39663
|
var init_docker_leftovers = __esm({
|
|
39498
39664
|
"src/core/docker-leftovers.ts"() {
|
|
39499
39665
|
"use strict";
|
|
39500
|
-
|
|
39501
|
-
|
|
39502
|
-
|
|
39666
|
+
import_node_child_process47 = require("child_process");
|
|
39667
|
+
import_node_fs61 = __toESM(require("fs"));
|
|
39668
|
+
import_node_path74 = __toESM(require("path"));
|
|
39503
39669
|
init_atomic_file();
|
|
39504
39670
|
init_devpod_mutation();
|
|
39505
39671
|
init_devpod_workspaces();
|
|
@@ -39520,7 +39686,7 @@ var init_docker_leftovers = __esm({
|
|
|
39520
39686
|
DockerListingBoundError = class extends Error {
|
|
39521
39687
|
};
|
|
39522
39688
|
defaultDockerRunner = (args) => {
|
|
39523
|
-
const result = (0,
|
|
39689
|
+
const result = (0, import_node_child_process47.spawnSync)("docker", args, {
|
|
39524
39690
|
encoding: "utf-8",
|
|
39525
39691
|
timeout: 6e4,
|
|
39526
39692
|
maxBuffer: 256 * 1024 * 1024
|
|
@@ -39551,13 +39717,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39551
39717
|
const startedAt = Date.now();
|
|
39552
39718
|
let rootStat;
|
|
39553
39719
|
try {
|
|
39554
|
-
rootStat =
|
|
39720
|
+
rootStat = import_node_fs62.default.lstatSync(worktreePath);
|
|
39555
39721
|
} catch (error) {
|
|
39556
39722
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39557
39723
|
}
|
|
39558
39724
|
let rootEntries;
|
|
39559
39725
|
try {
|
|
39560
|
-
rootEntries =
|
|
39726
|
+
rootEntries = import_node_fs62.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
39561
39727
|
} catch (error) {
|
|
39562
39728
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39563
39729
|
}
|
|
@@ -39583,10 +39749,10 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39583
39749
|
timedOut = true;
|
|
39584
39750
|
break;
|
|
39585
39751
|
}
|
|
39586
|
-
const entryPath =
|
|
39752
|
+
const entryPath = import_node_path75.default.join(dirPath, entry.name);
|
|
39587
39753
|
let entryStat;
|
|
39588
39754
|
try {
|
|
39589
|
-
entryStat =
|
|
39755
|
+
entryStat = import_node_fs62.default.lstatSync(entryPath);
|
|
39590
39756
|
} catch (error) {
|
|
39591
39757
|
if (error?.code === "ENOENT") continue;
|
|
39592
39758
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -39596,7 +39762,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39596
39762
|
if (!entryStat.isDirectory()) continue;
|
|
39597
39763
|
let childEntries;
|
|
39598
39764
|
try {
|
|
39599
|
-
childEntries =
|
|
39765
|
+
childEntries = import_node_fs62.default.readdirSync(entryPath, { withFileTypes: true });
|
|
39600
39766
|
} catch (error) {
|
|
39601
39767
|
unreadableReason = describeIncompleteWalk(error);
|
|
39602
39768
|
break;
|
|
@@ -39660,12 +39826,12 @@ function describeError(error, worktreePath) {
|
|
|
39660
39826
|
}
|
|
39661
39827
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
39662
39828
|
}
|
|
39663
|
-
var
|
|
39829
|
+
var import_node_fs62, import_node_path75, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
39664
39830
|
var init_workspace_consumption = __esm({
|
|
39665
39831
|
"src/core/workspace-consumption.ts"() {
|
|
39666
39832
|
"use strict";
|
|
39667
|
-
|
|
39668
|
-
|
|
39833
|
+
import_node_fs62 = __toESM(require("fs"));
|
|
39834
|
+
import_node_path75 = __toESM(require("path"));
|
|
39669
39835
|
init_devpod_environment();
|
|
39670
39836
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
39671
39837
|
BLOCK_SIZE_BYTES = 512;
|
|
@@ -39751,7 +39917,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
39751
39917
|
}
|
|
39752
39918
|
function readGitSnapshot(worktree, commandRunner) {
|
|
39753
39919
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
39754
|
-
if (worktree.prunable || !
|
|
39920
|
+
if (worktree.prunable || !import_node_fs63.default.existsSync(comparablePath)) {
|
|
39755
39921
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
39756
39922
|
}
|
|
39757
39923
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -40324,7 +40490,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40324
40490
|
containers2 = measureContainersFn(worktreePaths);
|
|
40325
40491
|
} catch (error) {
|
|
40326
40492
|
const reason2 = `container measurement failed: ${describeCause(error)}`;
|
|
40327
|
-
containers2 = new Map(worktreePaths.map((
|
|
40493
|
+
containers2 = new Map(worktreePaths.map((path80) => [path80, unknownContainers(reason2)]));
|
|
40328
40494
|
}
|
|
40329
40495
|
}
|
|
40330
40496
|
const rows2 = records.map((record6) => {
|
|
@@ -40383,7 +40549,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40383
40549
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40384
40550
|
);
|
|
40385
40551
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40386
|
-
const disposable =
|
|
40552
|
+
const disposable = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40387
40553
|
const [primary, ...linked] = worktrees;
|
|
40388
40554
|
const safetyFor = (worktree, worktreePath, evidence) => toSafety(
|
|
40389
40555
|
classify({
|
|
@@ -40391,7 +40557,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40391
40557
|
branch: worktree?.branch,
|
|
40392
40558
|
primary: primary !== void 0 && sameWorkspacePath(primary.path, worktreePath),
|
|
40393
40559
|
locked: worktree?.locked ?? false,
|
|
40394
|
-
missing: !worktree || worktree.prunable || !
|
|
40560
|
+
missing: !worktree || worktree.prunable || !import_node_fs63.default.existsSync(worktreePath),
|
|
40395
40561
|
runtimeEvidence: evidence,
|
|
40396
40562
|
forge,
|
|
40397
40563
|
extraDisposablePatterns: disposable
|
|
@@ -40452,7 +40618,7 @@ function readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies) {
|
|
|
40452
40618
|
}
|
|
40453
40619
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40454
40620
|
const cutoffEpoch = Math.floor(Date.now() / 1e3) - parseInactiveFor(inactiveFor).seconds;
|
|
40455
|
-
const gitDir = (0,
|
|
40621
|
+
const gitDir = (0, import_node_child_process48.spawnSync)(
|
|
40456
40622
|
"git",
|
|
40457
40623
|
["-C", worktreePath, "rev-parse", "--path-format=absolute", "--git-dir"],
|
|
40458
40624
|
{ encoding: "utf-8", env: READ_ONLY_GIT_ENV2 }
|
|
@@ -40472,7 +40638,7 @@ function classifyExactPath(repoPath, worktreePath, evidence, forge, extraDisposa
|
|
|
40472
40638
|
branch: worktree?.branch,
|
|
40473
40639
|
primary: worktrees[0] !== void 0 && sameWorkspacePath(worktrees[0].path, worktreePath),
|
|
40474
40640
|
locked: worktree?.locked ?? false,
|
|
40475
|
-
missing: !worktree || worktree.prunable || !
|
|
40641
|
+
missing: !worktree || worktree.prunable || !import_node_fs63.default.existsSync(worktreePath),
|
|
40476
40642
|
runtimeEvidence: evidence.runtimeEvidence,
|
|
40477
40643
|
forge,
|
|
40478
40644
|
extraDisposablePatterns
|
|
@@ -40498,7 +40664,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40498
40664
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40499
40665
|
);
|
|
40500
40666
|
const forge = evidence.status === "not-checked" ? { status: "unavailable", reason: "forge not checked" } : evidence;
|
|
40501
|
-
const disposable =
|
|
40667
|
+
const disposable = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40502
40668
|
const paths = evidenceCache(
|
|
40503
40669
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
40504
40670
|
);
|
|
@@ -40517,7 +40683,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40517
40683
|
}
|
|
40518
40684
|
function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
40519
40685
|
const repoPath = resolveRepoPath(repo);
|
|
40520
|
-
const configured =
|
|
40686
|
+
const configured = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
40521
40687
|
const patterns = configured?.trim ?? [];
|
|
40522
40688
|
const paths = evidenceCache(
|
|
40523
40689
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
@@ -40542,13 +40708,13 @@ function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
|
40542
40708
|
isActive: (worktreePath) => paths.last(worktreePath).active
|
|
40543
40709
|
};
|
|
40544
40710
|
}
|
|
40545
|
-
var
|
|
40711
|
+
var import_node_child_process48, import_node_fs63, import_node_path76, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
40546
40712
|
var init_workspace_cleanup = __esm({
|
|
40547
40713
|
"src/core/workspace-cleanup.ts"() {
|
|
40548
40714
|
"use strict";
|
|
40549
|
-
|
|
40550
|
-
|
|
40551
|
-
|
|
40715
|
+
import_node_child_process48 = require("child_process");
|
|
40716
|
+
import_node_fs63 = __toESM(require("fs"));
|
|
40717
|
+
import_node_path76 = __toESM(require("path"));
|
|
40552
40718
|
init_devpod_workspaces();
|
|
40553
40719
|
init_docker_leftovers();
|
|
40554
40720
|
init_duration();
|
|
@@ -40571,7 +40737,7 @@ var init_workspace_cleanup = __esm({
|
|
|
40571
40737
|
];
|
|
40572
40738
|
defaultCommandRunner = (command, args, input2) => {
|
|
40573
40739
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
40574
|
-
const result = (0,
|
|
40740
|
+
const result = (0, import_node_child_process48.spawnSync)(command, args, {
|
|
40575
40741
|
encoding: "utf-8",
|
|
40576
40742
|
env: environment,
|
|
40577
40743
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -40696,7 +40862,7 @@ function journalVetoes(record6) {
|
|
|
40696
40862
|
}
|
|
40697
40863
|
function readTraefikWindow(cutoffMs) {
|
|
40698
40864
|
const since = String(Math.floor(cutoffMs / 1e3));
|
|
40699
|
-
const run = (args, maxBuffer) => (0,
|
|
40865
|
+
const run = (args, maxBuffer) => (0, import_node_child_process49.spawnSync)("docker", ["logs", "--timestamps", ...args, ROUTER_CONTAINER_NAME], {
|
|
40700
40866
|
encoding: "utf-8",
|
|
40701
40867
|
maxBuffer,
|
|
40702
40868
|
...networkDockerOptions()
|
|
@@ -40865,13 +41031,13 @@ function setIdlePin(repoPath, pinned) {
|
|
|
40865
41031
|
}
|
|
40866
41032
|
);
|
|
40867
41033
|
}
|
|
40868
|
-
var
|
|
41034
|
+
var import_node_child_process49, import_node_fs64, import_node_path77, DEFAULT_IDLE_FOR, ACTIVITY_FILES, IdleStopSkipped, defaultDependencies;
|
|
40869
41035
|
var init_workspace_idle = __esm({
|
|
40870
41036
|
"src/core/workspace-idle.ts"() {
|
|
40871
41037
|
"use strict";
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
|
|
41038
|
+
import_node_child_process49 = require("child_process");
|
|
41039
|
+
import_node_fs64 = __toESM(require("fs"));
|
|
41040
|
+
import_node_path77 = __toESM(require("path"));
|
|
40875
41041
|
init_devpod_environment();
|
|
40876
41042
|
init_devpod_workspaces();
|
|
40877
41043
|
init_duration();
|
|
@@ -40892,7 +41058,7 @@ var init_workspace_idle = __esm({
|
|
|
40892
41058
|
readJournals: () => listReliabilityOperations(),
|
|
40893
41059
|
journalModifiedMs: (record6) => {
|
|
40894
41060
|
try {
|
|
40895
|
-
return
|
|
41061
|
+
return import_node_fs64.default.statSync(reliabilityOperationPath(record6.identity)).mtimeMs;
|
|
40896
41062
|
} catch {
|
|
40897
41063
|
return void 0;
|
|
40898
41064
|
}
|
|
@@ -40900,7 +41066,7 @@ var init_workspace_idle = __esm({
|
|
|
40900
41066
|
registryPaths: () => listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
40901
41067
|
inspectContainers: () => inspectWorkspaceContainers(),
|
|
40902
41068
|
statActivity: (containerId) => {
|
|
40903
|
-
const result = (0,
|
|
41069
|
+
const result = (0, import_node_child_process49.spawnSync)(
|
|
40904
41070
|
"docker",
|
|
40905
41071
|
["exec", containerId, "stat", "-c", "%Y", ...ACTIVITY_FILES],
|
|
40906
41072
|
{
|
|
@@ -40915,7 +41081,7 @@ var init_workspace_idle = __esm({
|
|
|
40915
41081
|
};
|
|
40916
41082
|
},
|
|
40917
41083
|
readTraefik: readTraefikWindow,
|
|
40918
|
-
isConfiguredCheckout: (repoPath) =>
|
|
41084
|
+
isConfiguredCheckout: (repoPath) => import_node_fs64.default.existsSync(import_node_path77.default.join(repoPath, ".devrouter.yml")),
|
|
40919
41085
|
gitCommonDir: (repoPath) => {
|
|
40920
41086
|
try {
|
|
40921
41087
|
return resolveGitCommonDir(repoPath);
|
|
@@ -41006,20 +41172,20 @@ function warnMissingWorkspaceOwnership(repoPath) {
|
|
|
41006
41172
|
);
|
|
41007
41173
|
}
|
|
41008
41174
|
function defaultWorktreePath(mainRepo, ws) {
|
|
41009
|
-
return
|
|
41175
|
+
return import_node_path78.default.join(mainRepo, "trees", ws);
|
|
41010
41176
|
}
|
|
41011
41177
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
41012
|
-
const ignored = (0,
|
|
41178
|
+
const ignored = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
41013
41179
|
encoding: "utf-8"
|
|
41014
41180
|
});
|
|
41015
41181
|
if (ignored.status !== 0) {
|
|
41016
41182
|
throw new Error(
|
|
41017
|
-
`Default worktree root '${
|
|
41183
|
+
`Default worktree root '${import_node_path78.default.join(mainRepo, "trees")}' is not ignored. Add 'trees/' to '${import_node_path78.default.join(mainRepo, ".gitignore")}' or use --path.`
|
|
41018
41184
|
);
|
|
41019
41185
|
}
|
|
41020
41186
|
}
|
|
41021
41187
|
function legacyDefaultWorktreePath(mainRepo, ws) {
|
|
41022
|
-
return
|
|
41188
|
+
return import_node_path78.default.join(import_node_path78.default.dirname(mainRepo), `${import_node_path78.default.basename(mainRepo)}-${ws}`);
|
|
41023
41189
|
}
|
|
41024
41190
|
function teardownFallbackPath(mainRepo, workspace) {
|
|
41025
41191
|
const candidates = [
|
|
@@ -41131,7 +41297,7 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
41131
41297
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
41132
41298
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
41133
41299
|
}
|
|
41134
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
41300
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs65.default.existsSync(target.worktreePath)) return;
|
|
41135
41301
|
if (target.worktree.locked) {
|
|
41136
41302
|
throw new Error(
|
|
41137
41303
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
@@ -41163,9 +41329,9 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41163
41329
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
41164
41330
|
);
|
|
41165
41331
|
const generatedPath = candidatePaths.find(
|
|
41166
|
-
(candidate) => !
|
|
41332
|
+
(candidate) => !import_node_fs65.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
41167
41333
|
);
|
|
41168
|
-
const selectedPath = opts.path ?
|
|
41334
|
+
const selectedPath = opts.path ? import_node_path78.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
41169
41335
|
if (!selectedPath) {
|
|
41170
41336
|
throw new Error(`Could not allocate a collision-safe worktree path for branch '${branch}'.`);
|
|
41171
41337
|
}
|
|
@@ -41174,7 +41340,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41174
41340
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
41175
41341
|
);
|
|
41176
41342
|
}
|
|
41177
|
-
if (
|
|
41343
|
+
if (import_node_fs65.default.existsSync(selectedPath)) {
|
|
41178
41344
|
const registered = worktrees.find(
|
|
41179
41345
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
41180
41346
|
);
|
|
@@ -41193,11 +41359,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41193
41359
|
return selectedPath;
|
|
41194
41360
|
}
|
|
41195
41361
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
41196
|
-
const add2 = (0,
|
|
41362
|
+
const add2 = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
41197
41363
|
encoding: "utf-8"
|
|
41198
41364
|
});
|
|
41199
41365
|
if (add2.status !== 0) {
|
|
41200
|
-
const addNew = (0,
|
|
41366
|
+
const addNew = (0, import_node_child_process50.spawnSync)(
|
|
41201
41367
|
"git",
|
|
41202
41368
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
41203
41369
|
{ encoding: "utf-8" }
|
|
@@ -41337,8 +41503,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41337
41503
|
}
|
|
41338
41504
|
const result = await mutateWorkspaceRuntime("delete", resolved2, worktrees, opts.quiet);
|
|
41339
41505
|
if (removeWorktree) {
|
|
41340
|
-
if (resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41341
|
-
const rm = (0,
|
|
41506
|
+
if (resolved2.worktree && !resolved2.worktree.prunable && import_node_fs65.default.existsSync(resolved2.worktreePath)) {
|
|
41507
|
+
const rm = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved2.worktreePath], {
|
|
41342
41508
|
encoding: "utf-8"
|
|
41343
41509
|
});
|
|
41344
41510
|
if (rm.status !== 0) {
|
|
@@ -41356,7 +41522,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41356
41522
|
}
|
|
41357
41523
|
return result;
|
|
41358
41524
|
};
|
|
41359
|
-
return resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41525
|
+
return resolved2.worktree && !resolved2.worktree.prunable && import_node_fs65.default.existsSync(resolved2.worktreePath) ? withLifecycleOperationLock(resolved2.worktreePath, operation) : operation();
|
|
41360
41526
|
}
|
|
41361
41527
|
async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRemove, steps) {
|
|
41362
41528
|
await withLifecycleOperationLock(worktreePath, async () => {
|
|
@@ -41382,7 +41548,7 @@ async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRem
|
|
|
41382
41548
|
);
|
|
41383
41549
|
steps.push("runtime-deleted");
|
|
41384
41550
|
}
|
|
41385
|
-
const rm = (0,
|
|
41551
|
+
const rm = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", worktreePath], {
|
|
41386
41552
|
encoding: "utf-8"
|
|
41387
41553
|
});
|
|
41388
41554
|
if (rm.status !== 0) {
|
|
@@ -41403,13 +41569,13 @@ async function workspaceStop(target, opts = {}) {
|
|
|
41403
41569
|
async function workspaceDown(target, opts = {}) {
|
|
41404
41570
|
return runWorkspaceLifecycle("down", target, opts);
|
|
41405
41571
|
}
|
|
41406
|
-
var
|
|
41572
|
+
var import_node_child_process50, import_node_fs65, import_node_path78, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
41407
41573
|
var init_workspace_lifecycle = __esm({
|
|
41408
41574
|
"src/core/workspace-lifecycle.ts"() {
|
|
41409
41575
|
"use strict";
|
|
41410
|
-
|
|
41411
|
-
|
|
41412
|
-
|
|
41576
|
+
import_node_child_process50 = require("child_process");
|
|
41577
|
+
import_node_fs65 = __toESM(require("fs"));
|
|
41578
|
+
import_node_path78 = __toESM(require("path"));
|
|
41413
41579
|
init_devpod_mutation();
|
|
41414
41580
|
init_devpod_workspaces();
|
|
41415
41581
|
init_devsy_mutation();
|
|
@@ -41428,7 +41594,7 @@ var init_workspace_lifecycle = __esm({
|
|
|
41428
41594
|
|
|
41429
41595
|
// src/core/worktree-trim.ts
|
|
41430
41596
|
function listIgnoredPaths(worktreePath) {
|
|
41431
|
-
const result = (0,
|
|
41597
|
+
const result = (0, import_node_child_process51.spawnSync)(
|
|
41432
41598
|
"git",
|
|
41433
41599
|
[
|
|
41434
41600
|
"-C",
|
|
@@ -41512,19 +41678,19 @@ function buildTrimManifest(report, patterns, createdAtEpoch) {
|
|
|
41512
41678
|
return canonicalJson(manifest);
|
|
41513
41679
|
}
|
|
41514
41680
|
function isInside(parent, child) {
|
|
41515
|
-
const relative2 =
|
|
41516
|
-
return relative2 !== "" && !relative2.startsWith("..") && !
|
|
41681
|
+
const relative2 = import_node_path79.default.relative(parent, child);
|
|
41682
|
+
return relative2 !== "" && !relative2.startsWith("..") && !import_node_path79.default.isAbsolute(relative2);
|
|
41517
41683
|
}
|
|
41518
41684
|
function exists(file) {
|
|
41519
41685
|
try {
|
|
41520
|
-
|
|
41686
|
+
import_node_fs66.default.lstatSync(file);
|
|
41521
41687
|
return true;
|
|
41522
41688
|
} catch {
|
|
41523
41689
|
return false;
|
|
41524
41690
|
}
|
|
41525
41691
|
}
|
|
41526
41692
|
function hasTrackedFiles(worktreePath, relative2) {
|
|
41527
|
-
const result = (0,
|
|
41693
|
+
const result = (0, import_node_child_process51.spawnSync)(
|
|
41528
41694
|
"git",
|
|
41529
41695
|
["-C", worktreePath, "--literal-pathspecs", "ls-files", "-z", "--", relative2],
|
|
41530
41696
|
{ encoding: "utf-8", env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" } }
|
|
@@ -41532,10 +41698,10 @@ function hasTrackedFiles(worktreePath, relative2) {
|
|
|
41532
41698
|
return result.status !== 0 || Boolean(result.error) || result.stdout.length > 0;
|
|
41533
41699
|
}
|
|
41534
41700
|
function trimOnePath(candidate, relative2, patterns, steps) {
|
|
41535
|
-
const target =
|
|
41701
|
+
const target = import_node_path79.default.join(candidate.path, relative2);
|
|
41536
41702
|
let stat;
|
|
41537
41703
|
try {
|
|
41538
|
-
stat =
|
|
41704
|
+
stat = import_node_fs66.default.lstatSync(target);
|
|
41539
41705
|
} catch (error) {
|
|
41540
41706
|
if (error.code === "ENOENT") {
|
|
41541
41707
|
steps.push(`gone:${relative2}`);
|
|
@@ -41547,7 +41713,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41547
41713
|
steps.push(`skipped-symlink:${relative2}`);
|
|
41548
41714
|
return;
|
|
41549
41715
|
}
|
|
41550
|
-
if (!isInside(
|
|
41716
|
+
if (!isInside(import_node_fs66.default.realpathSync.native(candidate.path), import_node_fs66.default.realpathSync.native(target))) {
|
|
41551
41717
|
steps.push(`skipped-outside:${relative2}`);
|
|
41552
41718
|
return;
|
|
41553
41719
|
}
|
|
@@ -41560,7 +41726,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41560
41726
|
return;
|
|
41561
41727
|
}
|
|
41562
41728
|
try {
|
|
41563
|
-
|
|
41729
|
+
import_node_fs66.default.rmSync(target, { recursive: true, force: true });
|
|
41564
41730
|
} catch (error) {
|
|
41565
41731
|
steps.push(`partial:${relative2}`);
|
|
41566
41732
|
throw error;
|
|
@@ -41600,7 +41766,7 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41600
41766
|
continue;
|
|
41601
41767
|
}
|
|
41602
41768
|
const listed = candidate.paths ?? [];
|
|
41603
|
-
if (listed.every((relative2) => !exists(
|
|
41769
|
+
if (listed.every((relative2) => !exists(import_node_path79.default.join(candidate.path, relative2))) && matchingReceipt(candidate, manifestSha256)) {
|
|
41604
41770
|
outcome.status = "already-done";
|
|
41605
41771
|
continue;
|
|
41606
41772
|
}
|
|
@@ -41624,7 +41790,7 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41624
41790
|
if (!options.yes) {
|
|
41625
41791
|
verify();
|
|
41626
41792
|
outcome.status = "would-trim";
|
|
41627
|
-
const present = listed.filter((relative2) => exists(
|
|
41793
|
+
const present = listed.filter((relative2) => exists(import_node_path79.default.join(candidate.path, relative2)));
|
|
41628
41794
|
outcome.reason = present.length ? `would remove: ${present.join(", ")}` : "nothing present";
|
|
41629
41795
|
continue;
|
|
41630
41796
|
}
|
|
@@ -41661,13 +41827,13 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41661
41827
|
}
|
|
41662
41828
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
41663
41829
|
}
|
|
41664
|
-
var
|
|
41830
|
+
var import_node_child_process51, import_node_fs66, import_node_path79;
|
|
41665
41831
|
var init_worktree_trim = __esm({
|
|
41666
41832
|
"src/core/worktree-trim.ts"() {
|
|
41667
41833
|
"use strict";
|
|
41668
|
-
|
|
41669
|
-
|
|
41670
|
-
|
|
41834
|
+
import_node_child_process51 = require("child_process");
|
|
41835
|
+
import_node_fs66 = __toESM(require("fs"));
|
|
41836
|
+
import_node_path79 = __toESM(require("path"));
|
|
41671
41837
|
init_reliability_lifecycle();
|
|
41672
41838
|
init_worktree_reclaim();
|
|
41673
41839
|
init_worktree_safety();
|
|
@@ -41735,7 +41901,7 @@ function runWorkspaceLsCommand(options) {
|
|
|
41735
41901
|
}
|
|
41736
41902
|
function writeManifestOutput(manifest, output2) {
|
|
41737
41903
|
if (output2) {
|
|
41738
|
-
|
|
41904
|
+
import_node_fs67.default.writeFileSync(output2, manifest, { flag: "wx" });
|
|
41739
41905
|
process.stdout.write(`${sha256Hex(manifest)} ${output2}
|
|
41740
41906
|
`);
|
|
41741
41907
|
} else {
|
|
@@ -41765,7 +41931,7 @@ function runWorkspaceCleanupCommand(options) {
|
|
|
41765
41931
|
throw new Error("--manifest requires --all-worktrees and --check-merged.");
|
|
41766
41932
|
}
|
|
41767
41933
|
const createdAtEpoch = Math.floor(Date.now() / 1e3);
|
|
41768
|
-
const worktrees =
|
|
41934
|
+
const worktrees = import_node_fs67.default.existsSync(import_node_path80.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
41769
41935
|
const manifest = action2 === "trim" ? buildTrimManifest(
|
|
41770
41936
|
report,
|
|
41771
41937
|
{ trim: worktrees?.trim ?? [], disposable: worktrees?.disposable },
|
|
@@ -41803,7 +41969,7 @@ async function runWorkspaceIdleCommand(options) {
|
|
|
41803
41969
|
if (options.stop) {
|
|
41804
41970
|
const paths = idleSweepPaths();
|
|
41805
41971
|
if (!process.stderr.isTTY) muteLifecycleProgressHeartbeat();
|
|
41806
|
-
|
|
41972
|
+
import_node_fs67.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
41807
41973
|
const result = await withFileLock(paths.lock, { activity: "idle sweep" }, async () => {
|
|
41808
41974
|
try {
|
|
41809
41975
|
const swept = await stopIdleEnvironments(
|
|
@@ -41905,7 +42071,7 @@ async function runWorkspaceJournalSettleCommand(options) {
|
|
|
41905
42071
|
function runWorkspaceManifestHashCommand(file) {
|
|
41906
42072
|
let leftover = false;
|
|
41907
42073
|
try {
|
|
41908
|
-
leftover = isLeftoverManifest(JSON.parse(
|
|
42074
|
+
leftover = isLeftoverManifest(JSON.parse(import_node_fs67.default.readFileSync(file, "utf-8")));
|
|
41909
42075
|
} catch {
|
|
41910
42076
|
}
|
|
41911
42077
|
const { raw } = leftover ? readLeftoverManifest(file) : readManifest(file);
|
|
@@ -42002,12 +42168,12 @@ async function runWorkspaceTrimCommand(options) {
|
|
|
42002
42168
|
process.exitCode = 1;
|
|
42003
42169
|
}
|
|
42004
42170
|
}
|
|
42005
|
-
var
|
|
42171
|
+
var import_node_fs67, import_node_path80;
|
|
42006
42172
|
var init_workspace2 = __esm({
|
|
42007
42173
|
"src/commands/workspace.ts"() {
|
|
42008
42174
|
"use strict";
|
|
42009
|
-
|
|
42010
|
-
|
|
42175
|
+
import_node_fs67 = __toESM(require("fs"));
|
|
42176
|
+
import_node_path80 = __toESM(require("path"));
|
|
42011
42177
|
init_docker_leftovers();
|
|
42012
42178
|
init_file_lock();
|
|
42013
42179
|
init_idle_sweep();
|
|
@@ -42065,7 +42231,7 @@ var init_version = __esm({
|
|
|
42065
42231
|
|
|
42066
42232
|
// src/cli.ts
|
|
42067
42233
|
var import_commander = require("commander");
|
|
42068
|
-
var CLI_VERSION = true ? "0.6.
|
|
42234
|
+
var CLI_VERSION = true ? "0.6.3" : "0.0.0-dev";
|
|
42069
42235
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
42070
42236
|
function withErrorHandling(action2) {
|
|
42071
42237
|
return async (...args) => {
|
|
@@ -42159,7 +42325,7 @@ program.command("up").description("Ensure devnet and start shared Traefik (reser
|
|
|
42159
42325
|
await runUpCommand2();
|
|
42160
42326
|
})
|
|
42161
42327
|
);
|
|
42162
|
-
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("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42328
|
+
program.command("ensure").description("Start and prove a primary or linked checkout's environment and routes").argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42163
42329
|
withErrorHandling(async (repoPath, _options, command) => {
|
|
42164
42330
|
const options = command.opts();
|
|
42165
42331
|
const { runEnsureCommand: runEnsureCommand2 } = await Promise.resolve().then(() => (init_ensure(), ensure_exports));
|
|
@@ -42168,6 +42334,7 @@ program.command("ensure").description("Start and prove a primary or linked check
|
|
|
42168
42334
|
profile: options.profile,
|
|
42169
42335
|
variant: options.variant,
|
|
42170
42336
|
repair: options.repair,
|
|
42337
|
+
initializeNew: options.initializeNew,
|
|
42171
42338
|
open: Boolean(options.open),
|
|
42172
42339
|
json: Boolean(options.json)
|
|
42173
42340
|
});
|
|
@@ -42432,7 +42599,7 @@ workspaceCommand2.command("up").description(
|
|
|
42432
42599
|
);
|
|
42433
42600
|
workspaceCommand2.command("ensure").description(
|
|
42434
42601
|
"Start and prove a primary or linked checkout's workspace runtime, upstreams, and routes"
|
|
42435
|
-
).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("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42602
|
+
).argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42436
42603
|
withErrorHandling(
|
|
42437
42604
|
async (worktreePath, _options, command) => {
|
|
42438
42605
|
const options = command.opts();
|
|
@@ -42442,6 +42609,7 @@ workspaceCommand2.command("ensure").description(
|
|
|
42442
42609
|
profile: options.profile,
|
|
42443
42610
|
variant: options.variant,
|
|
42444
42611
|
repair: options.repair,
|
|
42612
|
+
initializeNew: options.initializeNew,
|
|
42445
42613
|
open: Boolean(options.open),
|
|
42446
42614
|
json: Boolean(options.json)
|
|
42447
42615
|
});
|
|
@@ -42588,10 +42756,10 @@ workspaceCommand2.command("down").description("Delete a workspace's runtime and
|
|
|
42588
42756
|
workspaceCommand2.command("journal").description("Inspect and recover workspace lifecycle journals").command("settle").description(
|
|
42589
42757
|
"Settle an interrupted lifecycle operation as unobservable so ensure and stop can proceed"
|
|
42590
42758
|
).argument("[path]", "Checkout path (defaults to current directory)").option("--json", "Output JSON").action(
|
|
42591
|
-
withErrorHandling(async (
|
|
42759
|
+
withErrorHandling(async (path80, _options, command) => {
|
|
42592
42760
|
const options = command.opts();
|
|
42593
42761
|
const { runWorkspaceJournalSettleCommand: runWorkspaceJournalSettleCommand2 } = await Promise.resolve().then(() => (init_workspace2(), workspace_exports));
|
|
42594
|
-
await runWorkspaceJournalSettleCommand2({ ...
|
|
42762
|
+
await runWorkspaceJournalSettleCommand2({ ...path80 ? { path: path80 } : {}, ...options });
|
|
42595
42763
|
})
|
|
42596
42764
|
);
|
|
42597
42765
|
function parseVersionRequest(argv) {
|