@devrouter/cli 0.6.1 → 0.6.2
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 +797 -221
- package/dist/devrouter.js +926 -762
- package/package.json +1 -1
- package/upgrade-prompts/0.6.2.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.2" : "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.2" : "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";
|
|
@@ -18029,7 +18171,7 @@ function readDocker(endpoint, args, timeoutMs) {
|
|
|
18029
18171
|
const env = { ...process.env };
|
|
18030
18172
|
delete env.DOCKER_CONTEXT;
|
|
18031
18173
|
delete env.DOCKER_HOST;
|
|
18032
|
-
const result = (0,
|
|
18174
|
+
const result = (0, import_node_child_process29.spawnSync)("docker", ["--host", endpoint, ...args], {
|
|
18033
18175
|
env,
|
|
18034
18176
|
encoding: "utf-8",
|
|
18035
18177
|
timeout: timeoutMs,
|
|
@@ -18191,11 +18333,11 @@ function collectDockerNetworkInventory(options = {}, dependencies = {}) {
|
|
|
18191
18333
|
}
|
|
18192
18334
|
return result;
|
|
18193
18335
|
}
|
|
18194
|
-
var
|
|
18336
|
+
var import_node_child_process29, NetworkInventoryError, MAX_IDS, MAX_OUTPUT_BYTES, FULL_ID, NETWORK_TEMPLATE, CONTAINER_TEMPLATE;
|
|
18195
18337
|
var init_network_inventory = __esm({
|
|
18196
18338
|
"src/core/network-inventory.ts"() {
|
|
18197
18339
|
"use strict";
|
|
18198
|
-
|
|
18340
|
+
import_node_child_process29 = require("child_process");
|
|
18199
18341
|
init_devpod_environment();
|
|
18200
18342
|
NetworkInventoryError = class extends Error {
|
|
18201
18343
|
};
|
|
@@ -18523,26 +18665,26 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18523
18665
|
try {
|
|
18524
18666
|
if (!endpoint.startsWith("unix:///")) return false;
|
|
18525
18667
|
const socket = endpoint.slice("unix://".length);
|
|
18526
|
-
const table =
|
|
18668
|
+
const table = import_node_fs37.default.readFileSync(import_node_path45.default.join(procRoot, "net/unix"), "utf8");
|
|
18527
18669
|
if (Buffer.byteLength(table) > 1024 * 1024) return false;
|
|
18528
18670
|
const rows2 = table.split("\n").map((line) => line.trim().split(/\s+/)).filter((row) => row[7] === socket && row[3] === "00010000");
|
|
18529
18671
|
if (rows2.length !== 1 || !/^\d+$/.test(rows2[0][6])) return false;
|
|
18530
18672
|
const inode = `socket:[${rows2[0][6]}]`;
|
|
18531
|
-
const ownNamespace =
|
|
18532
|
-
const pids =
|
|
18673
|
+
const ownNamespace = import_node_fs37.default.readlinkSync(import_node_path45.default.join(procRoot, "self/ns/net"));
|
|
18674
|
+
const pids = import_node_fs37.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
|
|
18533
18675
|
if (pids.length > 4096) return false;
|
|
18534
18676
|
for (const pid of pids) {
|
|
18535
18677
|
if (Date.now() > deadline) return false;
|
|
18536
18678
|
try {
|
|
18537
|
-
const root =
|
|
18538
|
-
if (
|
|
18539
|
-
if (
|
|
18540
|
-
const descriptors =
|
|
18679
|
+
const root = import_node_path45.default.join(procRoot, pid);
|
|
18680
|
+
if (import_node_path45.default.basename(import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "exe"))) !== "dockerd") continue;
|
|
18681
|
+
if (import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "ns/net")) !== ownNamespace) continue;
|
|
18682
|
+
const descriptors = import_node_fs37.default.readdirSync(import_node_path45.default.join(root, "fd"));
|
|
18541
18683
|
if (descriptors.length > 4096) continue;
|
|
18542
18684
|
if (descriptors.some((fd) => {
|
|
18543
18685
|
if (Date.now() > deadline) return false;
|
|
18544
18686
|
try {
|
|
18545
|
-
return
|
|
18687
|
+
return import_node_fs37.default.readlinkSync(import_node_path45.default.join(root, "fd", fd)) === inode;
|
|
18546
18688
|
} catch {
|
|
18547
18689
|
return false;
|
|
18548
18690
|
}
|
|
@@ -18556,12 +18698,12 @@ function hasLocalDockerNetworkNamespace(endpoint, procRoot = "/proc") {
|
|
|
18556
18698
|
}
|
|
18557
18699
|
return false;
|
|
18558
18700
|
}
|
|
18559
|
-
var
|
|
18701
|
+
var import_node_fs37, import_node_path45;
|
|
18560
18702
|
var init_network_local_daemon = __esm({
|
|
18561
18703
|
"src/core/network-local-daemon.ts"() {
|
|
18562
18704
|
"use strict";
|
|
18563
|
-
|
|
18564
|
-
|
|
18705
|
+
import_node_fs37 = __toESM(require("fs"));
|
|
18706
|
+
import_node_path45 = __toESM(require("path"));
|
|
18565
18707
|
}
|
|
18566
18708
|
});
|
|
18567
18709
|
|
|
@@ -18589,7 +18731,7 @@ function parseLinuxNetworkRoutes(output2) {
|
|
|
18589
18731
|
function collectNetworkRoutes(options) {
|
|
18590
18732
|
if ((options.platform ?? process.platform) !== "linux" || !hasLocalDockerNetworkNamespace(options.endpoint))
|
|
18591
18733
|
return { status: "unknown", routes: [] };
|
|
18592
|
-
const result = (0,
|
|
18734
|
+
const result = (0, import_node_child_process30.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
|
|
18593
18735
|
encoding: "utf8",
|
|
18594
18736
|
timeout: 5e3,
|
|
18595
18737
|
maxBuffer: 1024 * 1024
|
|
@@ -18597,11 +18739,11 @@ function collectNetworkRoutes(options) {
|
|
|
18597
18739
|
if (result.error || result.status !== 0) return { status: "unknown", routes: [] };
|
|
18598
18740
|
return parseLinuxNetworkRoutes(result.stdout);
|
|
18599
18741
|
}
|
|
18600
|
-
var
|
|
18742
|
+
var import_node_child_process30, import_node_net3;
|
|
18601
18743
|
var init_network_routes = __esm({
|
|
18602
18744
|
"src/core/network-routes.ts"() {
|
|
18603
18745
|
"use strict";
|
|
18604
|
-
|
|
18746
|
+
import_node_child_process30 = require("child_process");
|
|
18605
18747
|
import_node_net3 = require("net");
|
|
18606
18748
|
init_network_capacity();
|
|
18607
18749
|
init_network_local_daemon();
|
|
@@ -18769,11 +18911,11 @@ function extendDockerComposeFile(nativeConfig, overlayPath) {
|
|
|
18769
18911
|
const config = { ...nativeConfig, dockerComposeFile };
|
|
18770
18912
|
return { status: "ready", config, reasons: [] };
|
|
18771
18913
|
}
|
|
18772
|
-
var
|
|
18914
|
+
var import_node_crypto23;
|
|
18773
18915
|
var init_network_compose = __esm({
|
|
18774
18916
|
"src/core/network-compose.ts"() {
|
|
18775
18917
|
"use strict";
|
|
18776
|
-
|
|
18918
|
+
import_node_crypto23 = require("crypto");
|
|
18777
18919
|
}
|
|
18778
18920
|
});
|
|
18779
18921
|
|
|
@@ -18781,8 +18923,8 @@ var init_network_compose = __esm({
|
|
|
18781
18923
|
function prepareNetworkComposeFiles(plan, subnet) {
|
|
18782
18924
|
const overlay = deriveComposeNetworkOverlay(subnet);
|
|
18783
18925
|
if (overlay.status !== "ready" || !overlay.overlay) throw new Error("Network subnet is invalid.");
|
|
18784
|
-
const overlayPath =
|
|
18785
|
-
const ignored = (0,
|
|
18926
|
+
const overlayPath = import_node_path46.default.join(plan.composeDirectory, OVERLAY);
|
|
18927
|
+
const ignored = (0, import_node_child_process31.spawnSync)("git", [
|
|
18786
18928
|
"-C",
|
|
18787
18929
|
plan.composeDirectory,
|
|
18788
18930
|
"check-ignore",
|
|
@@ -18794,11 +18936,11 @@ function prepareNetworkComposeFiles(plan, subnet) {
|
|
|
18794
18936
|
if (ignored.status !== 0)
|
|
18795
18937
|
throw new Error("Generated network overlay must be ignored before allocation.");
|
|
18796
18938
|
const bytes2 = `${MARKER}
|
|
18797
|
-
${
|
|
18939
|
+
${import_yaml5.default.stringify(overlay.overlay)}`;
|
|
18798
18940
|
const assertOwnership = () => {
|
|
18799
|
-
if (!
|
|
18800
|
-
const stat =
|
|
18801
|
-
if (!stat.isFile() || stat.size > MAX_BYTES3 ||
|
|
18941
|
+
if (!import_node_fs38.default.existsSync(overlayPath)) return;
|
|
18942
|
+
const stat = import_node_fs38.default.lstatSync(overlayPath);
|
|
18943
|
+
if (!stat.isFile() || stat.size > MAX_BYTES3 || import_node_fs38.default.readFileSync(overlayPath, "utf8") !== bytes2)
|
|
18802
18944
|
throw new Error("Retained network overlay changed; repair is required.");
|
|
18803
18945
|
};
|
|
18804
18946
|
assertOwnership();
|
|
@@ -18812,7 +18954,7 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18812
18954
|
...plan,
|
|
18813
18955
|
contents,
|
|
18814
18956
|
composeFiles: [...plan.composeFiles, overlayPath],
|
|
18815
|
-
effectiveConfigSha256: (0,
|
|
18957
|
+
effectiveConfigSha256: (0, import_node_crypto24.createHash)("sha256").update(contents).digest("hex")
|
|
18816
18958
|
};
|
|
18817
18959
|
return {
|
|
18818
18960
|
plan: result,
|
|
@@ -18822,15 +18964,15 @@ ${JSON.stringify(extended.config, null, 2)}
|
|
|
18822
18964
|
}
|
|
18823
18965
|
};
|
|
18824
18966
|
}
|
|
18825
|
-
var
|
|
18967
|
+
var import_node_child_process31, import_node_crypto24, import_node_fs38, import_node_path46, import_yaml5, OVERLAY, MARKER, MAX_BYTES3;
|
|
18826
18968
|
var init_network_compose_files = __esm({
|
|
18827
18969
|
"src/core/network-compose-files.ts"() {
|
|
18828
18970
|
"use strict";
|
|
18829
|
-
|
|
18830
|
-
|
|
18831
|
-
|
|
18832
|
-
|
|
18833
|
-
|
|
18971
|
+
import_node_child_process31 = require("child_process");
|
|
18972
|
+
import_node_crypto24 = require("crypto");
|
|
18973
|
+
import_node_fs38 = __toESM(require("fs"));
|
|
18974
|
+
import_node_path46 = __toESM(require("path"));
|
|
18975
|
+
import_yaml5 = __toESM(require("yaml"));
|
|
18834
18976
|
init_atomic_file();
|
|
18835
18977
|
init_devcontainer_profile();
|
|
18836
18978
|
init_network_compose();
|
|
@@ -18841,11 +18983,11 @@ var init_network_compose_files = __esm({
|
|
|
18841
18983
|
});
|
|
18842
18984
|
|
|
18843
18985
|
// src/core/network-connected-route.ts
|
|
18844
|
-
var
|
|
18986
|
+
var import_node_child_process32;
|
|
18845
18987
|
var init_network_connected_route = __esm({
|
|
18846
18988
|
"src/core/network-connected-route.ts"() {
|
|
18847
18989
|
"use strict";
|
|
18848
|
-
|
|
18990
|
+
import_node_child_process32 = require("child_process");
|
|
18849
18991
|
init_network_capacity();
|
|
18850
18992
|
}
|
|
18851
18993
|
});
|
|
@@ -18861,11 +19003,11 @@ var init_network_lifecycle = __esm({
|
|
|
18861
19003
|
});
|
|
18862
19004
|
|
|
18863
19005
|
// src/core/network-managed.ts
|
|
18864
|
-
var
|
|
19006
|
+
var import_node_crypto25;
|
|
18865
19007
|
var init_network_managed = __esm({
|
|
18866
19008
|
"src/core/network-managed.ts"() {
|
|
18867
19009
|
"use strict";
|
|
18868
|
-
|
|
19010
|
+
import_node_crypto25 = require("crypto");
|
|
18869
19011
|
init_devpod_environment();
|
|
18870
19012
|
init_network_capacity();
|
|
18871
19013
|
init_network_claim_lookup();
|
|
@@ -18935,13 +19077,13 @@ function resolveLinkedTarget(repoPath) {
|
|
|
18935
19077
|
gitCommonDir: resolveGitCommonDir(repoPath)
|
|
18936
19078
|
};
|
|
18937
19079
|
}
|
|
18938
|
-
var
|
|
19080
|
+
var import_node_child_process33, import_node_fs39, import_node_path47;
|
|
18939
19081
|
var init_workspace_ensure = __esm({
|
|
18940
19082
|
"src/core/workspace-ensure.ts"() {
|
|
18941
19083
|
"use strict";
|
|
18942
|
-
|
|
18943
|
-
|
|
18944
|
-
|
|
19084
|
+
import_node_child_process33 = require("child_process");
|
|
19085
|
+
import_node_fs39 = __toESM(require("fs"));
|
|
19086
|
+
import_node_path47 = __toESM(require("path"));
|
|
18945
19087
|
init_devcontainer_profile();
|
|
18946
19088
|
init_devpod_environment();
|
|
18947
19089
|
init_devpod_mutation();
|
|
@@ -18952,6 +19094,7 @@ var init_workspace_ensure = __esm({
|
|
|
18952
19094
|
init_host_routes();
|
|
18953
19095
|
init_http_route_probe();
|
|
18954
19096
|
init_lifecycle_progress();
|
|
19097
|
+
init_managed_fresh_bootstrap();
|
|
18955
19098
|
init_managed_host_ports();
|
|
18956
19099
|
init_managed_host_preparation();
|
|
18957
19100
|
init_managed_post_start();
|
|
@@ -19057,6 +19200,9 @@ function prepareManagedLifecycleOperation(input2) {
|
|
|
19057
19200
|
throw new Error("Invalid managed operation command.");
|
|
19058
19201
|
if (Buffer.byteLength(JSON.stringify(input2)) > 32768)
|
|
19059
19202
|
throw new Error("Managed operation input exceeds its byte limit.");
|
|
19203
|
+
if (input2.initializeNew && input2.kind !== "ensure")
|
|
19204
|
+
throw new Error("Initialization intent is valid only for an ensure operation.");
|
|
19205
|
+
if (input2.kind === "ensure") assertFreshBootstrapRequest(input2.identity, input2);
|
|
19060
19206
|
const ids2 = newLifecycleIds();
|
|
19061
19207
|
return updateReliabilityOperation(input2.identity, (record6) => {
|
|
19062
19208
|
const retained = readManagedRuntimeState(
|
|
@@ -19105,13 +19251,17 @@ function prepareManagedLifecycleOperation(input2) {
|
|
|
19105
19251
|
repoPath: input2.identity.repoPath,
|
|
19106
19252
|
identity: { ...input2.identity },
|
|
19107
19253
|
fence: reliabilityFence(record6.state),
|
|
19108
|
-
options: {
|
|
19254
|
+
options: {
|
|
19255
|
+
profile: input2.profile,
|
|
19256
|
+
quiet: true,
|
|
19257
|
+
...input2.initializeNew ? { initializeNew: true } : {}
|
|
19258
|
+
},
|
|
19109
19259
|
...input2.command ? { command: [...input2.command] } : {}
|
|
19110
19260
|
}
|
|
19111
19261
|
};
|
|
19112
19262
|
});
|
|
19113
19263
|
}
|
|
19114
|
-
function assertCurrentCapacityController(expected, directory =
|
|
19264
|
+
function assertCurrentCapacityController(expected, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller")) {
|
|
19115
19265
|
const current = new ControllerStore(directory).read();
|
|
19116
19266
|
if (!expected || current?.store !== expected.store || current.epoch !== expected.epoch)
|
|
19117
19267
|
throw new Error("Capacity controller incarnation changed.");
|
|
@@ -19282,7 +19432,7 @@ function withdrawUnstartedLifecycleStop(input2) {
|
|
|
19282
19432
|
if (record6.worker || record6.stopWorkStarted) return false;
|
|
19283
19433
|
if (state.desired !== "stopped-by-user" || state.phase !== "stopping") return false;
|
|
19284
19434
|
if (state.stopProof.workloadsStopped || state.stopProof.routesRemoved) return false;
|
|
19285
|
-
if (!(0,
|
|
19435
|
+
if (!(0, import_node_util13.isDeepStrictEqual)(state.operation, intent.recordedOperation)) return false;
|
|
19286
19436
|
const prior = intent.prior;
|
|
19287
19437
|
state.intentRevision = prior.intentRevision;
|
|
19288
19438
|
state.observationsAfterMs = prior.observationsAfterMs;
|
|
@@ -19360,7 +19510,7 @@ function prepareResumeLifecycleOperation(input2) {
|
|
|
19360
19510
|
});
|
|
19361
19511
|
}
|
|
19362
19512
|
function settlePreparedLifecycleCapacity(input2) {
|
|
19363
|
-
const directory = input2.directory ??
|
|
19513
|
+
const directory = input2.directory ?? import_node_path48.default.join(DEVROUTER_HOME, "controller");
|
|
19364
19514
|
const store = createLifecycleCapacityStore(directory);
|
|
19365
19515
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
19366
19516
|
const snapshot = store.read();
|
|
@@ -19388,21 +19538,21 @@ function settlePreparedLifecycleCapacity(input2) {
|
|
|
19388
19538
|
reservationId: binding.reservationId,
|
|
19389
19539
|
policyRevision: binding.policyRevision
|
|
19390
19540
|
};
|
|
19391
|
-
if (operation.kind === "exec" && !(0,
|
|
19541
|
+
if (operation.kind === "exec" && !(0, import_node_util13.isDeepStrictEqual)(target.totals, binding.execSteady?.totals))
|
|
19392
19542
|
return null;
|
|
19393
19543
|
const retained = snapshot.reservations.find(
|
|
19394
19544
|
(entry) => entry.environmentId === target.environmentId
|
|
19395
19545
|
);
|
|
19396
19546
|
if (!retained || retained.reservationId !== target.reservationId || retained.operationId !== target.operationId || retained.policyRevision !== target.policyRevision)
|
|
19397
19547
|
return null;
|
|
19398
|
-
if (!record6.phaseSettlement && (0,
|
|
19548
|
+
if (!record6.phaseSettlement && (0, import_node_util13.isDeepStrictEqual)(retained, target)) return null;
|
|
19399
19549
|
const marker = {
|
|
19400
19550
|
id: binding.reservationId,
|
|
19401
19551
|
fence: { ...proof.fence },
|
|
19402
19552
|
target,
|
|
19403
19553
|
estimatesDigest: input2.enrollment.estimatesDigest
|
|
19404
19554
|
};
|
|
19405
|
-
if (record6.phaseSettlement && !(0,
|
|
19555
|
+
if (record6.phaseSettlement && !(0, import_node_util13.isDeepStrictEqual)(record6.phaseSettlement, marker))
|
|
19406
19556
|
throw new Error("Capacity phase settlement proof changed.");
|
|
19407
19557
|
binding.validUntilMs = 0;
|
|
19408
19558
|
record6.phaseSettlement = marker;
|
|
@@ -19417,7 +19567,7 @@ function settlePreparedLifecycleCapacity(input2) {
|
|
|
19417
19567
|
}
|
|
19418
19568
|
return updateReliabilityOperation(input2.identity, (record6) => {
|
|
19419
19569
|
assertCurrentCapacityController(input2.controller, directory);
|
|
19420
|
-
if (!matchesFence(record6, pending.fence) || !(0,
|
|
19570
|
+
if (!matchesFence(record6, pending.fence) || !(0, import_node_util13.isDeepStrictEqual)(record6.phaseSettlement, pending))
|
|
19421
19571
|
return false;
|
|
19422
19572
|
record6.phaseSettlement = null;
|
|
19423
19573
|
return true;
|
|
@@ -19467,6 +19617,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19467
19617
|
};
|
|
19468
19618
|
const ids2 = newLifecycleIds();
|
|
19469
19619
|
const copiedOptions = { ...options };
|
|
19620
|
+
if (kind === "ensure") assertFreshBootstrapRequest(identity2, options);
|
|
19470
19621
|
const copiedCommand = command ? [...command] : void 0;
|
|
19471
19622
|
if (kind === "stop") {
|
|
19472
19623
|
const intent = updateReliabilityOperation(identity2, (record6) => {
|
|
@@ -19510,6 +19661,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19510
19661
|
identity: identity2,
|
|
19511
19662
|
requestId: ids2.requestId,
|
|
19512
19663
|
profile: copiedOptions.profile,
|
|
19664
|
+
...copiedOptions.initializeNew ? { initializeNew: true } : {},
|
|
19513
19665
|
...copiedCommand ? { command: copiedCommand } : {}
|
|
19514
19666
|
});
|
|
19515
19667
|
if (initial.state.executionPolicy !== "manual")
|
|
@@ -19616,7 +19768,7 @@ async function superviseLifecycle(kind, repoPath, options = {}, command, hooks =
|
|
|
19616
19768
|
removeSignals();
|
|
19617
19769
|
}
|
|
19618
19770
|
}
|
|
19619
|
-
function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs, maxSampleAgeMs, directory =
|
|
19771
|
+
function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs, maxSampleAgeMs, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller"), controller, admission) {
|
|
19620
19772
|
if (request2.kind === "stop") throw new Error("Stop never requires capacity admission.");
|
|
19621
19773
|
const capacity = createLifecycleCapacityStore(directory);
|
|
19622
19774
|
const snapshot = capacity.read();
|
|
@@ -19672,10 +19824,10 @@ function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs,
|
|
|
19672
19824
|
totals
|
|
19673
19825
|
};
|
|
19674
19826
|
if (binding.operationId === request2.operationId) {
|
|
19675
|
-
if (binding.execSteady && !(0,
|
|
19827
|
+
if (binding.execSteady && !(0, import_node_util13.isDeepStrictEqual)(binding.execSteady, receipt))
|
|
19676
19828
|
throw new Error("Repeated exec settlement proof changed.");
|
|
19677
19829
|
execSteady = binding.execSteady;
|
|
19678
|
-
} else if (!retained.startup && !retained.heavy && (0,
|
|
19830
|
+
} else if (!retained.startup && !retained.heavy && (0, import_node_util13.isDeepStrictEqual)(retained.totals, totals)) {
|
|
19679
19831
|
execSteady = receipt;
|
|
19680
19832
|
}
|
|
19681
19833
|
} else if (binding.operationId === request2.operationId && binding.execSteady) {
|
|
@@ -19716,7 +19868,7 @@ function admitLifecycleCapacity(request2, reservation, budgets, samples, nowMs,
|
|
|
19716
19868
|
return decision;
|
|
19717
19869
|
}
|
|
19718
19870
|
function capacityPolicyTargets(repoPath) {
|
|
19719
|
-
const policy = readCapacityPolicy(
|
|
19871
|
+
const policy = readCapacityPolicy(import_node_path48.default.join(DEVROUTER_HOME, "controller"));
|
|
19720
19872
|
return policy?.admissions === "enabled" && policy.enrollments.some((entry) => entry.repoPath === repoPath);
|
|
19721
19873
|
}
|
|
19722
19874
|
function controllerWaitSeconds(deadline) {
|
|
@@ -19725,7 +19877,7 @@ function controllerWaitSeconds(deadline) {
|
|
|
19725
19877
|
async function superviseThroughController(input2) {
|
|
19726
19878
|
if (input2.kind === "exec" && !input2.command)
|
|
19727
19879
|
throw new Error("Exec requires a command for controller admission.");
|
|
19728
|
-
const directory =
|
|
19880
|
+
const directory = import_node_path48.default.join(DEVROUTER_HOME, "controller");
|
|
19729
19881
|
const cancellation = { requested: false };
|
|
19730
19882
|
const removeSignals = installLifecycleWaitSignals(cancellation);
|
|
19731
19883
|
const cancelled = () => {
|
|
@@ -19749,7 +19901,7 @@ async function superviseThroughController(input2) {
|
|
|
19749
19901
|
try {
|
|
19750
19902
|
const bind = () => observeControllerBinding(directory, {
|
|
19751
19903
|
path: input2.repoPath,
|
|
19752
|
-
session: (0,
|
|
19904
|
+
session: (0, import_node_crypto26.randomUUID)(),
|
|
19753
19905
|
profile: input2.profile ?? "full",
|
|
19754
19906
|
// The protocol requires at least one readiness selector, and every
|
|
19755
19907
|
// supervised operation depends on runtime readiness; "runtime" is the
|
|
@@ -19759,7 +19911,12 @@ async function superviseThroughController(input2) {
|
|
|
19759
19911
|
let binding = await bind();
|
|
19760
19912
|
let pending = await submitControllerOperation(
|
|
19761
19913
|
directory,
|
|
19762
|
-
input2.kind === "exec" ? { ...binding, requestId: input2.requestId, kind: "exec", command: input2.command ?? [] } : {
|
|
19914
|
+
input2.kind === "exec" ? { ...binding, requestId: input2.requestId, kind: "exec", command: input2.command ?? [] } : {
|
|
19915
|
+
...binding,
|
|
19916
|
+
requestId: input2.requestId,
|
|
19917
|
+
kind: "ensure",
|
|
19918
|
+
...input2.initializeNew ? { initializeNew: true } : {}
|
|
19919
|
+
},
|
|
19763
19920
|
{ waitSeconds: controllerWaitSeconds(deadline), onOutput }
|
|
19764
19921
|
);
|
|
19765
19922
|
while (pending.status !== "terminal") {
|
|
@@ -19797,7 +19954,7 @@ async function superviseThroughController(input2) {
|
|
|
19797
19954
|
removeSignals();
|
|
19798
19955
|
}
|
|
19799
19956
|
}
|
|
19800
|
-
function renewLifecycleCapacity(request2, policy, samples, controller, directory =
|
|
19957
|
+
function renewLifecycleCapacity(request2, policy, samples, controller, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller"), nowMs = Date.now()) {
|
|
19801
19958
|
return updateReliabilityOperation(request2.identity, (record6) => {
|
|
19802
19959
|
const binding = record6.capacity;
|
|
19803
19960
|
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 +20042,7 @@ function retireQueuedLifecycle(request2, supersededOnly = false) {
|
|
|
19885
20042
|
return true;
|
|
19886
20043
|
});
|
|
19887
20044
|
}
|
|
19888
|
-
function bindLifecycleCapacity(request2, binding, directory =
|
|
20045
|
+
function bindLifecycleCapacity(request2, binding, directory = import_node_path48.default.join(DEVROUTER_HOME, "controller")) {
|
|
19889
20046
|
if (request2.kind === "stop") throw new Error("Stop never requires capacity admission.");
|
|
19890
20047
|
updateReliabilityOperation(request2.identity, (record6) => {
|
|
19891
20048
|
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 +20057,13 @@ function bindLifecycleCapacity(request2, binding, directory = import_node_path47
|
|
|
19900
20057
|
stepRecord(record6, { ...request2.fence, type: "admission", result: "admitted" });
|
|
19901
20058
|
});
|
|
19902
20059
|
}
|
|
19903
|
-
var
|
|
20060
|
+
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
20061
|
var init_reliability_lifecycle = __esm({
|
|
19905
20062
|
"src/core/reliability-lifecycle.ts"() {
|
|
19906
20063
|
"use strict";
|
|
19907
|
-
|
|
19908
|
-
|
|
19909
|
-
|
|
20064
|
+
import_node_crypto26 = require("crypto");
|
|
20065
|
+
import_node_path48 = __toESM(require("path"));
|
|
20066
|
+
import_node_util13 = require("util");
|
|
19910
20067
|
init_capacity_accounting();
|
|
19911
20068
|
init_capacity_policy();
|
|
19912
20069
|
init_capacity_request();
|
|
@@ -19922,6 +20079,7 @@ var init_reliability_lifecycle = __esm({
|
|
|
19922
20079
|
init_file_lock();
|
|
19923
20080
|
init_host_routes();
|
|
19924
20081
|
init_managed_devsy_stop();
|
|
20082
|
+
init_managed_fresh_bootstrap();
|
|
19925
20083
|
init_managed_post_start();
|
|
19926
20084
|
init_managed_runtime_state();
|
|
19927
20085
|
init_managed_stop_recovery();
|
|
@@ -19947,11 +20105,11 @@ var init_reliability_lifecycle = __esm({
|
|
|
19947
20105
|
});
|
|
19948
20106
|
|
|
19949
20107
|
// src/core/capacity-queue.ts
|
|
19950
|
-
var
|
|
20108
|
+
var import_node_util14, CapacityQueue;
|
|
19951
20109
|
var init_capacity_queue = __esm({
|
|
19952
20110
|
"src/core/capacity-queue.ts"() {
|
|
19953
20111
|
"use strict";
|
|
19954
|
-
|
|
20112
|
+
import_node_util14 = require("util");
|
|
19955
20113
|
init_capacity_policy();
|
|
19956
20114
|
init_capacity_store();
|
|
19957
20115
|
init_reliability_contract();
|
|
@@ -19987,7 +20145,7 @@ var init_capacity_queue = __esm({
|
|
|
19987
20145
|
if (existing) {
|
|
19988
20146
|
const existingRequest = existing.phase === "terminal" ? { ...existing.request, command: void 0 } : existing.request;
|
|
19989
20147
|
const incomingRequest = existing.phase === "terminal" ? { ...request2, command: void 0 } : request2;
|
|
19990
|
-
if (!(0,
|
|
20148
|
+
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
20149
|
throw new Error("Operation reference belongs to another accepted request.");
|
|
19992
20150
|
return request2.operationId;
|
|
19993
20151
|
}
|
|
@@ -20150,7 +20308,7 @@ var init_capacity_queue = __esm({
|
|
|
20150
20308
|
const operation = record6?.state.operation?.id === entry.request.operationId ? record6.state.operation : record6?.state.operationHistory.find(
|
|
20151
20309
|
(operation2) => operation2.id === entry.request.operationId
|
|
20152
20310
|
);
|
|
20153
|
-
if (record6 && (!(0,
|
|
20311
|
+
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
20312
|
entry.reason = "intent-superseded";
|
|
20155
20313
|
entry.phase = "terminal";
|
|
20156
20314
|
entry.request.command = void 0;
|
|
@@ -20286,7 +20444,7 @@ var init_capacity_startup_witness = __esm({
|
|
|
20286
20444
|
function readHostWakeEpoch(platform = process.platform) {
|
|
20287
20445
|
if (platform !== "darwin") return void 0;
|
|
20288
20446
|
try {
|
|
20289
|
-
const result = (0,
|
|
20447
|
+
const result = (0, import_node_child_process34.spawnSync)("/usr/sbin/sysctl", ["-n", "kern.wake_abs_time"], {
|
|
20290
20448
|
encoding: "utf8",
|
|
20291
20449
|
stdio: ["ignore", "pipe", "pipe"],
|
|
20292
20450
|
timeout: 250,
|
|
@@ -20301,11 +20459,11 @@ function readHostWakeEpoch(platform = process.platform) {
|
|
|
20301
20459
|
return null;
|
|
20302
20460
|
}
|
|
20303
20461
|
}
|
|
20304
|
-
var
|
|
20462
|
+
var import_node_child_process34;
|
|
20305
20463
|
var init_host_wake = __esm({
|
|
20306
20464
|
"src/core/host-wake.ts"() {
|
|
20307
20465
|
"use strict";
|
|
20308
|
-
|
|
20466
|
+
import_node_child_process34 = require("child_process");
|
|
20309
20467
|
}
|
|
20310
20468
|
});
|
|
20311
20469
|
|
|
@@ -20379,7 +20537,7 @@ function createCapacityController(options) {
|
|
|
20379
20537
|
let matches = false;
|
|
20380
20538
|
try {
|
|
20381
20539
|
current = new ControllerStore(options.directory).read();
|
|
20382
|
-
matches = current?.store === controller.store && current.epoch === controller.epoch && (0,
|
|
20540
|
+
matches = current?.store === controller.store && current.epoch === controller.epoch && (0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy);
|
|
20383
20541
|
} catch {
|
|
20384
20542
|
}
|
|
20385
20543
|
if (invalidated || lifetime.signal.aborted || !matches) {
|
|
@@ -20531,12 +20689,12 @@ function createCapacityController(options) {
|
|
|
20531
20689
|
controller,
|
|
20532
20690
|
policyRevision: policy.revision
|
|
20533
20691
|
});
|
|
20534
|
-
const payloadKey = (0,
|
|
20692
|
+
const payloadKey = (0, import_node_crypto27.randomBytes)(32);
|
|
20535
20693
|
const acceptedPayloads = /* @__PURE__ */ new Map();
|
|
20536
20694
|
const settlePreparations = () => {
|
|
20537
20695
|
if (lifetime.signal.aborted) return;
|
|
20538
20696
|
try {
|
|
20539
|
-
if (!(0,
|
|
20697
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy)) return;
|
|
20540
20698
|
} catch {
|
|
20541
20699
|
return;
|
|
20542
20700
|
}
|
|
@@ -20550,7 +20708,7 @@ function createCapacityController(options) {
|
|
|
20550
20708
|
const record6 = readReliabilityOperation(identity2);
|
|
20551
20709
|
if (!record6?.capacity || !record6.preparation && !record6.capacity.execSteady || record6.worker || !record6.state.operation?.drained || !["ensure", "exec"].includes(record6.state.operation.kind))
|
|
20552
20710
|
continue;
|
|
20553
|
-
const bytes2 = readControllerEvidence(
|
|
20711
|
+
const bytes2 = readControllerEvidence(import_node_path49.default.join(enrollment.repoPath, ".devrouter.yml"));
|
|
20554
20712
|
const estimates = loadRepoConfig(enrollment.repoPath, () => bytes2).capacity;
|
|
20555
20713
|
if (!estimates) continue;
|
|
20556
20714
|
settlePreparedLifecycleCapacity({
|
|
@@ -20588,7 +20746,7 @@ function createCapacityController(options) {
|
|
|
20588
20746
|
};
|
|
20589
20747
|
const resolveCapacityTarget = async (environment, signal) => {
|
|
20590
20748
|
const current = readCapacityPolicy(options.directory);
|
|
20591
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20749
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return void 0;
|
|
20592
20750
|
let resolved2;
|
|
20593
20751
|
try {
|
|
20594
20752
|
resolved2 = await resolveCapacityEnrollment(
|
|
@@ -20600,10 +20758,10 @@ function createCapacityController(options) {
|
|
|
20600
20758
|
} catch {
|
|
20601
20759
|
return void 0;
|
|
20602
20760
|
}
|
|
20603
|
-
if (signal.aborted || !(0,
|
|
20604
|
-
if (!(0,
|
|
20761
|
+
if (signal.aborted || !(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment)) return void 0;
|
|
20762
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return void 0;
|
|
20605
20763
|
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,
|
|
20764
|
+
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
20765
|
return void 0;
|
|
20608
20766
|
return { current, resolved: resolved2, runtime };
|
|
20609
20767
|
};
|
|
@@ -20645,7 +20803,7 @@ function createCapacityController(options) {
|
|
|
20645
20803
|
const bounded = AbortSignal.any([signal, lifetime.signal]);
|
|
20646
20804
|
if (bounded.aborted) return false;
|
|
20647
20805
|
const current = readCapacityPolicy(options.directory);
|
|
20648
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20806
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return false;
|
|
20649
20807
|
const request2 = reconcileParkedLifecycleStop({
|
|
20650
20808
|
identity: { ...identity2 },
|
|
20651
20809
|
controller,
|
|
@@ -20695,7 +20853,7 @@ function createCapacityController(options) {
|
|
|
20695
20853
|
{
|
|
20696
20854
|
...charge,
|
|
20697
20855
|
operationId: prepared.operationId,
|
|
20698
|
-
reservationId: (0,
|
|
20856
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20699
20857
|
policyRevision: target.current.revision
|
|
20700
20858
|
},
|
|
20701
20859
|
{
|
|
@@ -20724,7 +20882,7 @@ function createCapacityController(options) {
|
|
|
20724
20882
|
signal = AbortSignal.any([signal, lifetime.signal]);
|
|
20725
20883
|
if (signal.aborted) throw new Error("Capacity submission unavailable.");
|
|
20726
20884
|
const current = readCapacityPolicy(options.directory);
|
|
20727
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
20885
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy))
|
|
20728
20886
|
throw new Error("Capacity controller policy changed.");
|
|
20729
20887
|
validate3();
|
|
20730
20888
|
const resolved2 = await enrollCapacityLifecycle(
|
|
@@ -20738,12 +20896,12 @@ function createCapacityController(options) {
|
|
|
20738
20896
|
options.directory,
|
|
20739
20897
|
bindingResolver
|
|
20740
20898
|
);
|
|
20741
|
-
if (!(0,
|
|
20899
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment) || signal.aborted)
|
|
20742
20900
|
throw new Error("Capacity submission binding changed.");
|
|
20743
|
-
if (!(0,
|
|
20901
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current))
|
|
20744
20902
|
throw new Error("Capacity submission policy changed during resolution.");
|
|
20745
20903
|
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,
|
|
20904
|
+
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
20905
|
throw new Error("Capacity pool does not match policy enrollment.");
|
|
20748
20906
|
const pool = {
|
|
20749
20907
|
daemonId: runtime.daemonId,
|
|
@@ -20780,7 +20938,8 @@ function createCapacityController(options) {
|
|
|
20780
20938
|
profile: environment.profile,
|
|
20781
20939
|
consumer: initialConsumer,
|
|
20782
20940
|
runtimeRunning: request2.kind === "exec" && Boolean(resolveRunningWorkspaceContainer(environment.repoPath)),
|
|
20783
|
-
...request2.kind === "exec" ? { command: request2.command } : {}
|
|
20941
|
+
...request2.kind === "exec" ? { command: request2.command } : {},
|
|
20942
|
+
...request2.kind === "ensure" && request2.initializeNew ? { initializeNew: true } : {}
|
|
20784
20943
|
});
|
|
20785
20944
|
if (prepared.request && request2.kind === "ensure") {
|
|
20786
20945
|
try {
|
|
@@ -20798,13 +20957,14 @@ function createCapacityController(options) {
|
|
|
20798
20957
|
throw error;
|
|
20799
20958
|
}
|
|
20800
20959
|
}
|
|
20801
|
-
const signature = (0,
|
|
20960
|
+
const signature = (0, import_node_crypto27.createHmac)("sha256", payloadKey).update(
|
|
20802
20961
|
JSON.stringify({
|
|
20803
20962
|
repoPath: identity2.repoPath,
|
|
20804
20963
|
profile: environment.profile,
|
|
20805
20964
|
kind: request2.kind,
|
|
20806
20965
|
operation: request2.operation ?? null,
|
|
20807
|
-
command: request2.kind === "exec" ? request2.command : null
|
|
20966
|
+
command: request2.kind === "exec" ? request2.command : null,
|
|
20967
|
+
...request2.kind === "ensure" && request2.initializeNew ? { initializeNew: true } : {}
|
|
20808
20968
|
})
|
|
20809
20969
|
).digest("hex");
|
|
20810
20970
|
const previousPayload = acceptedPayloads.get(prepared.operationId);
|
|
@@ -20818,7 +20978,7 @@ function createCapacityController(options) {
|
|
|
20818
20978
|
{
|
|
20819
20979
|
...charge,
|
|
20820
20980
|
operationId: prepared.operationId,
|
|
20821
|
-
reservationId: (0,
|
|
20981
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20822
20982
|
policyRevision: current.revision
|
|
20823
20983
|
},
|
|
20824
20984
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -20877,7 +21037,7 @@ function createCapacityController(options) {
|
|
|
20877
21037
|
if (signal.aborted || !policy.recovery.enabled) return;
|
|
20878
21038
|
if (failedCapabilities.length === 0 || failedCapabilities.length > 64) return;
|
|
20879
21039
|
const current = readCapacityPolicy(options.directory);
|
|
20880
|
-
if (current?.admissions !== "enabled" || !(0,
|
|
21040
|
+
if (current?.admissions !== "enabled" || !(0, import_node_util15.isDeepStrictEqual)(current, policy)) return;
|
|
20881
21041
|
let observed;
|
|
20882
21042
|
try {
|
|
20883
21043
|
observed = revalidate();
|
|
@@ -20897,10 +21057,10 @@ function createCapacityController(options) {
|
|
|
20897
21057
|
} catch {
|
|
20898
21058
|
return;
|
|
20899
21059
|
}
|
|
20900
|
-
if (signal.aborted || !(0,
|
|
20901
|
-
if (!(0,
|
|
21060
|
+
if (signal.aborted || !(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment)) return;
|
|
21061
|
+
if (!(0, import_node_util15.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return;
|
|
20902
21062
|
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,
|
|
21063
|
+
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
21064
|
return;
|
|
20905
21065
|
const identity2 = environmentIdentity(environment);
|
|
20906
21066
|
const record6 = readReliabilityOperation(identity2);
|
|
@@ -20953,7 +21113,7 @@ function createCapacityController(options) {
|
|
|
20953
21113
|
// the budget module then falls back to the conservative wall duration.
|
|
20954
21114
|
activeElapsedMs: null,
|
|
20955
21115
|
profile: environment.profile,
|
|
20956
|
-
incidentId: `incident-${(0,
|
|
21116
|
+
incidentId: `incident-${(0, import_node_crypto27.randomUUID)()}`
|
|
20957
21117
|
});
|
|
20958
21118
|
} catch {
|
|
20959
21119
|
return;
|
|
@@ -20971,7 +21131,7 @@ function createCapacityController(options) {
|
|
|
20971
21131
|
{
|
|
20972
21132
|
...charge,
|
|
20973
21133
|
operationId: prepared.operationId,
|
|
20974
|
-
reservationId: (0,
|
|
21134
|
+
reservationId: (0, import_node_crypto27.randomUUID)(),
|
|
20975
21135
|
policyRevision: current.revision
|
|
20976
21136
|
},
|
|
20977
21137
|
{ estimates: resolved2.estimates, enrollment: resolved2.enrollment, pool }
|
|
@@ -20991,13 +21151,13 @@ function createCapacityController(options) {
|
|
|
20991
21151
|
}
|
|
20992
21152
|
};
|
|
20993
21153
|
}
|
|
20994
|
-
var
|
|
21154
|
+
var import_node_crypto27, import_node_path49, import_node_util15;
|
|
20995
21155
|
var init_capacity_controller = __esm({
|
|
20996
21156
|
"src/core/capacity-controller.ts"() {
|
|
20997
21157
|
"use strict";
|
|
20998
|
-
|
|
20999
|
-
|
|
21000
|
-
|
|
21158
|
+
import_node_crypto27 = require("crypto");
|
|
21159
|
+
import_node_path49 = __toESM(require("path"));
|
|
21160
|
+
import_node_util15 = require("util");
|
|
21001
21161
|
init_capacity_accounting();
|
|
21002
21162
|
init_capacity_docker_probe();
|
|
21003
21163
|
init_capacity_enrollment();
|
|
@@ -21093,7 +21253,7 @@ printf '%s %s %s\n' "$pid" "$birth" "$fingerprint"
|
|
|
21093
21253
|
|
|
21094
21254
|
// src/core/controller-observation.ts
|
|
21095
21255
|
function digest2(value) {
|
|
21096
|
-
return (0,
|
|
21256
|
+
return (0, import_node_crypto28.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
21097
21257
|
}
|
|
21098
21258
|
function readRoutes() {
|
|
21099
21259
|
return readHostRouteStateReadOnly((file) => readControllerEvidence(file, 1048576));
|
|
@@ -21156,14 +21316,14 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21156
21316
|
)).trim().split("\n");
|
|
21157
21317
|
if (metadata.length !== 2) throw new Error("Observation ownership paths unavailable.");
|
|
21158
21318
|
const [gitDir, commonDir] = metadata;
|
|
21159
|
-
const sourcePath =
|
|
21319
|
+
const sourcePath = import_node_path50.default.join(environment.repoPath, ".devcontainer/devcontainer.json");
|
|
21160
21320
|
const files = [
|
|
21161
|
-
|
|
21162
|
-
|
|
21163
|
-
|
|
21321
|
+
import_node_path50.default.join(commonDir, "devrouter/workspaces", `${environment.workspace}.json`),
|
|
21322
|
+
import_node_path50.default.join(environment.repoPath, ".devrouter.yml"),
|
|
21323
|
+
import_node_path50.default.join(gitDir, "devrouter-workspace"),
|
|
21164
21324
|
managedRuntimeStatePath(environment.repoPath, environment.workspace),
|
|
21165
21325
|
sourcePath,
|
|
21166
|
-
|
|
21326
|
+
import_node_path50.default.join(environment.repoPath, MANAGED_DEVCONTAINER_PATH)
|
|
21167
21327
|
];
|
|
21168
21328
|
const persisted = captureControllerEvidence(files);
|
|
21169
21329
|
if (fingerprint(persisted.contents[0], persisted.contents[1]) !== environment.fingerprint)
|
|
@@ -21177,7 +21337,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21177
21337
|
() => persisted.contents[3]
|
|
21178
21338
|
);
|
|
21179
21339
|
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,
|
|
21340
|
+
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
21341
|
throw new ControllerObservationBindingChanged("Observation retained configuration changed.");
|
|
21182
21342
|
const identity2 = {
|
|
21183
21343
|
repoPath: environment.repoPath,
|
|
@@ -21188,7 +21348,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21188
21348
|
if (!journal) throw new Error("Observation journal is unavailable.");
|
|
21189
21349
|
const routes = readRoutes().filter((route) => route.repoPath === environment.repoPath);
|
|
21190
21350
|
const before = await containers(state.composeProject, signal);
|
|
21191
|
-
const composeDirectory =
|
|
21351
|
+
const composeDirectory = import_node_path50.default.join(environment.repoPath, ".devcontainer");
|
|
21192
21352
|
const references = typeof source.dockerComposeFile === "string" ? [source.dockerComposeFile] : source.dockerComposeFile;
|
|
21193
21353
|
if (!Array.isArray(references) || !references.length || references.some((value) => typeof value !== "string"))
|
|
21194
21354
|
throw new Error("Observation Compose source is unavailable.");
|
|
@@ -21205,7 +21365,7 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21205
21365
|
if (!recorded || container.labels["com.docker.compose.project.working_dir"] !== composeDirectory)
|
|
21206
21366
|
throw new Error("Observation Compose ownership is unavailable.");
|
|
21207
21367
|
const files2 = recorded.split(",").map((file) => file.trim());
|
|
21208
|
-
if (files2.some((file) => !
|
|
21368
|
+
if (files2.some((file) => !import_node_path50.default.isAbsolute(file)) || !hasExactComposeIdentity(container, {
|
|
21209
21369
|
repoPath: environment.repoPath,
|
|
21210
21370
|
service: container.labels["com.docker.compose.service"] ?? "",
|
|
21211
21371
|
composeProject: state.composeProject,
|
|
@@ -21352,12 +21512,12 @@ function createControllerObservationCollector(resolve, fingerprint) {
|
|
|
21352
21512
|
};
|
|
21353
21513
|
};
|
|
21354
21514
|
}
|
|
21355
|
-
var
|
|
21515
|
+
var import_node_crypto28, import_node_path50, OBSERVATION_INSPECT_TEMPLATE;
|
|
21356
21516
|
var init_controller_observation = __esm({
|
|
21357
21517
|
"src/core/controller-observation.ts"() {
|
|
21358
21518
|
"use strict";
|
|
21359
|
-
|
|
21360
|
-
|
|
21519
|
+
import_node_crypto28 = require("crypto");
|
|
21520
|
+
import_node_path50 = __toESM(require("path"));
|
|
21361
21521
|
init_controller_binding();
|
|
21362
21522
|
init_controller_monitor();
|
|
21363
21523
|
init_controller_probe();
|
|
@@ -21381,12 +21541,12 @@ var init_controller_observation = __esm({
|
|
|
21381
21541
|
});
|
|
21382
21542
|
|
|
21383
21543
|
// src/core/controller-sessions.ts
|
|
21384
|
-
var
|
|
21544
|
+
var import_node_crypto29, import_node_util16, ControllerSessions;
|
|
21385
21545
|
var init_controller_sessions = __esm({
|
|
21386
21546
|
"src/core/controller-sessions.ts"() {
|
|
21387
21547
|
"use strict";
|
|
21388
|
-
|
|
21389
|
-
|
|
21548
|
+
import_node_crypto29 = require("crypto");
|
|
21549
|
+
import_node_util16 = require("util");
|
|
21390
21550
|
ControllerSessions = class {
|
|
21391
21551
|
constructor(store, readWakeEpoch = () => void 0) {
|
|
21392
21552
|
this.store = store;
|
|
@@ -21465,7 +21625,7 @@ var init_controller_sessions = __esm({
|
|
|
21465
21625
|
}
|
|
21466
21626
|
checkEnvironment(next, environment) {
|
|
21467
21627
|
const shared = next.environments.find((entry) => entry.repoPath === environment.repoPath);
|
|
21468
|
-
if (shared && !(0,
|
|
21628
|
+
if (shared && !(0, import_node_util16.isDeepStrictEqual)(shared, environment))
|
|
21469
21629
|
throw new Error("Controller environment binding conflicts.");
|
|
21470
21630
|
const known = [
|
|
21471
21631
|
...next.environments,
|
|
@@ -21579,7 +21739,7 @@ var init_controller_sessions = __esm({
|
|
|
21579
21739
|
const session = {
|
|
21580
21740
|
id: id5,
|
|
21581
21741
|
environmentId: environment.id,
|
|
21582
|
-
generation: (0,
|
|
21742
|
+
generation: (0, import_node_crypto29.randomUUID)(),
|
|
21583
21743
|
requirements: required,
|
|
21584
21744
|
renewedAtMs: wall,
|
|
21585
21745
|
parkingConsent: "protected",
|
|
@@ -21601,13 +21761,13 @@ var init_controller_sessions = __esm({
|
|
|
21601
21761
|
const retained = next.retainedSessions.find(
|
|
21602
21762
|
(entry) => entry.id === previous.session && entry.epoch === previous.epoch && entry.generation === previous.generation
|
|
21603
21763
|
);
|
|
21604
|
-
if (previous.store !== next.store || next.version !== 3 || previous.epoch < next.fingerprint.enrolledEpoch || !retained || next.sessions.some((entry) => entry.id === previous.session) || !(0,
|
|
21764
|
+
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
21765
|
throw new Error("Controller reconnect binding is unavailable or changed.");
|
|
21606
21766
|
const shared = this.checkEnvironment(next, environment);
|
|
21607
21767
|
const session = {
|
|
21608
21768
|
id: previous.session,
|
|
21609
21769
|
environmentId: environment.id,
|
|
21610
|
-
generation: (0,
|
|
21770
|
+
generation: (0, import_node_crypto29.randomUUID)(),
|
|
21611
21771
|
requirements: required,
|
|
21612
21772
|
renewedAtMs: wall,
|
|
21613
21773
|
parkingConsent: "protected",
|
|
@@ -21767,26 +21927,26 @@ var init_controller_sessions = __esm({
|
|
|
21767
21927
|
|
|
21768
21928
|
// src/core/controller-server.ts
|
|
21769
21929
|
function privateDirectory2(directory) {
|
|
21770
|
-
const absolute2 =
|
|
21771
|
-
let current =
|
|
21772
|
-
for (const part of absolute2.slice(current.length).split(
|
|
21773
|
-
current =
|
|
21930
|
+
const absolute2 = import_node_path51.default.resolve(directory);
|
|
21931
|
+
let current = import_node_path51.default.parse(absolute2).root;
|
|
21932
|
+
for (const part of absolute2.slice(current.length).split(import_node_path51.default.sep)) {
|
|
21933
|
+
current = import_node_path51.default.join(current, part);
|
|
21774
21934
|
try {
|
|
21775
|
-
const stat2 =
|
|
21935
|
+
const stat2 = import_node_fs40.default.lstatSync(current);
|
|
21776
21936
|
if (!stat2.isDirectory() || stat2.isSymbolicLink())
|
|
21777
21937
|
throw new Error("Unsafe controller directory.");
|
|
21778
21938
|
} catch (error) {
|
|
21779
21939
|
if (error.code !== "ENOENT") throw error;
|
|
21780
|
-
|
|
21940
|
+
import_node_fs40.default.mkdirSync(current, { mode: 448 });
|
|
21781
21941
|
}
|
|
21782
21942
|
}
|
|
21783
|
-
const stat =
|
|
21943
|
+
const stat = import_node_fs40.default.lstatSync(absolute2);
|
|
21784
21944
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0)
|
|
21785
21945
|
throw new Error("Controller directory is not private.");
|
|
21786
21946
|
}
|
|
21787
21947
|
function validateOwnedFile(file, socket) {
|
|
21788
21948
|
try {
|
|
21789
|
-
const stat =
|
|
21949
|
+
const stat = import_node_fs40.default.lstatSync(file);
|
|
21790
21950
|
if (stat.uid !== process.getuid?.() || (socket ? !stat.isSocket() : !stat.isFile()) || (stat.mode & 63) !== 0)
|
|
21791
21951
|
throw new Error("Unsafe controller artifact.");
|
|
21792
21952
|
return true;
|
|
@@ -21806,12 +21966,12 @@ async function runController(options) {
|
|
|
21806
21966
|
throw new Error("Controller bindings require one owner.");
|
|
21807
21967
|
if (options.operations && options.createOperations)
|
|
21808
21968
|
throw new Error("Controller operations have multiple owners.");
|
|
21809
|
-
const socketPath =
|
|
21969
|
+
const socketPath = import_node_path51.default.join(options.directory, "control.sock");
|
|
21810
21970
|
if (Buffer.byteLength(socketPath) > 103) throw new Error("Controller socket path is too long.");
|
|
21811
21971
|
privateDirectory2(options.directory);
|
|
21812
|
-
const lockPath =
|
|
21972
|
+
const lockPath = import_node_path51.default.join(options.directory, "owner.lock");
|
|
21813
21973
|
try {
|
|
21814
|
-
const stat =
|
|
21974
|
+
const stat = import_node_fs40.default.lstatSync(lockPath);
|
|
21815
21975
|
if (!stat.isFile() || stat.uid !== process.getuid?.())
|
|
21816
21976
|
throw new Error("Unsafe controller owner lock.");
|
|
21817
21977
|
} catch (error) {
|
|
@@ -21822,7 +21982,7 @@ async function runController(options) {
|
|
|
21822
21982
|
await withFileLock(lockPath, { activity: "controller ownership", waitMs: 0 }, async () => {
|
|
21823
21983
|
const staleSocket = validateOwnedFile(socketPath, true);
|
|
21824
21984
|
const sessions = new ControllerSessions(store, options.wakeEpoch ?? readHostWakeEpoch);
|
|
21825
|
-
if (staleSocket)
|
|
21985
|
+
if (staleSocket) import_node_fs40.default.unlinkSync(socketPath);
|
|
21826
21986
|
const incarnation = sessions.read();
|
|
21827
21987
|
const { resolve, collect } = options.createBindings?.(store.bindingFingerprint()) ?? {
|
|
21828
21988
|
resolve: options.resolve,
|
|
@@ -22368,7 +22528,7 @@ async function runController(options) {
|
|
|
22368
22528
|
resolve2();
|
|
22369
22529
|
});
|
|
22370
22530
|
});
|
|
22371
|
-
|
|
22531
|
+
import_node_fs40.default.chmodSync(socketPath, 384);
|
|
22372
22532
|
await new Promise((resolve2) => {
|
|
22373
22533
|
finish = resolve2;
|
|
22374
22534
|
options.signal.addEventListener("abort", shutdown, { once: true });
|
|
@@ -22387,13 +22547,13 @@ async function runController(options) {
|
|
|
22387
22547
|
}
|
|
22388
22548
|
});
|
|
22389
22549
|
}
|
|
22390
|
-
var
|
|
22550
|
+
var import_node_fs40, import_node_net4, import_node_path51, FRAME_BYTES;
|
|
22391
22551
|
var init_controller_server = __esm({
|
|
22392
22552
|
"src/core/controller-server.ts"() {
|
|
22393
22553
|
"use strict";
|
|
22394
|
-
|
|
22554
|
+
import_node_fs40 = __toESM(require("fs"));
|
|
22395
22555
|
import_node_net4 = __toESM(require("net"));
|
|
22396
|
-
|
|
22556
|
+
import_node_path51 = __toESM(require("path"));
|
|
22397
22557
|
init_controller_monitor();
|
|
22398
22558
|
init_controller_protocol();
|
|
22399
22559
|
init_controller_sessions();
|
|
@@ -22412,7 +22572,7 @@ __export(controller_exports, {
|
|
|
22412
22572
|
runControllerCommand: () => runControllerCommand
|
|
22413
22573
|
});
|
|
22414
22574
|
async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
22415
|
-
const directory =
|
|
22575
|
+
const directory = import_node_path52.default.join(DEVROUTER_HOME, "controller");
|
|
22416
22576
|
try {
|
|
22417
22577
|
if (method === "run") {
|
|
22418
22578
|
const controller = new AbortController();
|
|
@@ -22458,7 +22618,7 @@ async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
|
22458
22618
|
if (fields2.timeout !== void 0) fields2.timeout = Number(fields2.timeout);
|
|
22459
22619
|
await controllerRequest(
|
|
22460
22620
|
directory,
|
|
22461
|
-
{ method, ...fields2, ...repo ? { path:
|
|
22621
|
+
{ method, ...fields2, ...repo ? { path: import_node_path52.default.resolve(repo) } : {} },
|
|
22462
22622
|
(value) => process.stdout.write(`${JSON.stringify(value)}
|
|
22463
22623
|
`)
|
|
22464
22624
|
);
|
|
@@ -22473,11 +22633,11 @@ async function runControllerCommand(method, options, repo, dependencies = {}) {
|
|
|
22473
22633
|
process.exitCode = 1;
|
|
22474
22634
|
}
|
|
22475
22635
|
}
|
|
22476
|
-
var
|
|
22636
|
+
var import_node_path52;
|
|
22477
22637
|
var init_controller = __esm({
|
|
22478
22638
|
"src/commands/controller.ts"() {
|
|
22479
22639
|
"use strict";
|
|
22480
|
-
|
|
22640
|
+
import_node_path52 = __toESM(require("path"));
|
|
22481
22641
|
init_capacity_collector();
|
|
22482
22642
|
init_capacity_controller();
|
|
22483
22643
|
init_capacity_policy();
|
|
@@ -22561,7 +22721,7 @@ function refusalLines(refusal) {
|
|
|
22561
22721
|
}
|
|
22562
22722
|
async function runCapacityCommand(method, options, dependencies = {}) {
|
|
22563
22723
|
if (method !== "reconcile") throw new Error(`Unsupported capacity command: ${method}`);
|
|
22564
|
-
const directory = dependencies.directory ??
|
|
22724
|
+
const directory = dependencies.directory ?? import_node_path53.default.join(DEVROUTER_HOME, "controller");
|
|
22565
22725
|
const json = Boolean(options.json);
|
|
22566
22726
|
const emit = (payload, human) => {
|
|
22567
22727
|
process.stdout.write(json ? `${JSON.stringify(payload, null, 2)}
|
|
@@ -22617,11 +22777,11 @@ async function runCapacityCommand(method, options, dependencies = {}) {
|
|
|
22617
22777
|
);
|
|
22618
22778
|
}
|
|
22619
22779
|
}
|
|
22620
|
-
var
|
|
22780
|
+
var import_node_path53, POOL_PROBE_TIMEOUT_MS, CapacityReconcileRefusal;
|
|
22621
22781
|
var init_capacity = __esm({
|
|
22622
22782
|
"src/commands/capacity.ts"() {
|
|
22623
22783
|
"use strict";
|
|
22624
|
-
|
|
22784
|
+
import_node_path53 = __toESM(require("path"));
|
|
22625
22785
|
init_capacity_docker_probe();
|
|
22626
22786
|
init_capacity_policy();
|
|
22627
22787
|
init_reliability_operation_store();
|
|
@@ -22677,28 +22837,28 @@ function replaceDevrouterSection(content) {
|
|
|
22677
22837
|
return `${content.slice(0, start)}${buildDevrouterSection()}${content.slice(end)}`;
|
|
22678
22838
|
}
|
|
22679
22839
|
function writeRepoFile(repoPath, relPath, content) {
|
|
22680
|
-
const absolutePath = (0,
|
|
22681
|
-
(0,
|
|
22682
|
-
(0,
|
|
22840
|
+
const absolutePath = (0, import_node_path54.join)(repoPath, relPath);
|
|
22841
|
+
(0, import_node_fs41.mkdirSync)((0, import_node_path54.dirname)(absolutePath), { recursive: true });
|
|
22842
|
+
(0, import_node_fs41.writeFileSync)(absolutePath, content, "utf-8");
|
|
22683
22843
|
return absolutePath;
|
|
22684
22844
|
}
|
|
22685
22845
|
function ensureAgentsMdSection(repoPath) {
|
|
22686
|
-
const filePath = (0,
|
|
22687
|
-
if ((0,
|
|
22688
|
-
const content = (0,
|
|
22846
|
+
const filePath = (0, import_node_path54.join)(repoPath, AGENTS_MD);
|
|
22847
|
+
if ((0, import_node_fs41.existsSync)(filePath)) {
|
|
22848
|
+
const content = (0, import_node_fs41.readFileSync)(filePath, "utf-8");
|
|
22689
22849
|
if (content.includes(DEVROUTER_SENTINEL)) {
|
|
22690
22850
|
const updated = replaceDevrouterSection(content);
|
|
22691
22851
|
if (updated === void 0 || updated === content) return { path: filePath, written: false };
|
|
22692
|
-
(0,
|
|
22852
|
+
(0, import_node_fs41.writeFileSync)(filePath, updated, "utf-8");
|
|
22693
22853
|
return { path: filePath, written: true };
|
|
22694
22854
|
}
|
|
22695
|
-
(0,
|
|
22855
|
+
(0, import_node_fs41.writeFileSync)(filePath, `${content.trimEnd()}
|
|
22696
22856
|
|
|
22697
22857
|
${buildDevrouterSection()}
|
|
22698
22858
|
`, "utf-8");
|
|
22699
22859
|
return { path: filePath, written: true };
|
|
22700
22860
|
}
|
|
22701
|
-
(0,
|
|
22861
|
+
(0, import_node_fs41.writeFileSync)(filePath, `# AGENTS.md
|
|
22702
22862
|
|
|
22703
22863
|
${buildDevrouterSection()}
|
|
22704
22864
|
`, "utf-8");
|
|
@@ -22708,12 +22868,12 @@ function ensureSkillFile(repoPath) {
|
|
|
22708
22868
|
const filePath = writeRepoFile(repoPath, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT);
|
|
22709
22869
|
return { path: filePath, written: true };
|
|
22710
22870
|
}
|
|
22711
|
-
var
|
|
22871
|
+
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
22872
|
var init_agents_md = __esm({
|
|
22713
22873
|
"src/core/agents-md.ts"() {
|
|
22714
22874
|
"use strict";
|
|
22715
|
-
|
|
22716
|
-
|
|
22875
|
+
import_node_fs41 = require("fs");
|
|
22876
|
+
import_node_path54 = require("path");
|
|
22717
22877
|
DEVROUTER_SENTINEL = "<!-- devrouter -->";
|
|
22718
22878
|
DEVROUTER_END_SENTINEL = "<!-- /devrouter -->";
|
|
22719
22879
|
LEGACY_DEVROUTER_SECTION_END = "- `devrouter ls`";
|
|
@@ -23335,6 +23495,7 @@ function buildOnboardingPrompt(options = {}) {
|
|
|
23335
23495
|
"- 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
23496
|
"- 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
23497
|
"- Host-generated Compose inputs may use managedRuntime.devcontainer.prepareCommand as literal argv. Ensure runs it once from the checkout root before Compose inspection, with a 60-second bound and no implicit shell. Keep .devrouter.yml unchanged. Diagnostics never run it; changed warm mounts require separate verification.",
|
|
23498
|
+
"- Explicit 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, 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
23499
|
"- 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
23500
|
"- 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
23501
|
"- `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 +23665,7 @@ var init_ai_prompt = __esm({
|
|
|
23504
23665
|
purpose: "Write/update devrouter section in the repo's AGENTS.md and install the devrouter skill."
|
|
23505
23666
|
},
|
|
23506
23667
|
{
|
|
23507
|
-
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair] [--open] [--json]",
|
|
23668
|
+
command: "devrouter ensure [path] [--profile <name>] [--variant <name>] [--repair | --initialize-new] [--open] [--json]",
|
|
23508
23669
|
purpose: "Canonical startup and proof for an exact primary or linked checkout; atomically publishes routes after readiness."
|
|
23509
23670
|
},
|
|
23510
23671
|
{
|
|
@@ -24222,11 +24383,11 @@ function extractCurrentVersionFromRepoConfig(repoPath) {
|
|
|
24222
24383
|
};
|
|
24223
24384
|
}
|
|
24224
24385
|
function readPromptDirectory(promptDirPath) {
|
|
24225
|
-
if (!
|
|
24386
|
+
if (!import_node_fs42.default.existsSync(promptDirPath)) {
|
|
24226
24387
|
throw new Error(`Missing ${UPGRADE_PROMPTS_DIR} directory at ${promptDirPath}.`);
|
|
24227
24388
|
}
|
|
24228
24389
|
const releases = [];
|
|
24229
|
-
const files =
|
|
24390
|
+
const files = import_node_fs42.default.readdirSync(promptDirPath, { withFileTypes: true });
|
|
24230
24391
|
for (const file of files) {
|
|
24231
24392
|
if (!file.isFile() || !file.name.endsWith(".md")) {
|
|
24232
24393
|
continue;
|
|
@@ -24236,8 +24397,8 @@ function readPromptDirectory(promptDirPath) {
|
|
|
24236
24397
|
continue;
|
|
24237
24398
|
}
|
|
24238
24399
|
const version = normalizeVersion(basename);
|
|
24239
|
-
const promptPath =
|
|
24240
|
-
const prompt =
|
|
24400
|
+
const promptPath = import_node_path55.default.join(promptDirPath, file.name);
|
|
24401
|
+
const prompt = import_node_fs42.default.readFileSync(promptPath, "utf-8").trim();
|
|
24241
24402
|
releases.push({ version, prompt, promptPath });
|
|
24242
24403
|
}
|
|
24243
24404
|
const deduped = /* @__PURE__ */ new Map();
|
|
@@ -24258,19 +24419,19 @@ function listAvailableUpgradeTargets(currentVersion, releases) {
|
|
|
24258
24419
|
}
|
|
24259
24420
|
function resolvePromptDirectory(explicitPath) {
|
|
24260
24421
|
if (explicitPath) {
|
|
24261
|
-
return
|
|
24422
|
+
return import_node_path55.default.resolve(explicitPath);
|
|
24262
24423
|
}
|
|
24263
|
-
const entryFile = process.argv[1] ?
|
|
24264
|
-
const entryDir =
|
|
24265
|
-
const resolvedEntryDir =
|
|
24424
|
+
const entryFile = process.argv[1] ? import_node_path55.default.resolve(process.argv[1]) : __filename;
|
|
24425
|
+
const entryDir = import_node_path55.default.dirname(entryFile);
|
|
24426
|
+
const resolvedEntryDir = import_node_fs42.default.existsSync(entryFile) ? import_node_path55.default.dirname(import_node_fs42.default.realpathSync(entryFile)) : entryDir;
|
|
24266
24427
|
const candidates = [
|
|
24267
|
-
|
|
24268
|
-
|
|
24269
|
-
|
|
24270
|
-
|
|
24271
|
-
|
|
24428
|
+
import_node_path55.default.resolve(resolvedEntryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24429
|
+
import_node_path55.default.resolve(entryDir, "..", UPGRADE_PROMPTS_DIR),
|
|
24430
|
+
import_node_path55.default.resolve(__dirname, "..", UPGRADE_PROMPTS_DIR),
|
|
24431
|
+
import_node_path55.default.resolve(__dirname, "..", "..", UPGRADE_PROMPTS_DIR),
|
|
24432
|
+
import_node_path55.default.resolve(process.cwd(), UPGRADE_PROMPTS_DIR)
|
|
24272
24433
|
];
|
|
24273
|
-
const existing = candidates.find((candidate) =>
|
|
24434
|
+
const existing = candidates.find((candidate) => import_node_fs42.default.existsSync(candidate));
|
|
24274
24435
|
return existing ?? candidates[0];
|
|
24275
24436
|
}
|
|
24276
24437
|
function loadUpgradeCatalog(options = {}) {
|
|
@@ -24286,12 +24447,12 @@ function loadUpgradeCatalog(options = {}) {
|
|
|
24286
24447
|
releases
|
|
24287
24448
|
};
|
|
24288
24449
|
}
|
|
24289
|
-
var
|
|
24450
|
+
var import_node_fs42, import_node_path55, SEMVER_RE, UPGRADE_PROMPTS_DIR;
|
|
24290
24451
|
var init_upgrade = __esm({
|
|
24291
24452
|
"src/core/upgrade.ts"() {
|
|
24292
24453
|
"use strict";
|
|
24293
|
-
|
|
24294
|
-
|
|
24454
|
+
import_node_fs42 = __toESM(require("fs"));
|
|
24455
|
+
import_node_path55 = __toESM(require("path"));
|
|
24295
24456
|
init_repo_config();
|
|
24296
24457
|
SEMVER_RE = /^v?(\d+)\.(\d+)\.(\d+)$/;
|
|
24297
24458
|
UPGRADE_PROMPTS_DIR = "upgrade-prompts";
|
|
@@ -24444,7 +24605,7 @@ function isLoopbackHost(host) {
|
|
|
24444
24605
|
return host === "127.0.0.1" || host === "localhost" || host === "host.docker.internal";
|
|
24445
24606
|
}
|
|
24446
24607
|
function inspectCompose(composeFile, _workspace) {
|
|
24447
|
-
if (!
|
|
24608
|
+
if (!import_node_fs43.default.existsSync(composeFile)) {
|
|
24448
24609
|
return {
|
|
24449
24610
|
aliases: [],
|
|
24450
24611
|
publishedPorts: [],
|
|
@@ -24453,8 +24614,8 @@ function inspectCompose(composeFile, _workspace) {
|
|
|
24453
24614
|
};
|
|
24454
24615
|
}
|
|
24455
24616
|
try {
|
|
24456
|
-
const raw =
|
|
24457
|
-
const parsed =
|
|
24617
|
+
const raw = import_node_fs43.default.readFileSync(composeFile, "utf-8");
|
|
24618
|
+
const parsed = import_yaml6.default.parse(raw);
|
|
24458
24619
|
const root = asRecord(parsed);
|
|
24459
24620
|
const services = asRecord(root?.services);
|
|
24460
24621
|
const networks = asRecord(root?.networks);
|
|
@@ -24550,11 +24711,11 @@ function buildHostPortClaimsCheck(repoPath, workspace) {
|
|
|
24550
24711
|
}
|
|
24551
24712
|
}
|
|
24552
24713
|
function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
24553
|
-
const devcontainerDir =
|
|
24554
|
-
if (!
|
|
24714
|
+
const devcontainerDir = import_node_path56.default.join(repoPath, ".devcontainer");
|
|
24715
|
+
if (!import_node_fs43.default.existsSync(devcontainerDir)) {
|
|
24555
24716
|
return [];
|
|
24556
24717
|
}
|
|
24557
|
-
const compose = inspectCompose(
|
|
24718
|
+
const compose = inspectCompose(import_node_path56.default.join(devcontainerDir, "docker-compose.yml"), workspace);
|
|
24558
24719
|
const checks = [];
|
|
24559
24720
|
if (compose.parseError) {
|
|
24560
24721
|
checks.push({
|
|
@@ -24581,9 +24742,9 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24581
24742
|
details: compose.publishedPorts.length > 0 ? compose.publishedPorts.join(", ") : void 0,
|
|
24582
24743
|
suggestion: compose.parseError || compose.publishedPorts.length > 0 ? "Remove published ports and route services through devnet aliases with devrouter proxy apps." : void 0
|
|
24583
24744
|
});
|
|
24584
|
-
const dockerfilePath =
|
|
24585
|
-
const dockerfileExists =
|
|
24586
|
-
const dockerfile = dockerfileExists ?
|
|
24745
|
+
const dockerfilePath = import_node_path56.default.join(devcontainerDir, "Dockerfile");
|
|
24746
|
+
const dockerfileExists = import_node_fs43.default.existsSync(dockerfilePath);
|
|
24747
|
+
const dockerfile = dockerfileExists ? import_node_fs43.default.readFileSync(dockerfilePath, "utf-8") : "";
|
|
24587
24748
|
const devrouterArtifacts = ["@devrouter/cli", "devrouter-process"].filter(
|
|
24588
24749
|
(artifact) => dockerfile.includes(artifact)
|
|
24589
24750
|
);
|
|
@@ -24641,13 +24802,13 @@ function buildDevcontainerChecks(repoPath, config, workspace) {
|
|
|
24641
24802
|
});
|
|
24642
24803
|
return checks;
|
|
24643
24804
|
}
|
|
24644
|
-
var
|
|
24805
|
+
var import_node_fs43, import_node_path56, import_yaml6;
|
|
24645
24806
|
var init_devcontainer_diagnostics = __esm({
|
|
24646
24807
|
"src/core/devcontainer-diagnostics.ts"() {
|
|
24647
24808
|
"use strict";
|
|
24648
|
-
|
|
24649
|
-
|
|
24650
|
-
|
|
24809
|
+
import_node_fs43 = __toESM(require("fs"));
|
|
24810
|
+
import_node_path56 = __toESM(require("path"));
|
|
24811
|
+
import_yaml6 = __toESM(require("yaml"));
|
|
24651
24812
|
init_devcontainer_profile();
|
|
24652
24813
|
init_host_port_claims();
|
|
24653
24814
|
init_managed_post_start();
|
|
@@ -24742,11 +24903,11 @@ function reconcileRouteRunConflict(repoPath, app) {
|
|
|
24742
24903
|
}
|
|
24743
24904
|
}
|
|
24744
24905
|
}
|
|
24745
|
-
var
|
|
24906
|
+
var import_node_fs44;
|
|
24746
24907
|
var init_route_state = __esm({
|
|
24747
24908
|
"src/core/route-state.ts"() {
|
|
24748
24909
|
"use strict";
|
|
24749
|
-
|
|
24910
|
+
import_node_fs44 = __toESM(require("fs"));
|
|
24750
24911
|
init_host_routes();
|
|
24751
24912
|
init_workspace();
|
|
24752
24913
|
}
|
|
@@ -24921,7 +25082,7 @@ function toRepoStatus(repoPath) {
|
|
|
24921
25082
|
const resolvedRepoPath = resolveRepoPath(repoPath);
|
|
24922
25083
|
const configPath = getRepoConfigPath(resolvedRepoPath);
|
|
24923
25084
|
const explicitRepo = typeof repoPath === "string" && repoPath.trim().length > 0;
|
|
24924
|
-
const configExists =
|
|
25085
|
+
const configExists = import_node_fs45.default.existsSync(configPath);
|
|
24925
25086
|
if (!explicitRepo && !configExists) {
|
|
24926
25087
|
return void 0;
|
|
24927
25088
|
}
|
|
@@ -25074,11 +25235,11 @@ async function collectRouterStatus(repoPath) {
|
|
|
25074
25235
|
}
|
|
25075
25236
|
};
|
|
25076
25237
|
}
|
|
25077
|
-
var
|
|
25238
|
+
var import_node_fs45;
|
|
25078
25239
|
var init_status = __esm({
|
|
25079
25240
|
"src/core/status.ts"() {
|
|
25080
25241
|
"use strict";
|
|
25081
|
-
|
|
25242
|
+
import_node_fs45 = __toESM(require("fs"));
|
|
25082
25243
|
init_docker();
|
|
25083
25244
|
init_managed_runtime_state();
|
|
25084
25245
|
init_managed_runtime_status();
|
|
@@ -25088,14 +25249,14 @@ var init_status = __esm({
|
|
|
25088
25249
|
});
|
|
25089
25250
|
|
|
25090
25251
|
// src/core/idle-sweep.ts
|
|
25091
|
-
function idleSweepPaths(home =
|
|
25092
|
-
const directory =
|
|
25252
|
+
function idleSweepPaths(home = import_node_os7.default.homedir(), devrouterHome = DEVROUTER_HOME) {
|
|
25253
|
+
const directory = import_node_path57.default.join(devrouterHome, "idle");
|
|
25093
25254
|
return {
|
|
25094
|
-
plist:
|
|
25255
|
+
plist: import_node_path57.default.join(home, "Library", "LaunchAgents", `${IDLE_SWEEP_LABEL}.plist`),
|
|
25095
25256
|
directory,
|
|
25096
|
-
log:
|
|
25097
|
-
lastSweep:
|
|
25098
|
-
lock:
|
|
25257
|
+
log: import_node_path57.default.join(directory, "sweep.log"),
|
|
25258
|
+
lastSweep: import_node_path57.default.join(directory, "last-sweep.json"),
|
|
25259
|
+
lock: import_node_path57.default.join(directory, "sweep.lock")
|
|
25099
25260
|
};
|
|
25100
25261
|
}
|
|
25101
25262
|
function xml(value) {
|
|
@@ -25140,14 +25301,14 @@ ${env}
|
|
|
25140
25301
|
function readInstalledIdleFor(plistPath) {
|
|
25141
25302
|
let contents;
|
|
25142
25303
|
try {
|
|
25143
|
-
contents =
|
|
25304
|
+
contents = import_node_fs46.default.readFileSync(plistPath, "utf-8");
|
|
25144
25305
|
} catch {
|
|
25145
25306
|
return void 0;
|
|
25146
25307
|
}
|
|
25147
25308
|
return /<string>--idle-for<\/string>\s*<string>([^<]+)<\/string>/.exec(contents)?.[1] ?? "unknown";
|
|
25148
25309
|
}
|
|
25149
25310
|
function locateTool(name) {
|
|
25150
|
-
const result = (0,
|
|
25311
|
+
const result = (0, import_node_child_process35.spawnSync)("/bin/sh", ["-c", `command -v ${name}`], { encoding: "utf-8" });
|
|
25151
25312
|
const found = result.status === 0 ? result.stdout.trim() : "";
|
|
25152
25313
|
return found.startsWith("/") ? found : void 0;
|
|
25153
25314
|
}
|
|
@@ -25155,7 +25316,7 @@ function resolveIdleSweepEnvironment(env = process.env, locate = locateTool) {
|
|
|
25155
25316
|
const docker = locate("docker");
|
|
25156
25317
|
if (!docker)
|
|
25157
25318
|
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) =>
|
|
25319
|
+
const toolDirs = [docker, locate("devsy"), locate("devpod"), process.execPath].filter((tool) => Boolean(tool)).map((tool) => import_node_path57.default.dirname(tool));
|
|
25159
25320
|
const environment = {
|
|
25160
25321
|
PATH: [.../* @__PURE__ */ new Set([...toolDirs, ...SYSTEM_PATH])].join(":")
|
|
25161
25322
|
};
|
|
@@ -25173,9 +25334,9 @@ function installIdleSweep(input2) {
|
|
|
25173
25334
|
throw new Error("The idle sweep uses launchd and is only available on macOS.");
|
|
25174
25335
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25175
25336
|
const launchctl = input2.launchctl ?? defaultLaunchctl;
|
|
25176
|
-
const entryPath = input2.entryPath ??
|
|
25177
|
-
|
|
25178
|
-
|
|
25337
|
+
const entryPath = input2.entryPath ?? import_node_fs46.default.realpathSync(process.argv[1]);
|
|
25338
|
+
import_node_fs46.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25339
|
+
import_node_fs46.default.mkdirSync(import_node_path57.default.dirname(paths.plist), { recursive: true });
|
|
25179
25340
|
const contents = renderIdleSweepPlist({
|
|
25180
25341
|
nodePath: process.execPath,
|
|
25181
25342
|
entryPath,
|
|
@@ -25184,7 +25345,7 @@ function installIdleSweep(input2) {
|
|
|
25184
25345
|
logPath: paths.log
|
|
25185
25346
|
});
|
|
25186
25347
|
launchctl(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25187
|
-
|
|
25348
|
+
import_node_fs46.default.writeFileSync(paths.plist, contents, { mode: 420 });
|
|
25188
25349
|
const loaded = launchctl(["bootstrap", launchDomain(), paths.plist]);
|
|
25189
25350
|
if (loaded.status !== 0)
|
|
25190
25351
|
throw new Error(
|
|
@@ -25194,9 +25355,9 @@ function installIdleSweep(input2) {
|
|
|
25194
25355
|
}
|
|
25195
25356
|
function removeIdleSweep(input2 = {}) {
|
|
25196
25357
|
const paths = input2.paths ?? idleSweepPaths();
|
|
25197
|
-
if (!
|
|
25358
|
+
if (!import_node_fs46.default.existsSync(paths.plist)) return false;
|
|
25198
25359
|
(input2.launchctl ?? defaultLaunchctl)(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
|
|
25199
|
-
|
|
25360
|
+
import_node_fs46.default.rmSync(paths.plist, { force: true });
|
|
25200
25361
|
return true;
|
|
25201
25362
|
}
|
|
25202
25363
|
function summarizeSweep(idleFor, stops, error) {
|
|
@@ -25211,13 +25372,13 @@ function summarizeSweep(idleFor, stops, error) {
|
|
|
25211
25372
|
};
|
|
25212
25373
|
}
|
|
25213
25374
|
function writeLastSweep(record6, paths = idleSweepPaths()) {
|
|
25214
|
-
|
|
25215
|
-
|
|
25375
|
+
import_node_fs46.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
25376
|
+
import_node_fs46.default.writeFileSync(paths.lastSweep, `${JSON.stringify(record6, null, 2)}
|
|
25216
25377
|
`, { mode: 384 });
|
|
25217
25378
|
}
|
|
25218
25379
|
function readLastSweep(paths) {
|
|
25219
25380
|
try {
|
|
25220
|
-
return JSON.parse(
|
|
25381
|
+
return JSON.parse(import_node_fs46.default.readFileSync(paths.lastSweep, "utf-8"));
|
|
25221
25382
|
} catch {
|
|
25222
25383
|
return void 0;
|
|
25223
25384
|
}
|
|
@@ -25262,20 +25423,20 @@ function idleSweepCheck(paths = idleSweepPaths(), nowMs = Date.now()) {
|
|
|
25262
25423
|
...stale || last.failed > 0 ? { suggestion: `Inspect: ${paths.log}` } : {}
|
|
25263
25424
|
};
|
|
25264
25425
|
}
|
|
25265
|
-
var
|
|
25426
|
+
var import_node_child_process35, import_node_fs46, import_node_os7, import_node_path57, IDLE_SWEEP_LABEL, SWEEP_INTERVAL_SECONDS, SYSTEM_PATH, defaultLaunchctl;
|
|
25266
25427
|
var init_idle_sweep = __esm({
|
|
25267
25428
|
"src/core/idle-sweep.ts"() {
|
|
25268
25429
|
"use strict";
|
|
25269
|
-
|
|
25270
|
-
|
|
25271
|
-
|
|
25272
|
-
|
|
25430
|
+
import_node_child_process35 = require("child_process");
|
|
25431
|
+
import_node_fs46 = __toESM(require("fs"));
|
|
25432
|
+
import_node_os7 = __toESM(require("os"));
|
|
25433
|
+
import_node_path57 = __toESM(require("path"));
|
|
25273
25434
|
init_router();
|
|
25274
25435
|
IDLE_SWEEP_LABEL = "dev.devrouter.idle-stop";
|
|
25275
25436
|
SWEEP_INTERVAL_SECONDS = 300;
|
|
25276
25437
|
SYSTEM_PATH = ["/usr/bin", "/bin", "/usr/sbin", "/sbin"];
|
|
25277
25438
|
defaultLaunchctl = (args) => {
|
|
25278
|
-
const result = (0,
|
|
25439
|
+
const result = (0, import_node_child_process35.spawnSync)("launchctl", args, { encoding: "utf-8" });
|
|
25279
25440
|
return { status: result.status, stderr: result.stderr || result.error?.message || "" };
|
|
25280
25441
|
};
|
|
25281
25442
|
}
|
|
@@ -25289,7 +25450,7 @@ function outputFromResult(result) {
|
|
|
25289
25450
|
return output2.length > 0 ? output2 : void 0;
|
|
25290
25451
|
}
|
|
25291
25452
|
function runTool(command, args = []) {
|
|
25292
|
-
const result = (0,
|
|
25453
|
+
const result = (0, import_node_child_process36.spawnSync)(command, args, {
|
|
25293
25454
|
encoding: "utf-8"
|
|
25294
25455
|
});
|
|
25295
25456
|
if (result.error) {
|
|
@@ -25346,12 +25507,12 @@ function parseMinimumNodeMajor(value) {
|
|
|
25346
25507
|
return Number(match[1]);
|
|
25347
25508
|
}
|
|
25348
25509
|
function readPackageJson(repoPath) {
|
|
25349
|
-
const packagePath =
|
|
25350
|
-
if (!
|
|
25510
|
+
const packagePath = import_node_path58.default.join(repoPath, "package.json");
|
|
25511
|
+
if (!import_node_fs47.default.existsSync(packagePath)) {
|
|
25351
25512
|
return void 0;
|
|
25352
25513
|
}
|
|
25353
25514
|
try {
|
|
25354
|
-
return JSON.parse(
|
|
25515
|
+
return JSON.parse(import_node_fs47.default.readFileSync(packagePath, "utf-8"));
|
|
25355
25516
|
} catch {
|
|
25356
25517
|
return void 0;
|
|
25357
25518
|
}
|
|
@@ -25456,17 +25617,17 @@ function realpathOrUndefined(value) {
|
|
|
25456
25617
|
return void 0;
|
|
25457
25618
|
}
|
|
25458
25619
|
try {
|
|
25459
|
-
return
|
|
25620
|
+
return import_node_fs47.default.realpathSync(value);
|
|
25460
25621
|
} catch {
|
|
25461
25622
|
return void 0;
|
|
25462
25623
|
}
|
|
25463
25624
|
}
|
|
25464
25625
|
function isExecutableFile(filePath) {
|
|
25465
25626
|
try {
|
|
25466
|
-
if (!
|
|
25627
|
+
if (!import_node_fs47.default.statSync(filePath).isFile()) {
|
|
25467
25628
|
return false;
|
|
25468
25629
|
}
|
|
25469
|
-
|
|
25630
|
+
import_node_fs47.default.accessSync(filePath, import_node_fs47.default.constants.X_OK);
|
|
25470
25631
|
return true;
|
|
25471
25632
|
} catch {
|
|
25472
25633
|
return false;
|
|
@@ -25474,13 +25635,13 @@ function isExecutableFile(filePath) {
|
|
|
25474
25635
|
}
|
|
25475
25636
|
function displayPath(filePath) {
|
|
25476
25637
|
const home = process.env.HOME;
|
|
25477
|
-
if (!home || home.length < 2 || !filePath.startsWith(`${home}${
|
|
25638
|
+
if (!home || home.length < 2 || !filePath.startsWith(`${home}${import_node_path58.default.sep}`)) {
|
|
25478
25639
|
return filePath;
|
|
25479
25640
|
}
|
|
25480
25641
|
return `~${filePath.slice(home.length)}`;
|
|
25481
25642
|
}
|
|
25482
25643
|
function probeInstalledCliVersion(executable) {
|
|
25483
|
-
const result = (0,
|
|
25644
|
+
const result = (0, import_node_child_process36.spawnSync)(executable, ["-V"], {
|
|
25484
25645
|
encoding: "utf-8",
|
|
25485
25646
|
timeout: CLI_PATH_PROBE_TIMEOUT_MS
|
|
25486
25647
|
});
|
|
@@ -25491,7 +25652,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
25491
25652
|
}
|
|
25492
25653
|
function buildCliPathCheck(options = {}) {
|
|
25493
25654
|
const id5 = "global.cli-path";
|
|
25494
|
-
const runningVersion = options.runningVersion ?? (true ? "0.6.
|
|
25655
|
+
const runningVersion = options.runningVersion ?? (true ? "0.6.2" : "0.0.0-dev");
|
|
25495
25656
|
if (runningVersion === "0.0.0-dev") {
|
|
25496
25657
|
return {
|
|
25497
25658
|
id: id5,
|
|
@@ -25504,11 +25665,11 @@ function buildCliPathCheck(options = {}) {
|
|
|
25504
25665
|
const probeVersion = options.probeVersion ?? probeInstalledCliVersion;
|
|
25505
25666
|
const entries = [];
|
|
25506
25667
|
const seen = /* @__PURE__ */ new Set();
|
|
25507
|
-
for (const dir of (options.pathValue ?? process.env.PATH ?? "").split(
|
|
25668
|
+
for (const dir of (options.pathValue ?? process.env.PATH ?? "").split(import_node_path58.default.delimiter)) {
|
|
25508
25669
|
if (dir.length === 0) {
|
|
25509
25670
|
continue;
|
|
25510
25671
|
}
|
|
25511
|
-
const executable =
|
|
25672
|
+
const executable = import_node_path58.default.join(dir, "devrouter");
|
|
25512
25673
|
if (!isExecutableFile(executable)) {
|
|
25513
25674
|
continue;
|
|
25514
25675
|
}
|
|
@@ -25665,13 +25826,13 @@ function buildGlobalToolChecksWithoutTelemetry(repoPath) {
|
|
|
25665
25826
|
checks.push(nodeToolchainCheck(repoPath));
|
|
25666
25827
|
return checks;
|
|
25667
25828
|
}
|
|
25668
|
-
var
|
|
25829
|
+
var import_node_child_process36, import_node_fs47, import_node_path58, DEVSY_DISABLE_TELEMETRY, CLI_PATH_PROBE_TIMEOUT_MS, INSTALLED_CLI_VERSION_RE;
|
|
25669
25830
|
var init_tool_diagnostics = __esm({
|
|
25670
25831
|
"src/core/tool-diagnostics.ts"() {
|
|
25671
25832
|
"use strict";
|
|
25672
|
-
|
|
25673
|
-
|
|
25674
|
-
|
|
25833
|
+
import_node_child_process36 = require("child_process");
|
|
25834
|
+
import_node_fs47 = __toESM(require("fs"));
|
|
25835
|
+
import_node_path58 = __toESM(require("path"));
|
|
25675
25836
|
init_devsy_agent();
|
|
25676
25837
|
init_idle_sweep();
|
|
25677
25838
|
init_repo_config();
|
|
@@ -25692,10 +25853,10 @@ function inRepositoryWorkspaceScope(repoPath, worktreePath, livePaths) {
|
|
|
25692
25853
|
if (livePaths.some((candidate) => sameWorkspacePath(candidate, worktreePath))) return true;
|
|
25693
25854
|
const comparableRepo = comparableWorkspacePath(repoPath);
|
|
25694
25855
|
const comparableWorktree = comparableWorkspacePath(worktreePath);
|
|
25695
|
-
const localRoot =
|
|
25856
|
+
const localRoot = import_node_path59.default.join(comparableRepo, "trees") + import_node_path59.default.sep;
|
|
25696
25857
|
if (comparableWorktree.startsWith(localRoot)) return true;
|
|
25697
|
-
const legacyPrefix = `${
|
|
25698
|
-
return
|
|
25858
|
+
const legacyPrefix = `${import_node_path59.default.basename(comparableRepo)}-`;
|
|
25859
|
+
return import_node_path59.default.dirname(comparableWorktree) === import_node_path59.default.dirname(comparableRepo) && import_node_path59.default.basename(comparableWorktree).startsWith(legacyPrefix);
|
|
25699
25860
|
}
|
|
25700
25861
|
function previewActions(devpodStatus, routeCount, includeRecord) {
|
|
25701
25862
|
const actions = [
|
|
@@ -25947,11 +26108,11 @@ function applyWorkspaceGc(plan) {
|
|
|
25947
26108
|
candidates
|
|
25948
26109
|
};
|
|
25949
26110
|
}
|
|
25950
|
-
var
|
|
26111
|
+
var import_node_path59;
|
|
25951
26112
|
var init_workspace_gc = __esm({
|
|
25952
26113
|
"src/core/workspace-gc.ts"() {
|
|
25953
26114
|
"use strict";
|
|
25954
|
-
|
|
26115
|
+
import_node_path59 = __toESM(require("path"));
|
|
25955
26116
|
init_devpod_mutation();
|
|
25956
26117
|
init_devpod_workspaces();
|
|
25957
26118
|
init_host_routes();
|
|
@@ -26021,12 +26182,12 @@ function inspectPostgresCredentials(repoPath, config) {
|
|
|
26021
26182
|
parseErrors.push(`${app.name}: ${composeFile} (${message})`);
|
|
26022
26183
|
continue;
|
|
26023
26184
|
}
|
|
26024
|
-
if (!
|
|
26185
|
+
if (!import_node_fs48.default.existsSync(absolutePath)) {
|
|
26025
26186
|
continue;
|
|
26026
26187
|
}
|
|
26027
26188
|
try {
|
|
26028
|
-
const raw =
|
|
26029
|
-
const parsed =
|
|
26189
|
+
const raw = import_node_fs48.default.readFileSync(absolutePath, "utf-8");
|
|
26190
|
+
const parsed = import_yaml7.default.parse(raw);
|
|
26030
26191
|
const root = asRecord2(parsed);
|
|
26031
26192
|
const services = asRecord2(root?.services);
|
|
26032
26193
|
const service = asRecord2(services?.[app.docker.service]);
|
|
@@ -26389,7 +26550,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26389
26550
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
26390
26551
|
});
|
|
26391
26552
|
}
|
|
26392
|
-
const cliVersion = true ? "0.6.
|
|
26553
|
+
const cliVersion = true ? "0.6.2" : "0.0.0-dev";
|
|
26393
26554
|
const configVersion = config.devrouter?.version;
|
|
26394
26555
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
26395
26556
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -26425,9 +26586,9 @@ async function buildDoctorReport(options = {}) {
|
|
|
26425
26586
|
(app) => app.docker.composeFiles.map((filePath) => ({
|
|
26426
26587
|
app: app.name,
|
|
26427
26588
|
filePath,
|
|
26428
|
-
absolutePath:
|
|
26589
|
+
absolutePath: import_node_path60.default.resolve(repo.path, filePath)
|
|
26429
26590
|
}))
|
|
26430
|
-
).filter((entry) => !
|
|
26591
|
+
).filter((entry) => !import_node_fs48.default.existsSync(entry.absolutePath));
|
|
26431
26592
|
addCheck(checks, {
|
|
26432
26593
|
id: "repo.compose-files",
|
|
26433
26594
|
level: missingComposeFiles.length === 0 ? "ok" : "error",
|
|
@@ -26470,8 +26631,8 @@ async function buildDoctorReport(options = {}) {
|
|
|
26470
26631
|
const missingHostCwds = config.apps.filter((app) => app.runtime === "host").map((app) => ({
|
|
26471
26632
|
app: app.name,
|
|
26472
26633
|
cwd: app.hostRun.cwd,
|
|
26473
|
-
absolutePath:
|
|
26474
|
-
})).filter((entry) => !
|
|
26634
|
+
absolutePath: import_node_path60.default.resolve(repo.path, app.hostRun.cwd)
|
|
26635
|
+
})).filter((entry) => !import_node_fs48.default.existsSync(entry.absolutePath));
|
|
26475
26636
|
addCheck(checks, {
|
|
26476
26637
|
id: "repo.host-cwd",
|
|
26477
26638
|
level: missingHostCwds.length === 0 ? "ok" : "error",
|
|
@@ -26615,13 +26776,13 @@ async function buildDoctorReport(options = {}) {
|
|
|
26615
26776
|
nextSteps
|
|
26616
26777
|
};
|
|
26617
26778
|
}
|
|
26618
|
-
var
|
|
26779
|
+
var import_node_fs48, import_node_path60, import_yaml7, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
|
|
26619
26780
|
var init_doctor = __esm({
|
|
26620
26781
|
"src/core/doctor.ts"() {
|
|
26621
26782
|
"use strict";
|
|
26622
|
-
|
|
26623
|
-
|
|
26624
|
-
|
|
26783
|
+
import_node_fs48 = __toESM(require("fs"));
|
|
26784
|
+
import_node_path60 = __toESM(require("path"));
|
|
26785
|
+
import_yaml7 = __toESM(require("yaml"));
|
|
26625
26786
|
init_capacity_store();
|
|
26626
26787
|
init_docker();
|
|
26627
26788
|
init_host_routes();
|
|
@@ -27016,12 +27177,12 @@ function parseSsPortListeners(stdout, port) {
|
|
|
27016
27177
|
return listeners;
|
|
27017
27178
|
}
|
|
27018
27179
|
function findPortListeners(port) {
|
|
27019
|
-
const result = (0,
|
|
27180
|
+
const result = (0, import_node_child_process37.spawnSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
|
|
27020
27181
|
encoding: "utf-8"
|
|
27021
27182
|
});
|
|
27022
27183
|
if (result.error && result.error.code === "ENOENT") {
|
|
27023
27184
|
if (process.platform === "linux") {
|
|
27024
|
-
const ssResult = (0,
|
|
27185
|
+
const ssResult = (0, import_node_child_process37.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
27025
27186
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
27026
27187
|
return parseSsPortListeners(ssResult.stdout, port);
|
|
27027
27188
|
}
|
|
@@ -27050,11 +27211,11 @@ function findPortListeners(port) {
|
|
|
27050
27211
|
};
|
|
27051
27212
|
});
|
|
27052
27213
|
}
|
|
27053
|
-
var
|
|
27214
|
+
var import_node_child_process37;
|
|
27054
27215
|
var init_ports = __esm({
|
|
27055
27216
|
"src/util/ports.ts"() {
|
|
27056
27217
|
"use strict";
|
|
27057
|
-
|
|
27218
|
+
import_node_child_process37 = require("child_process");
|
|
27058
27219
|
}
|
|
27059
27220
|
});
|
|
27060
27221
|
|
|
@@ -27140,6 +27301,7 @@ async function runEnsureCommand(options) {
|
|
|
27140
27301
|
quiet: Boolean(options.json),
|
|
27141
27302
|
profile: options.profile,
|
|
27142
27303
|
...options.repair ? { repair: true } : {},
|
|
27304
|
+
...options.initializeNew ? { initializeNew: true } : {},
|
|
27143
27305
|
...options.variant !== void 0 ? { variant: options.variant } : {}
|
|
27144
27306
|
};
|
|
27145
27307
|
const result = await superviseLifecycle(
|
|
@@ -27327,7 +27489,7 @@ function resolveLoopback(app, repoPath, evidence) {
|
|
|
27327
27489
|
if (!evidence.containers) {
|
|
27328
27490
|
return { loopback: null, loopbackReason: "unavailable" };
|
|
27329
27491
|
}
|
|
27330
|
-
const devcontainerDir =
|
|
27492
|
+
const devcontainerDir = import_node_path61.default.join(repoPath, ".devcontainer");
|
|
27331
27493
|
const owners = evidence.containers.filter(
|
|
27332
27494
|
(container) => sameWorkspacePath(
|
|
27333
27495
|
container.labels["com.docker.compose.project.working_dir"] ?? "",
|
|
@@ -27387,13 +27549,13 @@ function buildHostEnvReport(input2) {
|
|
|
27387
27549
|
};
|
|
27388
27550
|
}
|
|
27389
27551
|
function listDevcontainerContainers(repoPath) {
|
|
27390
|
-
const listed = (0,
|
|
27552
|
+
const listed = (0, import_node_child_process38.spawnSync)(
|
|
27391
27553
|
"docker",
|
|
27392
27554
|
[
|
|
27393
27555
|
"ps",
|
|
27394
27556
|
"-a",
|
|
27395
27557
|
"--filter",
|
|
27396
|
-
`label=com.docker.compose.project.working_dir=${
|
|
27558
|
+
`label=com.docker.compose.project.working_dir=${import_node_path61.default.join(repoPath, ".devcontainer")}`,
|
|
27397
27559
|
"--format",
|
|
27398
27560
|
"{{.ID}}"
|
|
27399
27561
|
],
|
|
@@ -27408,7 +27570,7 @@ function listDevcontainerContainers(repoPath) {
|
|
|
27408
27570
|
}
|
|
27409
27571
|
}
|
|
27410
27572
|
function dockerPortBindings(containerId, port) {
|
|
27411
|
-
const result = (0,
|
|
27573
|
+
const result = (0, import_node_child_process38.spawnSync)("docker", ["port", containerId, `${port}/tcp`], {
|
|
27412
27574
|
encoding: "utf-8",
|
|
27413
27575
|
...networkDockerOptions()
|
|
27414
27576
|
});
|
|
@@ -27523,12 +27685,12 @@ function hostEnvVariables(report, processEnv) {
|
|
|
27523
27685
|
}
|
|
27524
27686
|
return variables;
|
|
27525
27687
|
}
|
|
27526
|
-
var
|
|
27688
|
+
var import_node_child_process38, import_node_path61, LOOPBACK_UPSTREAM_HOSTS, ROUTED_TCP_PARAMS;
|
|
27527
27689
|
var init_host_env = __esm({
|
|
27528
27690
|
"src/core/host-env.ts"() {
|
|
27529
27691
|
"use strict";
|
|
27530
|
-
|
|
27531
|
-
|
|
27692
|
+
import_node_child_process38 = require("child_process");
|
|
27693
|
+
import_node_path61 = __toESM(require("path"));
|
|
27532
27694
|
init_devcontainer_profile();
|
|
27533
27695
|
init_devpod_environment();
|
|
27534
27696
|
init_docker();
|
|
@@ -27625,7 +27787,7 @@ function hostCommandEnvironment(report, processEnv) {
|
|
|
27625
27787
|
}
|
|
27626
27788
|
function runHostCommand(command, env) {
|
|
27627
27789
|
return new Promise((resolve) => {
|
|
27628
|
-
const child = (0,
|
|
27790
|
+
const child = (0, import_node_child_process39.spawn)(command[0], command.slice(1), { env, stdio: "inherit" });
|
|
27629
27791
|
const forward = (signal) => () => child.kill(signal);
|
|
27630
27792
|
const handlers = [
|
|
27631
27793
|
["SIGINT", forward("SIGINT")],
|
|
@@ -27645,7 +27807,7 @@ function runHostCommand(command, env) {
|
|
|
27645
27807
|
settle(error.code === "ENOENT" ? 127 : 126);
|
|
27646
27808
|
});
|
|
27647
27809
|
child.on("exit", (code, signal) => {
|
|
27648
|
-
settle(code ?? 128 + (signal ?
|
|
27810
|
+
settle(code ?? 128 + (signal ? import_node_os8.constants.signals[signal] ?? 0 : 0));
|
|
27649
27811
|
});
|
|
27650
27812
|
});
|
|
27651
27813
|
}
|
|
@@ -27665,12 +27827,12 @@ async function runEnvCommand(invocation) {
|
|
|
27665
27827
|
}
|
|
27666
27828
|
process.stdout.write(formatEnvReport(report));
|
|
27667
27829
|
}
|
|
27668
|
-
var
|
|
27830
|
+
var import_node_child_process39, import_node_os8, HOST_PORT_ENV_PREFIX;
|
|
27669
27831
|
var init_env = __esm({
|
|
27670
27832
|
"src/commands/env.ts"() {
|
|
27671
27833
|
"use strict";
|
|
27672
|
-
|
|
27673
|
-
|
|
27834
|
+
import_node_child_process39 = require("child_process");
|
|
27835
|
+
import_node_os8 = require("os");
|
|
27674
27836
|
init_host_env();
|
|
27675
27837
|
init_managed_host_ports();
|
|
27676
27838
|
init_output();
|
|
@@ -27719,8 +27881,8 @@ var init_status2 = __esm({
|
|
|
27719
27881
|
|
|
27720
27882
|
// src/core/harness-continuation.ts
|
|
27721
27883
|
function harnessContinuationPath(repoRoot) {
|
|
27722
|
-
const key = (0,
|
|
27723
|
-
return
|
|
27884
|
+
const key = (0, import_node_crypto30.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
|
|
27885
|
+
return import_node_path62.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
|
|
27724
27886
|
}
|
|
27725
27887
|
function counter4(value) {
|
|
27726
27888
|
return Number.isSafeInteger(value) && value >= 0;
|
|
@@ -27733,7 +27895,7 @@ function validEntry(value) {
|
|
|
27733
27895
|
function readLedgerSync(file, nowMs) {
|
|
27734
27896
|
let stat;
|
|
27735
27897
|
try {
|
|
27736
|
-
stat =
|
|
27898
|
+
stat = import_node_fs49.default.lstatSync(file);
|
|
27737
27899
|
} catch {
|
|
27738
27900
|
return [];
|
|
27739
27901
|
}
|
|
@@ -27741,7 +27903,7 @@ function readLedgerSync(file, nowMs) {
|
|
|
27741
27903
|
if (stat.uid !== process.getuid?.() || (stat.mode & 63) !== 0) return [];
|
|
27742
27904
|
let parsed;
|
|
27743
27905
|
try {
|
|
27744
|
-
parsed = JSON.parse(
|
|
27906
|
+
parsed = JSON.parse(import_node_fs49.default.readFileSync(file, "utf-8"));
|
|
27745
27907
|
} catch {
|
|
27746
27908
|
return [];
|
|
27747
27909
|
}
|
|
@@ -27761,7 +27923,7 @@ function claimHarnessContinuation(repoRoot, claim2) {
|
|
|
27761
27923
|
const nowMs = claim2.nowMs ?? Date.now();
|
|
27762
27924
|
try {
|
|
27763
27925
|
const file = harnessContinuationPath(repoRoot);
|
|
27764
|
-
|
|
27926
|
+
import_node_fs49.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27765
27927
|
return withFileLockSync(
|
|
27766
27928
|
`${file}.lock`,
|
|
27767
27929
|
{ activity: "harness continuation claim", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27793,7 +27955,7 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27793
27955
|
const nowMs = settlement.nowMs ?? Date.now();
|
|
27794
27956
|
try {
|
|
27795
27957
|
const file = harnessContinuationPath(repoRoot);
|
|
27796
|
-
|
|
27958
|
+
import_node_fs49.default.mkdirSync(import_node_path62.default.dirname(file), { recursive: true, mode: 448 });
|
|
27797
27959
|
withFileLockSync(
|
|
27798
27960
|
`${file}.lock`,
|
|
27799
27961
|
{ activity: "harness continuation settlement", waitMs: HARNESS_CONTINUATION_LOCK_WAIT_MS },
|
|
@@ -27817,13 +27979,13 @@ function settleHarnessContinuation(repoRoot, toolUseId, settlement) {
|
|
|
27817
27979
|
} catch {
|
|
27818
27980
|
}
|
|
27819
27981
|
}
|
|
27820
|
-
var
|
|
27982
|
+
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
27983
|
var init_harness_continuation = __esm({
|
|
27822
27984
|
"src/core/harness-continuation.ts"() {
|
|
27823
27985
|
"use strict";
|
|
27824
|
-
|
|
27825
|
-
|
|
27826
|
-
|
|
27986
|
+
import_node_crypto30 = require("crypto");
|
|
27987
|
+
import_node_fs49 = __toESM(require("fs"));
|
|
27988
|
+
import_node_path62 = __toESM(require("path"));
|
|
27827
27989
|
init_atomic_file();
|
|
27828
27990
|
init_file_lock();
|
|
27829
27991
|
init_router();
|
|
@@ -27842,12 +28004,12 @@ function isTransitionalHarnessPhase(phase) {
|
|
|
27842
28004
|
return TRANSITIONAL_PHASES.includes(phase);
|
|
27843
28005
|
}
|
|
27844
28006
|
function findHarnessGateRepoRoot(cwd) {
|
|
27845
|
-
let current =
|
|
28007
|
+
let current = import_node_path63.default.resolve(cwd);
|
|
27846
28008
|
for (let depth = 0; depth < REPO_ROOT_MAX_DEPTH; depth += 1) {
|
|
27847
|
-
if (
|
|
28009
|
+
if (import_node_fs50.default.existsSync(import_node_path63.default.join(current, ".devrouter.yml"))) {
|
|
27848
28010
|
return current;
|
|
27849
28011
|
}
|
|
27850
|
-
const parent =
|
|
28012
|
+
const parent = import_node_path63.default.dirname(current);
|
|
27851
28013
|
if (parent === current) {
|
|
27852
28014
|
return void 0;
|
|
27853
28015
|
}
|
|
@@ -27939,12 +28101,12 @@ function parseHarnessGateBudget(value) {
|
|
|
27939
28101
|
}
|
|
27940
28102
|
return Math.min(Math.trunc(parsed), HARNESS_GATE_MAX_BUDGET_MS);
|
|
27941
28103
|
}
|
|
27942
|
-
var
|
|
28104
|
+
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
28105
|
var init_harness_gate = __esm({
|
|
27944
28106
|
"src/core/harness-gate.ts"() {
|
|
27945
28107
|
"use strict";
|
|
27946
|
-
|
|
27947
|
-
|
|
28108
|
+
import_node_fs50 = __toESM(require("fs"));
|
|
28109
|
+
import_node_path63 = __toESM(require("path"));
|
|
27948
28110
|
init_reliability_operation_store();
|
|
27949
28111
|
init_workspace();
|
|
27950
28112
|
init_workspace_runtime();
|
|
@@ -28203,7 +28365,7 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28203
28365
|
}
|
|
28204
28366
|
const budgetMs = parseHarnessGateBudget(options.waitBudgetMs);
|
|
28205
28367
|
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,
|
|
28368
|
+
const payloadSha256 = (0, import_node_crypto31.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
|
|
28207
28369
|
const claim2 = dependencies.claim ?? ((root, input2) => {
|
|
28208
28370
|
const outcome = claimHarnessContinuation(root, input2);
|
|
28209
28371
|
if (outcome.kind === "claimed") {
|
|
@@ -28311,11 +28473,11 @@ async function runHarnessCommand(method, options, repoPath, dependencies = {}) {
|
|
|
28311
28473
|
`
|
|
28312
28474
|
);
|
|
28313
28475
|
}
|
|
28314
|
-
var
|
|
28476
|
+
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
28477
|
var init_harness = __esm({
|
|
28316
28478
|
"src/commands/harness.ts"() {
|
|
28317
28479
|
"use strict";
|
|
28318
|
-
|
|
28480
|
+
import_node_crypto31 = require("crypto");
|
|
28319
28481
|
init_harness_continuation();
|
|
28320
28482
|
init_harness_gate();
|
|
28321
28483
|
MAX_HOOK_PAYLOAD_BYTES = 256 * 1024;
|
|
@@ -28431,7 +28593,7 @@ async function runOpenCommand(name) {
|
|
|
28431
28593
|
);
|
|
28432
28594
|
return;
|
|
28433
28595
|
}
|
|
28434
|
-
const result = (0,
|
|
28596
|
+
const result = (0, import_node_child_process40.spawnSync)("open", [url], { encoding: "utf-8" });
|
|
28435
28597
|
if (result.status !== 0) {
|
|
28436
28598
|
const details = [result.stdout, result.stderr].filter(Boolean).join("\n").trim();
|
|
28437
28599
|
throw new Error(`Unable to open '${url}': ${details || "unknown error"}`);
|
|
@@ -28439,11 +28601,11 @@ async function runOpenCommand(name) {
|
|
|
28439
28601
|
process.stdout.write(`Opened ${url}
|
|
28440
28602
|
`);
|
|
28441
28603
|
}
|
|
28442
|
-
var
|
|
28604
|
+
var import_node_child_process40;
|
|
28443
28605
|
var init_open = __esm({
|
|
28444
28606
|
"src/commands/open.ts"() {
|
|
28445
28607
|
"use strict";
|
|
28446
|
-
|
|
28608
|
+
import_node_child_process40 = require("child_process");
|
|
28447
28609
|
init_docker();
|
|
28448
28610
|
init_host_routes();
|
|
28449
28611
|
init_repo_config();
|
|
@@ -28487,7 +28649,7 @@ async function runLogsCommand(options) {
|
|
|
28487
28649
|
const args = ["logs", "--tail", tail, ROUTER_CONTAINER_NAME];
|
|
28488
28650
|
if (options.follow) {
|
|
28489
28651
|
args.splice(1, 0, "-f");
|
|
28490
|
-
const child = (0,
|
|
28652
|
+
const child = (0, import_node_child_process41.spawn)("docker", args, { stdio: "inherit" });
|
|
28491
28653
|
const onSignal = () => {
|
|
28492
28654
|
child.kill("SIGTERM");
|
|
28493
28655
|
};
|
|
@@ -28501,17 +28663,17 @@ async function runLogsCommand(options) {
|
|
|
28501
28663
|
});
|
|
28502
28664
|
});
|
|
28503
28665
|
} else {
|
|
28504
|
-
const result = (0,
|
|
28666
|
+
const result = (0, import_node_child_process41.spawnSync)("docker", args, { stdio: "inherit" });
|
|
28505
28667
|
if (result.status !== 0) {
|
|
28506
28668
|
throw new Error("Failed to retrieve router logs.");
|
|
28507
28669
|
}
|
|
28508
28670
|
}
|
|
28509
28671
|
}
|
|
28510
|
-
var
|
|
28672
|
+
var import_node_child_process41;
|
|
28511
28673
|
var init_logs = __esm({
|
|
28512
28674
|
"src/commands/logs.ts"() {
|
|
28513
28675
|
"use strict";
|
|
28514
|
-
|
|
28676
|
+
import_node_child_process41 = require("child_process");
|
|
28515
28677
|
init_docker();
|
|
28516
28678
|
init_lifecycle_diagnostics();
|
|
28517
28679
|
init_router();
|
|
@@ -28555,17 +28717,17 @@ function asRecord3(value) {
|
|
|
28555
28717
|
return value;
|
|
28556
28718
|
}
|
|
28557
28719
|
function readJson(filePath) {
|
|
28558
|
-
if (!
|
|
28720
|
+
if (!import_node_fs51.default.existsSync(filePath)) {
|
|
28559
28721
|
return void 0;
|
|
28560
28722
|
}
|
|
28561
28723
|
try {
|
|
28562
|
-
return JSON.parse(
|
|
28724
|
+
return JSON.parse(import_node_fs51.default.readFileSync(filePath, "utf-8"));
|
|
28563
28725
|
} catch {
|
|
28564
28726
|
return void 0;
|
|
28565
28727
|
}
|
|
28566
28728
|
}
|
|
28567
28729
|
function relative(repoPath, filePath) {
|
|
28568
|
-
return
|
|
28730
|
+
return import_node_path64.default.relative(repoPath, filePath) || ".";
|
|
28569
28731
|
}
|
|
28570
28732
|
function redactEnvAssignments(value) {
|
|
28571
28733
|
return value.replace(
|
|
@@ -28606,7 +28768,7 @@ function inspectPackageManager(repoPath, pkg) {
|
|
|
28606
28768
|
["bun.lock", "bun"]
|
|
28607
28769
|
];
|
|
28608
28770
|
for (const [fileName, name] of lockfiles) {
|
|
28609
|
-
if (
|
|
28771
|
+
if (import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28610
28772
|
return { name, source: fileName };
|
|
28611
28773
|
}
|
|
28612
28774
|
}
|
|
@@ -28621,9 +28783,9 @@ function inspectNode(repoPath, pkg) {
|
|
|
28621
28783
|
if (typeof engines?.node === "string") {
|
|
28622
28784
|
return { version: engines.node, source: "package.json:engines.node" };
|
|
28623
28785
|
}
|
|
28624
|
-
const nvmrc =
|
|
28625
|
-
if (
|
|
28626
|
-
const version =
|
|
28786
|
+
const nvmrc = import_node_path64.default.join(repoPath, ".nvmrc");
|
|
28787
|
+
if (import_node_fs51.default.existsSync(nvmrc)) {
|
|
28788
|
+
const version = import_node_fs51.default.readFileSync(nvmrc, "utf-8").trim();
|
|
28627
28789
|
return { version, source: ".nvmrc" };
|
|
28628
28790
|
}
|
|
28629
28791
|
return void 0;
|
|
@@ -28684,7 +28846,7 @@ function configuredComposeFiles(repoPath) {
|
|
|
28684
28846
|
const files = config.apps.filter(
|
|
28685
28847
|
(app) => app.runtime === "docker"
|
|
28686
28848
|
).flatMap((app) => app.docker.composeFiles).filter(
|
|
28687
|
-
(fileName) => !
|
|
28849
|
+
(fileName) => !import_node_path64.default.isAbsolute(fileName) && !import_node_path64.default.normalize(fileName).startsWith("..")
|
|
28688
28850
|
);
|
|
28689
28851
|
return Array.from(new Set(files));
|
|
28690
28852
|
} catch {
|
|
@@ -28702,7 +28864,7 @@ function composeFiles(repoPath) {
|
|
|
28702
28864
|
...configuredComposeFiles(repoPath)
|
|
28703
28865
|
];
|
|
28704
28866
|
return Array.from(new Set(candidates)).filter(
|
|
28705
|
-
(fileName) =>
|
|
28867
|
+
(fileName) => import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))
|
|
28706
28868
|
);
|
|
28707
28869
|
}
|
|
28708
28870
|
function stringArray2(value) {
|
|
@@ -28740,7 +28902,7 @@ function inspectServices(repoPath) {
|
|
|
28740
28902
|
const services = [];
|
|
28741
28903
|
for (const fileName of composeFiles(repoPath)) {
|
|
28742
28904
|
try {
|
|
28743
|
-
const parsed =
|
|
28905
|
+
const parsed = import_yaml8.default.parse(import_node_fs51.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8"));
|
|
28744
28906
|
const serviceMap = asRecord3(asRecord3(parsed)?.services);
|
|
28745
28907
|
for (const [name, value] of Object.entries(serviceMap ?? {})) {
|
|
28746
28908
|
const service = asRecord3(value);
|
|
@@ -28775,8 +28937,8 @@ function inspectServices(repoPath) {
|
|
|
28775
28937
|
return services;
|
|
28776
28938
|
}
|
|
28777
28939
|
function inspectEnvFiles(repoPath) {
|
|
28778
|
-
const files =
|
|
28779
|
-
const content =
|
|
28940
|
+
const files = import_node_fs51.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
|
|
28941
|
+
const content = import_node_fs51.default.readFileSync(import_node_path64.default.join(repoPath, fileName), "utf-8");
|
|
28780
28942
|
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
28943
|
return { path: fileName, names };
|
|
28782
28944
|
});
|
|
@@ -28790,18 +28952,18 @@ function inspectEnvFiles(repoPath) {
|
|
|
28790
28952
|
};
|
|
28791
28953
|
}
|
|
28792
28954
|
function inspectDevcontainer(repoPath) {
|
|
28793
|
-
const dir =
|
|
28794
|
-
if (!
|
|
28955
|
+
const dir = import_node_path64.default.join(repoPath, ".devcontainer");
|
|
28956
|
+
if (!import_node_fs51.default.existsSync(dir)) {
|
|
28795
28957
|
return { exists: false, files: [] };
|
|
28796
28958
|
}
|
|
28797
28959
|
return {
|
|
28798
28960
|
exists: true,
|
|
28799
|
-
files:
|
|
28961
|
+
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
28962
|
};
|
|
28801
28963
|
}
|
|
28802
28964
|
function inspectDevrouter(repoPath) {
|
|
28803
28965
|
const configPath = getRepoConfigPath(repoPath);
|
|
28804
|
-
if (!
|
|
28966
|
+
if (!import_node_fs51.default.existsSync(configPath)) {
|
|
28805
28967
|
return {
|
|
28806
28968
|
exists: false,
|
|
28807
28969
|
configPath,
|
|
@@ -28845,15 +29007,15 @@ function inspectAgentGuidance(repoPath) {
|
|
|
28845
29007
|
["AGENTS.md", "agents"],
|
|
28846
29008
|
["CLAUDE.md", "claude"]
|
|
28847
29009
|
]) {
|
|
28848
|
-
if (
|
|
29010
|
+
if (import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, fileName))) {
|
|
28849
29011
|
results.push({ path: fileName, kind });
|
|
28850
29012
|
}
|
|
28851
29013
|
}
|
|
28852
|
-
const skillsDir =
|
|
28853
|
-
if (
|
|
28854
|
-
for (const name of
|
|
28855
|
-
const skillPath =
|
|
28856
|
-
if (
|
|
29014
|
+
const skillsDir = import_node_path64.default.join(repoPath, ".agents", "skills");
|
|
29015
|
+
if (import_node_fs51.default.existsSync(skillsDir)) {
|
|
29016
|
+
for (const name of import_node_fs51.default.readdirSync(skillsDir).sort()) {
|
|
29017
|
+
const skillPath = import_node_path64.default.join(skillsDir, name, "SKILL.md");
|
|
29018
|
+
if (import_node_fs51.default.existsSync(skillPath)) {
|
|
28857
29019
|
results.push({ path: relative(repoPath, skillPath), kind: "skill" });
|
|
28858
29020
|
}
|
|
28859
29021
|
}
|
|
@@ -28896,7 +29058,7 @@ function buildIssues(report) {
|
|
|
28896
29058
|
}
|
|
28897
29059
|
function inspectRepo(options = {}) {
|
|
28898
29060
|
const repoPath = resolveRepoPath(options.repo);
|
|
28899
|
-
const pkg = readJson(
|
|
29061
|
+
const pkg = readJson(import_node_path64.default.join(repoPath, "package.json"));
|
|
28900
29062
|
const scripts = inspectScripts(pkg);
|
|
28901
29063
|
const reportWithoutIssues = {
|
|
28902
29064
|
repoPath,
|
|
@@ -28915,13 +29077,13 @@ function inspectRepo(options = {}) {
|
|
|
28915
29077
|
issues: buildIssues(reportWithoutIssues)
|
|
28916
29078
|
};
|
|
28917
29079
|
}
|
|
28918
|
-
var
|
|
29080
|
+
var import_node_fs51, import_node_path64, import_yaml8;
|
|
28919
29081
|
var init_repo_inspect = __esm({
|
|
28920
29082
|
"src/core/repo-inspect.ts"() {
|
|
28921
29083
|
"use strict";
|
|
28922
|
-
|
|
28923
|
-
|
|
28924
|
-
|
|
29084
|
+
import_node_fs51 = __toESM(require("fs"));
|
|
29085
|
+
import_node_path64 = __toESM(require("path"));
|
|
29086
|
+
import_yaml8 = __toESM(require("yaml"));
|
|
28925
29087
|
init_repo_config();
|
|
28926
29088
|
}
|
|
28927
29089
|
});
|
|
@@ -29025,7 +29187,7 @@ function requiredFileChecks(repoPath) {
|
|
|
29025
29187
|
".devcontainer/docker-compose.yml",
|
|
29026
29188
|
".devrouter.yml"
|
|
29027
29189
|
];
|
|
29028
|
-
const missing = required.filter((fileName) => !
|
|
29190
|
+
const missing = required.filter((fileName) => !import_node_fs52.default.existsSync(import_node_path65.default.join(repoPath, fileName)));
|
|
29029
29191
|
return {
|
|
29030
29192
|
id: "repo.devcontainer.verify-files",
|
|
29031
29193
|
level: missing.length === 0 ? "ok" : "error",
|
|
@@ -29250,12 +29412,12 @@ async function verifyDevcontainer(options = {}) {
|
|
|
29250
29412
|
nextSteps: collectNextSteps3(checks)
|
|
29251
29413
|
};
|
|
29252
29414
|
}
|
|
29253
|
-
var
|
|
29415
|
+
var import_node_fs52, import_node_path65;
|
|
29254
29416
|
var init_devcontainer_verify = __esm({
|
|
29255
29417
|
"src/core/devcontainer-verify.ts"() {
|
|
29256
29418
|
"use strict";
|
|
29257
|
-
|
|
29258
|
-
|
|
29419
|
+
import_node_fs52 = __toESM(require("fs"));
|
|
29420
|
+
import_node_path65 = __toESM(require("path"));
|
|
29259
29421
|
init_capabilities();
|
|
29260
29422
|
init_doctor();
|
|
29261
29423
|
init_host_routes();
|
|
@@ -29552,7 +29714,7 @@ function packageManagerIssues(repo) {
|
|
|
29552
29714
|
}
|
|
29553
29715
|
function plannedFiles(repoPath, version) {
|
|
29554
29716
|
const repo = inspectRepo({ repo: repoPath });
|
|
29555
|
-
const projectName = sanitizeProjectName(
|
|
29717
|
+
const projectName = sanitizeProjectName(import_node_path66.default.basename(repo.repoPath));
|
|
29556
29718
|
const nodeMajor = majorVersion(repo.node?.version, "24");
|
|
29557
29719
|
const pnpmVersion = repo.packageManager?.name === "pnpm" && repo.packageManager.version ? repo.packageManager.version : DEFAULT_PNPM_VERSION;
|
|
29558
29720
|
const port = inferPort2(repo);
|
|
@@ -29597,8 +29759,8 @@ function plannedFiles(repoPath, version) {
|
|
|
29597
29759
|
};
|
|
29598
29760
|
}
|
|
29599
29761
|
function classifyFile(repoPath, file) {
|
|
29600
|
-
const absolutePath =
|
|
29601
|
-
if (!
|
|
29762
|
+
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29763
|
+
if (!import_node_fs53.default.existsSync(absolutePath)) {
|
|
29602
29764
|
return {
|
|
29603
29765
|
path: file.relativePath,
|
|
29604
29766
|
action: "create",
|
|
@@ -29606,7 +29768,7 @@ function classifyFile(repoPath, file) {
|
|
|
29606
29768
|
bytes: Buffer.byteLength(file.content)
|
|
29607
29769
|
};
|
|
29608
29770
|
}
|
|
29609
|
-
const current =
|
|
29771
|
+
const current = import_node_fs53.default.readFileSync(absolutePath, "utf-8");
|
|
29610
29772
|
if (!current.includes(MANAGED_MARKER2)) {
|
|
29611
29773
|
return {
|
|
29612
29774
|
path: file.relativePath,
|
|
@@ -29663,11 +29825,11 @@ function buildPlan(repoPath, dryRun, version) {
|
|
|
29663
29825
|
};
|
|
29664
29826
|
}
|
|
29665
29827
|
function writeFile(repoPath, file) {
|
|
29666
|
-
const absolutePath =
|
|
29667
|
-
|
|
29668
|
-
|
|
29828
|
+
const absolutePath = import_node_path66.default.join(repoPath, file.relativePath);
|
|
29829
|
+
import_node_fs53.default.mkdirSync(import_node_path66.default.dirname(absolutePath), { recursive: true });
|
|
29830
|
+
import_node_fs53.default.writeFileSync(absolutePath, file.content, "utf-8");
|
|
29669
29831
|
if (file.executable) {
|
|
29670
|
-
|
|
29832
|
+
import_node_fs53.default.chmodSync(absolutePath, 493);
|
|
29671
29833
|
}
|
|
29672
29834
|
}
|
|
29673
29835
|
function writeDevcontainer(options = {}) {
|
|
@@ -29705,12 +29867,12 @@ function writeDevcontainer(options = {}) {
|
|
|
29705
29867
|
nextSteps: postWriteNextSteps(repoPath)
|
|
29706
29868
|
};
|
|
29707
29869
|
}
|
|
29708
|
-
var
|
|
29870
|
+
var import_node_fs53, import_node_path66, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
|
|
29709
29871
|
var init_devcontainer_write = __esm({
|
|
29710
29872
|
"src/core/devcontainer-write.ts"() {
|
|
29711
29873
|
"use strict";
|
|
29712
|
-
|
|
29713
|
-
|
|
29874
|
+
import_node_fs53 = __toESM(require("fs"));
|
|
29875
|
+
import_node_path66 = __toESM(require("path"));
|
|
29714
29876
|
init_repo_config();
|
|
29715
29877
|
init_repo_inspect();
|
|
29716
29878
|
MANAGED_MARKER2 = "devrouter:managed devcontainer";
|
|
@@ -29895,7 +30057,7 @@ function parseMappings(value) {
|
|
|
29895
30057
|
return Object.fromEntries(mappings);
|
|
29896
30058
|
}
|
|
29897
30059
|
function parseProfilePlanContract(source) {
|
|
29898
|
-
const document = (0,
|
|
30060
|
+
const document = (0, import_yaml9.parseDocument)(source, {
|
|
29899
30061
|
merge: false,
|
|
29900
30062
|
schema: "core",
|
|
29901
30063
|
uniqueKeys: true
|
|
@@ -30044,13 +30206,13 @@ function buildProfilePlanReport(options) {
|
|
|
30044
30206
|
return { ...report, contractPath, bindings: bindings2 };
|
|
30045
30207
|
}
|
|
30046
30208
|
function loadContract(repoPath, contractPath) {
|
|
30047
|
-
if (
|
|
30209
|
+
if (import_node_path67.default.isAbsolute(contractPath)) {
|
|
30048
30210
|
fail3("profile plan contract path must be relative to the repository.");
|
|
30049
30211
|
}
|
|
30050
30212
|
const absolutePath = assertPathWithinRepo(contractPath, repoPath, "Profile plan contract");
|
|
30051
30213
|
let metadata;
|
|
30052
30214
|
try {
|
|
30053
|
-
metadata =
|
|
30215
|
+
metadata = import_node_fs54.default.lstatSync(absolutePath);
|
|
30054
30216
|
} catch (error) {
|
|
30055
30217
|
fail3(`could not inspect profile plan contract '${contractPath}': ${error.message}`);
|
|
30056
30218
|
}
|
|
@@ -30060,16 +30222,16 @@ function loadContract(repoPath, contractPath) {
|
|
|
30060
30222
|
if (metadata.size > MAX_CONTRACT_BYTES) {
|
|
30061
30223
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30062
30224
|
}
|
|
30063
|
-
const realRepo =
|
|
30064
|
-
const realContract =
|
|
30225
|
+
const realRepo = import_node_fs54.default.realpathSync(repoPath);
|
|
30226
|
+
const realContract = import_node_fs54.default.realpathSync(absolutePath);
|
|
30065
30227
|
assertPathWithinRepo(realContract, realRepo, "Profile plan contract");
|
|
30066
|
-
const source =
|
|
30228
|
+
const source = import_node_fs54.default.readFileSync(absolutePath, "utf-8");
|
|
30067
30229
|
if (Buffer.byteLength(source, "utf-8") > MAX_CONTRACT_BYTES) {
|
|
30068
30230
|
fail3(`profile plan contract exceeds the ${MAX_CONTRACT_BYTES}-byte limit.`);
|
|
30069
30231
|
}
|
|
30070
30232
|
return {
|
|
30071
30233
|
contract: parseProfilePlanContract(source),
|
|
30072
|
-
contractPath:
|
|
30234
|
+
contractPath: import_node_path67.default.relative(repoPath, absolutePath).split(import_node_path67.default.sep).join("/")
|
|
30073
30235
|
};
|
|
30074
30236
|
}
|
|
30075
30237
|
function resolveProfilePlan(options) {
|
|
@@ -30083,13 +30245,13 @@ function resolveProfilePlan(options) {
|
|
|
30083
30245
|
contractPath: loaded.contractPath
|
|
30084
30246
|
});
|
|
30085
30247
|
}
|
|
30086
|
-
var
|
|
30248
|
+
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
30249
|
var init_profile_plan = __esm({
|
|
30088
30250
|
"src/core/profile-plan.ts"() {
|
|
30089
30251
|
"use strict";
|
|
30090
|
-
|
|
30091
|
-
|
|
30092
|
-
|
|
30252
|
+
import_node_fs54 = __toESM(require("fs"));
|
|
30253
|
+
import_node_path67 = __toESM(require("path"));
|
|
30254
|
+
import_yaml9 = require("yaml");
|
|
30093
30255
|
init_paths();
|
|
30094
30256
|
init_profile_resolution();
|
|
30095
30257
|
init_repo_config();
|
|
@@ -30120,7 +30282,7 @@ async function runProfileResolveCommand(options) {
|
|
|
30120
30282
|
async function runProfilePlanCommand(options) {
|
|
30121
30283
|
const report = resolveProfilePlan(options);
|
|
30122
30284
|
if (options.output) {
|
|
30123
|
-
writeFileAtomically(
|
|
30285
|
+
writeFileAtomically(import_node_path68.default.resolve(options.output), `${JSON.stringify(report, null, 2)}
|
|
30124
30286
|
`);
|
|
30125
30287
|
}
|
|
30126
30288
|
if (options.json) {
|
|
@@ -30167,14 +30329,14 @@ function printProfilePlanSummary(report, output2) {
|
|
|
30167
30329
|
process.stdout.write(`Binding ${key}: ${renderValues(report.bindings[key] ?? [])}
|
|
30168
30330
|
`);
|
|
30169
30331
|
}
|
|
30170
|
-
if (output2) process.stdout.write(`Output: ${
|
|
30332
|
+
if (output2) process.stdout.write(`Output: ${import_node_path68.default.resolve(output2)}
|
|
30171
30333
|
`);
|
|
30172
30334
|
}
|
|
30173
|
-
var
|
|
30335
|
+
var import_node_path68;
|
|
30174
30336
|
var init_profile = __esm({
|
|
30175
30337
|
"src/commands/profile.ts"() {
|
|
30176
30338
|
"use strict";
|
|
30177
|
-
|
|
30339
|
+
import_node_path68 = __toESM(require("path"));
|
|
30178
30340
|
init_atomic_file();
|
|
30179
30341
|
init_output();
|
|
30180
30342
|
init_profile_plan();
|
|
@@ -30524,7 +30686,7 @@ function assertResourceGraph(resources) {
|
|
|
30524
30686
|
for (const id5 of Object.keys(resources).sort()) visit(id5);
|
|
30525
30687
|
}
|
|
30526
30688
|
function parsePreviewManifest(source) {
|
|
30527
|
-
const document = (0,
|
|
30689
|
+
const document = (0, import_yaml10.parseDocument)(source, {
|
|
30528
30690
|
merge: false,
|
|
30529
30691
|
schema: "core",
|
|
30530
30692
|
uniqueKeys: true
|
|
@@ -30557,11 +30719,11 @@ function parsePreviewManifest(source) {
|
|
|
30557
30719
|
return { version: 1, aliases, bindings: bindings2, resources, selection };
|
|
30558
30720
|
}
|
|
30559
30721
|
function loadPreviewManifest(repoPath) {
|
|
30560
|
-
const resolvedRepo =
|
|
30722
|
+
const resolvedRepo = import_node_path69.default.resolve(repoPath);
|
|
30561
30723
|
const manifestPath = assertPathWithinRepo(MANIFEST_FILE_NAME, resolvedRepo, "Preview manifest");
|
|
30562
30724
|
let metadata;
|
|
30563
30725
|
try {
|
|
30564
|
-
metadata =
|
|
30726
|
+
metadata = import_node_fs55.default.lstatSync(manifestPath);
|
|
30565
30727
|
} catch (error) {
|
|
30566
30728
|
fail4(`could not inspect preview manifest '${MANIFEST_FILE_NAME}': ${error.message}`);
|
|
30567
30729
|
}
|
|
@@ -30571,26 +30733,26 @@ function loadPreviewManifest(repoPath) {
|
|
|
30571
30733
|
if (metadata.size > MAX_MANIFEST_BYTES) {
|
|
30572
30734
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30573
30735
|
}
|
|
30574
|
-
const realRepo =
|
|
30575
|
-
const realManifest =
|
|
30736
|
+
const realRepo = import_node_fs55.default.realpathSync(resolvedRepo);
|
|
30737
|
+
const realManifest = import_node_fs55.default.realpathSync(manifestPath);
|
|
30576
30738
|
assertPathWithinRepo(realManifest, realRepo, "Preview manifest");
|
|
30577
|
-
const source =
|
|
30739
|
+
const source = import_node_fs55.default.readFileSync(manifestPath, "utf-8");
|
|
30578
30740
|
if (Buffer.byteLength(source, "utf-8") > MAX_MANIFEST_BYTES) {
|
|
30579
30741
|
fail4(`preview manifest exceeds the ${MAX_MANIFEST_BYTES}-byte limit.`);
|
|
30580
30742
|
}
|
|
30581
30743
|
return {
|
|
30582
30744
|
manifest: parsePreviewManifest(source),
|
|
30583
|
-
digest: (0,
|
|
30745
|
+
digest: (0, import_node_crypto32.createHash)("sha256").update(source, "utf-8").digest("hex")
|
|
30584
30746
|
};
|
|
30585
30747
|
}
|
|
30586
|
-
var
|
|
30748
|
+
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
30749
|
var init_manifest = __esm({
|
|
30588
30750
|
"src/core/preview/manifest.ts"() {
|
|
30589
30751
|
"use strict";
|
|
30590
|
-
|
|
30591
|
-
|
|
30592
|
-
|
|
30593
|
-
|
|
30752
|
+
import_node_crypto32 = require("crypto");
|
|
30753
|
+
import_node_fs55 = __toESM(require("fs"));
|
|
30754
|
+
import_node_path69 = __toESM(require("path"));
|
|
30755
|
+
import_yaml10 = require("yaml");
|
|
30594
30756
|
init_paths();
|
|
30595
30757
|
MANIFEST_FILE_NAME = ".devrouter.preview.yml";
|
|
30596
30758
|
MAX_MANIFEST_BYTES = 1024 * 1024;
|
|
@@ -31385,7 +31547,7 @@ function createPreviewPool(installationId) {
|
|
|
31385
31547
|
processedCommands: []
|
|
31386
31548
|
});
|
|
31387
31549
|
}
|
|
31388
|
-
function
|
|
31550
|
+
function object5(value, required, optional = []) {
|
|
31389
31551
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
31390
31552
|
throw new Error("Invalid preview state object.");
|
|
31391
31553
|
const record6 = value;
|
|
@@ -31412,7 +31574,7 @@ function oneOf3(value, allowed) {
|
|
|
31412
31574
|
if (!allowed.includes(value)) throw new Error("Invalid preview state enum.");
|
|
31413
31575
|
}
|
|
31414
31576
|
function decodeSession(value) {
|
|
31415
|
-
const row =
|
|
31577
|
+
const row = object5(
|
|
31416
31578
|
value,
|
|
31417
31579
|
[
|
|
31418
31580
|
"generation",
|
|
@@ -31463,7 +31625,7 @@ function decodeSession(value) {
|
|
|
31463
31625
|
if (row.stopReason !== void 0)
|
|
31464
31626
|
oneOf3(row.stopReason, ["stop", "closed", "expiry", "setup-timeout"]);
|
|
31465
31627
|
if (row.pendingDeadline !== void 0) {
|
|
31466
|
-
const pending =
|
|
31628
|
+
const pending = object5(row.pendingDeadline, ["target", "commandId"]);
|
|
31467
31629
|
integer(pending.target);
|
|
31468
31630
|
text4(pending.commandId);
|
|
31469
31631
|
}
|
|
@@ -31491,7 +31653,7 @@ function decodeSession(value) {
|
|
|
31491
31653
|
return session;
|
|
31492
31654
|
}
|
|
31493
31655
|
function decodePlan(value) {
|
|
31494
|
-
const row =
|
|
31656
|
+
const row = object5(
|
|
31495
31657
|
value,
|
|
31496
31658
|
[
|
|
31497
31659
|
"schemaVersion",
|
|
@@ -31520,7 +31682,7 @@ function decodePlan(value) {
|
|
|
31520
31682
|
if (!/^[a-f0-9]{64}$/.test(row[key]))
|
|
31521
31683
|
throw new Error("Invalid preview config digest.");
|
|
31522
31684
|
}
|
|
31523
|
-
const source =
|
|
31685
|
+
const source = object5(row.source, ["head", "target", "mergeBase", "complete", "changes"]);
|
|
31524
31686
|
for (const key of ["head", "target", "mergeBase"]) {
|
|
31525
31687
|
text4(source[key], 64);
|
|
31526
31688
|
if (!/^(?:[a-f0-9]{40}|[a-f0-9]{64})$/.test(source[key]))
|
|
@@ -31529,7 +31691,7 @@ function decodePlan(value) {
|
|
|
31529
31691
|
if (source.complete !== true || !Array.isArray(source.changes) || source.changes.length > 1e4)
|
|
31530
31692
|
throw new Error("Incomplete stored preview source.");
|
|
31531
31693
|
for (const change of source.changes) {
|
|
31532
|
-
const item =
|
|
31694
|
+
const item = object5(change, ["status", "path"], ["oldPath"]);
|
|
31533
31695
|
oneOf3(item.status, ["A", "M", "D", "R", "C", "T"]);
|
|
31534
31696
|
for (const key of ["path", ...item.oldPath === void 0 ? [] : ["oldPath"]]) {
|
|
31535
31697
|
text4(item[key], 4096);
|
|
@@ -31543,7 +31705,7 @@ function decodePlan(value) {
|
|
|
31543
31705
|
throw new Error("Invalid stored preview graph.");
|
|
31544
31706
|
const resources = {};
|
|
31545
31707
|
for (const resource of row.resources) {
|
|
31546
|
-
const item =
|
|
31708
|
+
const item = object5(
|
|
31547
31709
|
resource,
|
|
31548
31710
|
["id", "kind"],
|
|
31549
31711
|
["dependsOn", "image", "imageTarget", "build", "ports", "command"]
|
|
@@ -31559,7 +31721,7 @@ function decodePlan(value) {
|
|
|
31559
31721
|
if (!aliases.length || row.reasons.includes("source-unbound"))
|
|
31560
31722
|
throw new Error("Unbound stored preview plan.");
|
|
31561
31723
|
parsePreviewManifest(
|
|
31562
|
-
(0,
|
|
31724
|
+
(0, import_yaml11.stringify)({
|
|
31563
31725
|
version: 1,
|
|
31564
31726
|
aliases: Object.fromEntries(
|
|
31565
31727
|
aliases.map((alias) => [alias, { resources: Object.keys(resources) }])
|
|
@@ -31574,7 +31736,7 @@ function decodePlan(value) {
|
|
|
31574
31736
|
function decodePreviewPool(value) {
|
|
31575
31737
|
if (Buffer.byteLength(JSON.stringify(value) ?? "") > 1024 * 1024)
|
|
31576
31738
|
throw new Error("Preview pool exceeds its bound.");
|
|
31577
|
-
const root =
|
|
31739
|
+
const root = object5(value, [
|
|
31578
31740
|
"schemaVersion",
|
|
31579
31741
|
"installationId",
|
|
31580
31742
|
"sessions",
|
|
@@ -31588,7 +31750,7 @@ function decodePreviewPool(value) {
|
|
|
31588
31750
|
throw new Error("Invalid preview command window.");
|
|
31589
31751
|
const receiptIds = /* @__PURE__ */ new Set();
|
|
31590
31752
|
for (const receipt of root.processedCommands) {
|
|
31591
|
-
const item =
|
|
31753
|
+
const item = object5(receipt, ["id", "admittedAt"]);
|
|
31592
31754
|
text4(item.id, 512);
|
|
31593
31755
|
integer(item.admittedAt);
|
|
31594
31756
|
if (receiptIds.has(item.id)) throw new Error("Duplicate preview command receipt.");
|
|
@@ -31599,7 +31761,7 @@ function decodePreviewPool(value) {
|
|
|
31599
31761
|
throw new Error("Invalid preview stop fence window.");
|
|
31600
31762
|
for (const [key, raw] of Object.entries(fences)) {
|
|
31601
31763
|
if (!/^[a-f0-9]{64}$/.test(key)) throw new Error("Invalid stop fence identity.");
|
|
31602
|
-
const fence =
|
|
31764
|
+
const fence = object5(raw, ["createdAt", "recordedAt", "commandId"]);
|
|
31603
31765
|
text4(fence.commandId, 128);
|
|
31604
31766
|
integer(fence.createdAt);
|
|
31605
31767
|
integer(fence.recordedAt);
|
|
@@ -31609,7 +31771,7 @@ function decodePreviewPool(value) {
|
|
|
31609
31771
|
throw new Error("Preview pool session bound exceeded.");
|
|
31610
31772
|
for (const [id5, value2] of Object.entries(sessions)) {
|
|
31611
31773
|
if (!/^[a-f0-9]{64}$/.test(id5)) throw new Error("Invalid preview identity key.");
|
|
31612
|
-
const entry =
|
|
31774
|
+
const entry = object5(
|
|
31613
31775
|
value2,
|
|
31614
31776
|
["session", "plan", "reservedCents", "hourlyCents", "operations", "effectSequence"],
|
|
31615
31777
|
[
|
|
@@ -31623,7 +31785,7 @@ function decodePreviewPool(value) {
|
|
|
31623
31785
|
]
|
|
31624
31786
|
);
|
|
31625
31787
|
if (entry.identity !== void 0) {
|
|
31626
|
-
const identity2 =
|
|
31788
|
+
const identity2 = object5(entry.identity, ["forgeHost", "projectId", "change"]);
|
|
31627
31789
|
text4(identity2.forgeHost, 253);
|
|
31628
31790
|
text4(identity2.projectId, 128);
|
|
31629
31791
|
integer(identity2.change, 1);
|
|
@@ -31649,7 +31811,7 @@ function decodePreviewPool(value) {
|
|
|
31649
31811
|
if (!entry.operations || typeof entry.operations !== "object" || Array.isArray(entry.operations) || Object.keys(entry.operations).length > 1024)
|
|
31650
31812
|
throw new Error("Invalid preview operation registry.");
|
|
31651
31813
|
for (const [operationId, raw] of Object.entries(entry.operations)) {
|
|
31652
|
-
const effect2 =
|
|
31814
|
+
const effect2 = object5(
|
|
31653
31815
|
raw,
|
|
31654
31816
|
[
|
|
31655
31817
|
"id",
|
|
@@ -31687,7 +31849,7 @@ function decodePreviewPool(value) {
|
|
|
31687
31849
|
throw new Error("Preview provider step journal exceeds its bound.");
|
|
31688
31850
|
const names = /* @__PURE__ */ new Set();
|
|
31689
31851
|
for (const rawStep of effect2.steps) {
|
|
31690
|
-
const step =
|
|
31852
|
+
const step = object5(rawStep, ["name", "mode", "state", "at"], ["ref", "fingerprint"]);
|
|
31691
31853
|
text4(step.name, 64);
|
|
31692
31854
|
if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(step.name) || names.has(step.name))
|
|
31693
31855
|
throw new Error("Invalid preview provider step identity.");
|
|
@@ -31713,11 +31875,11 @@ function decodePreviewPool(value) {
|
|
|
31713
31875
|
}
|
|
31714
31876
|
return structuredClone(root);
|
|
31715
31877
|
}
|
|
31716
|
-
var
|
|
31878
|
+
var import_yaml11, PreviewStateConflict;
|
|
31717
31879
|
var init_state = __esm({
|
|
31718
31880
|
"src/core/preview/state.ts"() {
|
|
31719
31881
|
"use strict";
|
|
31720
|
-
|
|
31882
|
+
import_yaml11 = require("yaml");
|
|
31721
31883
|
init_manifest();
|
|
31722
31884
|
PreviewStateConflict = class extends Error {
|
|
31723
31885
|
constructor() {
|
|
@@ -31732,7 +31894,7 @@ var init_state = __esm({
|
|
|
31732
31894
|
function previewIdentityKey(identity2) {
|
|
31733
31895
|
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
31896
|
throw new Error("Invalid immutable preview identity.");
|
|
31735
|
-
return (0,
|
|
31897
|
+
return (0, import_node_crypto33.createHash)("sha256").update(JSON.stringify([identity2.forgeHost, identity2.projectId, identity2.change])).digest("hex");
|
|
31736
31898
|
}
|
|
31737
31899
|
function costs(pool) {
|
|
31738
31900
|
return Object.values(pool.sessions).reduce((total, entry) => total + entry.reservedCents, 0);
|
|
@@ -31788,11 +31950,11 @@ function sessionReady(entry, now, expiresAt) {
|
|
|
31788
31950
|
...expiresAt === void 0 ? {} : { expiresAt }
|
|
31789
31951
|
});
|
|
31790
31952
|
}
|
|
31791
|
-
var
|
|
31953
|
+
var import_node_crypto33, PreviewAdmissionSuperseded, PreviewEngine;
|
|
31792
31954
|
var init_engine = __esm({
|
|
31793
31955
|
"src/core/preview/engine.ts"() {
|
|
31794
31956
|
"use strict";
|
|
31795
|
-
|
|
31957
|
+
import_node_crypto33 = require("crypto");
|
|
31796
31958
|
init_command();
|
|
31797
31959
|
init_lifecycle();
|
|
31798
31960
|
init_state();
|
|
@@ -31926,7 +32088,7 @@ var init_engine = __esm({
|
|
|
31926
32088
|
} else {
|
|
31927
32089
|
if (current && current.session.status !== "stopped" && current.session.status !== "expired")
|
|
31928
32090
|
throw new Error("Previous generation cleanup is incomplete.");
|
|
31929
|
-
const generation = (0,
|
|
32091
|
+
const generation = (0, import_node_crypto33.createHash)("sha256").update(receipt).digest("hex").slice(0, 24);
|
|
31930
32092
|
pool2.sessions[id5] = {
|
|
31931
32093
|
identity: input2.identity,
|
|
31932
32094
|
session: createPreviewSession({
|
|
@@ -32459,10 +32621,10 @@ var init_status3 = __esm({
|
|
|
32459
32621
|
throw new Error("Forge requires a trusted HTTPS API base.");
|
|
32460
32622
|
}
|
|
32461
32623
|
base;
|
|
32462
|
-
async request(method,
|
|
32463
|
-
if (!
|
|
32624
|
+
async request(method, path80, body, maxBytes) {
|
|
32625
|
+
if (!path80 || path80.startsWith("/") || path80.split("?")[0].split("/").some((part) => [".", ".."].includes(decodeURIComponent(part))) || path80.includes("\\") || path80.includes("#"))
|
|
32464
32626
|
throw new Error("Invalid forge API path.");
|
|
32465
|
-
const url = new URL(
|
|
32627
|
+
const url = new URL(path80, this.base);
|
|
32466
32628
|
if (url.origin !== this.base.origin || !url.pathname.startsWith(this.base.pathname))
|
|
32467
32629
|
throw new Error("Forge request escaped its configured API.");
|
|
32468
32630
|
let token;
|
|
@@ -32502,13 +32664,13 @@ var init_status3 = __esm({
|
|
|
32502
32664
|
throw new Error("Preview forge response is unreadable or exceeds its bound.");
|
|
32503
32665
|
}
|
|
32504
32666
|
}
|
|
32505
|
-
async pages(
|
|
32667
|
+
async pages(path80, options = {}) {
|
|
32506
32668
|
const rows2 = [];
|
|
32507
32669
|
for (let page = 1; page <= 100; page++) {
|
|
32508
|
-
const separator =
|
|
32670
|
+
const separator = path80.includes("?") ? "&" : "?";
|
|
32509
32671
|
const result = await this.request(
|
|
32510
32672
|
"GET",
|
|
32511
|
-
`${
|
|
32673
|
+
`${path80}${separator}per_page=100&page=${page}`,
|
|
32512
32674
|
void 0,
|
|
32513
32675
|
options.maxBytes
|
|
32514
32676
|
);
|
|
@@ -32534,14 +32696,14 @@ var init_status3 = __esm({
|
|
|
32534
32696
|
|
|
32535
32697
|
// src/core/preview/controller.ts
|
|
32536
32698
|
function decodeInbox(raw) {
|
|
32537
|
-
const row =
|
|
32699
|
+
const row = object5(
|
|
32538
32700
|
raw,
|
|
32539
32701
|
["schemaVersion", "identity", "scannedThrough", "closedThrough", "processed"],
|
|
32540
32702
|
["status", "selection", "needsStatus", "refusal"]
|
|
32541
32703
|
);
|
|
32542
32704
|
if (row.schemaVersion !== 1 || Buffer.byteLength(JSON.stringify(raw)) > 128 * 1024)
|
|
32543
32705
|
throw new Error("Invalid preview inbox.");
|
|
32544
|
-
const identity2 =
|
|
32706
|
+
const identity2 = object5(row.identity, ["forgeHost", "projectId", "change"]);
|
|
32545
32707
|
previewIdentityKey(identity2);
|
|
32546
32708
|
for (const key of ["scannedThrough", "closedThrough"])
|
|
32547
32709
|
if (!Number.isSafeInteger(row[key]) || row[key] < 0)
|
|
@@ -32550,7 +32712,7 @@ function decodeInbox(raw) {
|
|
|
32550
32712
|
throw new Error("Preview inbox exceeds its command bound.");
|
|
32551
32713
|
const ids2 = /* @__PURE__ */ new Set();
|
|
32552
32714
|
for (const item of row.processed) {
|
|
32553
|
-
const receipt =
|
|
32715
|
+
const receipt = object5(item, ["id", "at"]);
|
|
32554
32716
|
forgeId(receipt.id);
|
|
32555
32717
|
if (ids2.has(receipt.id) || !Number.isSafeInteger(receipt.at) || receipt.at < 0)
|
|
32556
32718
|
throw new Error("Invalid preview inbox receipt.");
|
|
@@ -32565,7 +32727,7 @@ function decodeInbox(raw) {
|
|
|
32565
32727
|
if (row.refusal !== void 0 && !previewRefusalReasons.includes(row.refusal))
|
|
32566
32728
|
throw new Error("Invalid preview refusal outcome.");
|
|
32567
32729
|
if (row.status) {
|
|
32568
|
-
const status =
|
|
32730
|
+
const status = object5(
|
|
32569
32731
|
row.status,
|
|
32570
32732
|
["intentAt"],
|
|
32571
32733
|
["commentId", "bodyDigest", "publishedAt", "intentId"]
|
|
@@ -32582,11 +32744,11 @@ function decodeInbox(raw) {
|
|
|
32582
32744
|
}
|
|
32583
32745
|
return structuredClone(row);
|
|
32584
32746
|
}
|
|
32585
|
-
var
|
|
32747
|
+
var import_node_crypto34, PreviewController;
|
|
32586
32748
|
var init_controller2 = __esm({
|
|
32587
32749
|
"src/core/preview/controller.ts"() {
|
|
32588
32750
|
"use strict";
|
|
32589
|
-
|
|
32751
|
+
import_node_crypto34 = require("crypto");
|
|
32590
32752
|
init_command();
|
|
32591
32753
|
init_engine();
|
|
32592
32754
|
init_status3();
|
|
@@ -32793,7 +32955,7 @@ Command refused: ${inbox.refusal}. Post a new command when the condition is reso
|
|
|
32793
32955
|
Available profiles: ${this.options.aliases.map((alias) => `\`${alias}\``).join(", ")}.` : ""}
|
|
32794
32956
|
|
|
32795
32957
|
${marker}`;
|
|
32796
|
-
const fingerprint = (0,
|
|
32958
|
+
const fingerprint = (0, import_node_crypto34.createHash)("sha256").update(body).digest("hex"), now = this.options.now();
|
|
32797
32959
|
if (inbox.status?.bodyDigest === fingerprint) {
|
|
32798
32960
|
if (inbox.needsStatus) await this.update(change, (row) => ({ ...row, needsStatus: false }));
|
|
32799
32961
|
return;
|
|
@@ -32804,7 +32966,7 @@ ${marker}`;
|
|
|
32804
32966
|
let commentId = inbox.status?.commentId;
|
|
32805
32967
|
if (!commentId) commentId = await this.options.forge.findStatus(change, marker) ?? void 0;
|
|
32806
32968
|
let create = false;
|
|
32807
|
-
const intentId = (0,
|
|
32969
|
+
const intentId = (0, import_node_crypto34.randomUUID)();
|
|
32808
32970
|
if (!inbox.status)
|
|
32809
32971
|
inbox = await this.update(change, (row) => {
|
|
32810
32972
|
create = !row.status;
|
|
@@ -33140,11 +33302,11 @@ var init_github = __esm({
|
|
|
33140
33302
|
throw new Error("Preview status has no ownership marker.");
|
|
33141
33303
|
if (Buffer.byteLength(body) > 32 * 1024) throw new Error("Preview status exceeds its bound.");
|
|
33142
33304
|
if (previousId) {
|
|
33143
|
-
const
|
|
33144
|
-
const comment = forgeObject((await this.http.request("GET",
|
|
33305
|
+
const path80 = `${this.repo}/issues/comments/${forgeId(previousId)}`;
|
|
33306
|
+
const comment = forgeObject((await this.http.request("GET", path80)).data);
|
|
33145
33307
|
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
33308
|
throw new Error("Preview status comment ownership differs.");
|
|
33147
|
-
await this.http.request("PATCH",
|
|
33309
|
+
await this.http.request("PATCH", path80, { body });
|
|
33148
33310
|
return previousId;
|
|
33149
33311
|
}
|
|
33150
33312
|
const created = forgeObject(
|
|
@@ -33320,11 +33482,11 @@ var init_gitlab = __esm({
|
|
|
33320
33482
|
const row = forgeObject(raw);
|
|
33321
33483
|
if (row.collapsed !== false || row.too_large !== false || ["new_file", "deleted_file", "renamed_file"].some((key) => typeof row[key] !== "boolean"))
|
|
33322
33484
|
throw new Error("GitLab file diff is incomplete.");
|
|
33323
|
-
const
|
|
33324
|
-
if (row.renamed_file) return { status: "R", path:
|
|
33485
|
+
const path80 = assertRepoRelativePath(row.new_path, "GitLab changed file"), oldPath = assertRepoRelativePath(row.old_path, "GitLab old file");
|
|
33486
|
+
if (row.renamed_file) return { status: "R", path: path80, oldPath };
|
|
33325
33487
|
return {
|
|
33326
33488
|
status: row.new_file ? "A" : row.deleted_file ? "D" : row.a_mode !== row.b_mode ? "T" : "M",
|
|
33327
|
-
path:
|
|
33489
|
+
path: path80
|
|
33328
33490
|
};
|
|
33329
33491
|
});
|
|
33330
33492
|
const current = await this.merge(change);
|
|
@@ -33554,7 +33716,7 @@ function canonicalizeImageConfiguration(configuration) {
|
|
|
33554
33716
|
return JSON.stringify(normalizeConfiguration(configuration, "image configuration"));
|
|
33555
33717
|
}
|
|
33556
33718
|
function imageConfigurationDigest(configuration) {
|
|
33557
|
-
return `sha256:${(0,
|
|
33719
|
+
return `sha256:${(0, import_node_crypto35.createHash)("sha256").update(canonicalizeImageConfiguration(configuration), "utf-8").digest("hex")}`;
|
|
33558
33720
|
}
|
|
33559
33721
|
function targetKey(target, configurationDigest) {
|
|
33560
33722
|
return `${target}\0${configurationDigest}`;
|
|
@@ -33809,11 +33971,11 @@ function resolvePreviewImages(plan, prepared, expectedProducer, value) {
|
|
|
33809
33971
|
images: Object.fromEntries(resourceReceipts)
|
|
33810
33972
|
};
|
|
33811
33973
|
}
|
|
33812
|
-
var
|
|
33974
|
+
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
33975
|
var init_images = __esm({
|
|
33814
33976
|
"src/core/preview/images.ts"() {
|
|
33815
33977
|
"use strict";
|
|
33816
|
-
|
|
33978
|
+
import_node_crypto35 = require("crypto");
|
|
33817
33979
|
MAX_COLLECTION_ENTRIES2 = 256;
|
|
33818
33980
|
MAX_CONFIGURATION_ENTRIES = 128;
|
|
33819
33981
|
MAX_CONFIGURATION_KEY_LENGTH = 128;
|
|
@@ -33847,8 +34009,8 @@ function commandImageBackend(options) {
|
|
|
33847
34009
|
throw new Error("Invalid installed image resolver command.");
|
|
33848
34010
|
const verify = () => {
|
|
33849
34011
|
for (const file of options.files) {
|
|
33850
|
-
const stat =
|
|
33851
|
-
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0,
|
|
34012
|
+
const stat = import_node_fs56.default.lstatSync(file.path);
|
|
34013
|
+
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
34014
|
throw new Error("Installed image resolver fingerprint differs.");
|
|
33853
34015
|
}
|
|
33854
34016
|
};
|
|
@@ -33860,7 +34022,7 @@ function commandImageBackend(options) {
|
|
|
33860
34022
|
platform: options.platform,
|
|
33861
34023
|
configurations: options.context(entry)
|
|
33862
34024
|
});
|
|
33863
|
-
const correlation = (0,
|
|
34025
|
+
const correlation = (0, import_node_crypto36.createHash)("sha256").update(
|
|
33864
34026
|
JSON.stringify([
|
|
33865
34027
|
entry.identity,
|
|
33866
34028
|
entry.session.generation,
|
|
@@ -33884,7 +34046,7 @@ function commandImageBackend(options) {
|
|
|
33884
34046
|
});
|
|
33885
34047
|
if (Buffer.byteLength(input2) > 1024 * 1024)
|
|
33886
34048
|
throw new Error("Image request exceeds its bound.");
|
|
33887
|
-
const result = (0,
|
|
34049
|
+
const result = (0, import_node_child_process42.spawnSync)(options.command[0], options.command.slice(1), {
|
|
33888
34050
|
shell: false,
|
|
33889
34051
|
cwd: options.cwd,
|
|
33890
34052
|
encoding: "utf8",
|
|
@@ -33897,7 +34059,7 @@ function commandImageBackend(options) {
|
|
|
33897
34059
|
throw new Error("Installed image resolver failed; output suppressed.");
|
|
33898
34060
|
return JSON.parse(result.stdout);
|
|
33899
34061
|
};
|
|
33900
|
-
const resolved2 =
|
|
34062
|
+
const resolved2 = object5(invoke("resolve"), ["receipts"], ["pending"]);
|
|
33901
34063
|
const outcome = resolvePreviewImages(entry.plan, prepared, options.producer, {
|
|
33902
34064
|
receipts: resolved2.receipts
|
|
33903
34065
|
});
|
|
@@ -33922,13 +34084,13 @@ function commandImageBackend(options) {
|
|
|
33922
34084
|
}
|
|
33923
34085
|
};
|
|
33924
34086
|
}
|
|
33925
|
-
var
|
|
34087
|
+
var import_node_child_process42, import_node_crypto36, import_node_fs56;
|
|
33926
34088
|
var init_image_command = __esm({
|
|
33927
34089
|
"src/core/preview/image-command.ts"() {
|
|
33928
34090
|
"use strict";
|
|
33929
|
-
|
|
33930
|
-
|
|
33931
|
-
|
|
34091
|
+
import_node_child_process42 = require("child_process");
|
|
34092
|
+
import_node_crypto36 = require("crypto");
|
|
34093
|
+
import_node_fs56 = __toESM(require("fs"));
|
|
33932
34094
|
init_images();
|
|
33933
34095
|
init_state();
|
|
33934
34096
|
}
|
|
@@ -34621,9 +34783,9 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
34621
34783
|
const resource = resources.get(id5);
|
|
34622
34784
|
if (!resource?.ports?.some((item) => item.name === port && item.public))
|
|
34623
34785
|
throw new Error("Northflank origin binding requires a selected public port.");
|
|
34624
|
-
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0,
|
|
34786
|
+
return `https://${prefix}--${id5.slice(0, 16)}-${port}-${(0, import_node_crypto37.createHash)("sha256").update(id5).digest("hex").slice(0, 6)}.${policy.baseDomain}`;
|
|
34625
34787
|
};
|
|
34626
|
-
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0,
|
|
34788
|
+
const resourceName = (id5) => `${northflankAllocationPrefix(policy, entry.session.generation)}${(0, import_node_crypto37.createHash)("sha256").update(id5).digest("hex").slice(0, 10)}`;
|
|
34627
34789
|
const suffix = (value) => {
|
|
34628
34790
|
if (value === void 0) return "";
|
|
34629
34791
|
if (typeof value !== "string" || value.length > 1024 || !value.startsWith("/") || value.startsWith("//") || value.includes("\\") || new RegExp("\\s|\\p{Cc}", "u").test(value))
|
|
@@ -35050,7 +35212,7 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35050
35212
|
]
|
|
35051
35213
|
}
|
|
35052
35214
|
};
|
|
35053
|
-
const digest5 = (0,
|
|
35215
|
+
const digest5 = (0, import_node_crypto37.createHash)("sha256").update(JSON.stringify({ spec, runtimeSecrets })).digest("hex");
|
|
35054
35216
|
return {
|
|
35055
35217
|
spec,
|
|
35056
35218
|
digest: digest5,
|
|
@@ -35061,11 +35223,11 @@ function compileNorthflankGraph(entry, policy, phase, owned = {
|
|
|
35061
35223
|
publicBuildEnvironment
|
|
35062
35224
|
};
|
|
35063
35225
|
}
|
|
35064
|
-
var
|
|
35226
|
+
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
35227
|
var init_northflank_graph = __esm({
|
|
35066
35228
|
"src/core/preview/providers/northflank-graph.ts"() {
|
|
35067
35229
|
"use strict";
|
|
35068
|
-
|
|
35230
|
+
import_node_crypto37 = require("crypto");
|
|
35069
35231
|
import_node_net5 = require("net");
|
|
35070
35232
|
ALLOCATION_PLAN = /^[a-zA-Z0-9-]{3,100}$/;
|
|
35071
35233
|
DATABASE_NAME = /^[a-z][a-z0-9_]{0,62}$/;
|
|
@@ -35090,7 +35252,7 @@ function identifier(value) {
|
|
|
35090
35252
|
function decodeNorthflankOwnership(value) {
|
|
35091
35253
|
if (Buffer.byteLength(JSON.stringify(value) ?? "") > 128 * 1024)
|
|
35092
35254
|
throw new Error("Northflank ownership exceeds its bound.");
|
|
35093
|
-
const row =
|
|
35255
|
+
const row = object5(
|
|
35094
35256
|
value,
|
|
35095
35257
|
["schemaVersion", "generation", "policyDigest", "resources", "absent"],
|
|
35096
35258
|
[
|
|
@@ -35119,7 +35281,7 @@ function decodeNorthflankOwnership(value) {
|
|
|
35119
35281
|
)))
|
|
35120
35282
|
throw new Error("Invalid Northflank completed-job metadata.");
|
|
35121
35283
|
if (row.apiWait !== void 0) {
|
|
35122
|
-
const wait =
|
|
35284
|
+
const wait = object5(row.apiWait, ["until", "exhausted"]);
|
|
35123
35285
|
if (!Number.isSafeInteger(wait.until) || wait.until < 1 || typeof wait.exhausted !== "boolean")
|
|
35124
35286
|
throw new Error("Invalid Northflank API wait metadata.");
|
|
35125
35287
|
}
|
|
@@ -35128,7 +35290,7 @@ function decodeNorthflankOwnership(value) {
|
|
|
35128
35290
|
const references = /* @__PURE__ */ new Set();
|
|
35129
35291
|
const ids2 = /* @__PURE__ */ new Set();
|
|
35130
35292
|
for (const raw of row.resources) {
|
|
35131
|
-
const resource =
|
|
35293
|
+
const resource = object5(raw, ["reference", "kind", "id", "name"], ["uid"]);
|
|
35132
35294
|
identifier(resource.id);
|
|
35133
35295
|
identifier(resource.reference);
|
|
35134
35296
|
identifier(resource.name);
|
|
@@ -35169,7 +35331,7 @@ function specDigest(value) {
|
|
|
35169
35331
|
return digest3(definition(value));
|
|
35170
35332
|
}
|
|
35171
35333
|
function digest3(value) {
|
|
35172
|
-
return (0,
|
|
35334
|
+
return (0, import_node_crypto38.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
|
|
35173
35335
|
}
|
|
35174
35336
|
function bindings(owned) {
|
|
35175
35337
|
return {
|
|
@@ -35194,11 +35356,11 @@ function outputNames(graph) {
|
|
|
35194
35356
|
)
|
|
35195
35357
|
].sort();
|
|
35196
35358
|
}
|
|
35197
|
-
var
|
|
35359
|
+
var import_node_crypto38, resourceKinds, NorthflankOwnershipStore, northflankQualificationKeys, NorthflankFailure, NorthflankFenced, NorthflankPreviewProvider, nativeKinds, emptySpec;
|
|
35198
35360
|
var init_northflank = __esm({
|
|
35199
35361
|
"src/core/preview/providers/northflank.ts"() {
|
|
35200
35362
|
"use strict";
|
|
35201
|
-
|
|
35363
|
+
import_node_crypto38 = require("crypto");
|
|
35202
35364
|
init_command();
|
|
35203
35365
|
init_state();
|
|
35204
35366
|
init_northflank_api();
|
|
@@ -35831,7 +35993,7 @@ var init_northflank = __esm({
|
|
|
35831
35993
|
const settings = this.options.graph.generated?.[name];
|
|
35832
35994
|
if (!settings)
|
|
35833
35995
|
throw new NorthflankFailure("Northflank generated value is undeclared.");
|
|
35834
|
-
value = (0,
|
|
35996
|
+
value = (0, import_node_crypto38.randomBytes)(settings.bytes).toString(settings.encoding);
|
|
35835
35997
|
}
|
|
35836
35998
|
if (kind === "output" && value === void 0)
|
|
35837
35999
|
throw new NorthflankFailure("Northflank output has no verified recipient.");
|
|
@@ -35908,10 +36070,10 @@ var init_northflank = __esm({
|
|
|
35908
36070
|
for (const step of steps.filter((item) => item.name.endsWith("-run"))) {
|
|
35909
36071
|
if (!owned.blueprintId) return this.receipt(owned);
|
|
35910
36072
|
const operation = `${step.name.slice(0, -4)}-${digest3(effect2.id).slice(0, 20)}`;
|
|
35911
|
-
const
|
|
35912
|
-
const id5 = step.ref ?? await this.findRun(
|
|
36073
|
+
const path80 = ["preview-blueprints", owned.blueprintId];
|
|
36074
|
+
const id5 = step.ref ?? await this.findRun(path80, operation);
|
|
35913
36075
|
if (!id5) return this.receipt(owned);
|
|
35914
|
-
const result = await this.options.api.request("GET", [...
|
|
36076
|
+
const result = await this.options.api.request("GET", [...path80, "runs", id5]);
|
|
35915
36077
|
if (!result) return this.receipt(owned);
|
|
35916
36078
|
const run = data(result);
|
|
35917
36079
|
if (!run.concluded || specDigest(run.spec) !== step.fingerprint || northflankRecord(run.arguments).devrouterOperation !== operation || run.environmentId !== (owned.previewId ?? `preview-${entry.session.generation}`))
|
|
@@ -35934,11 +36096,11 @@ var init_northflank = __esm({
|
|
|
35934
36096
|
}
|
|
35935
36097
|
};
|
|
35936
36098
|
}
|
|
35937
|
-
async findRun(
|
|
36099
|
+
async findRun(path80, operation) {
|
|
35938
36100
|
let match;
|
|
35939
|
-
for (const summary of await this.options.api.list([...
|
|
36101
|
+
for (const summary of await this.options.api.list([...path80, "runs"], "runs")) {
|
|
35940
36102
|
const id5 = northflankIdentifier(summary.id);
|
|
35941
|
-
const candidate = data(await this.options.api.request("GET", [...
|
|
36103
|
+
const candidate = data(await this.options.api.request("GET", [...path80, "runs", id5]));
|
|
35942
36104
|
if (northflankRecord(candidate.arguments ?? {}).devrouterOperation !== operation) continue;
|
|
35943
36105
|
if (match) throw new NorthflankFailure("Ambiguous Northflank run outcome.");
|
|
35944
36106
|
match = id5;
|
|
@@ -35947,13 +36109,13 @@ var init_northflank = __esm({
|
|
|
35947
36109
|
}
|
|
35948
36110
|
async run(entry, effect2, gate, owned, stage, spec) {
|
|
35949
36111
|
const api = this.options.api;
|
|
35950
|
-
const
|
|
36112
|
+
const path80 = ["preview-blueprints", northflankIdentifier(owned.blueprintId)];
|
|
35951
36113
|
let fingerprint = specDigest(spec);
|
|
35952
36114
|
const operation = `${stage}-${digest3(effect2.id).slice(0, 20)}`;
|
|
35953
36115
|
const recorded = (await gate.read()).find((step2) => step2.name === `${stage}-run`);
|
|
35954
36116
|
if (!recorded) {
|
|
35955
36117
|
if (await begin(gate, `${stage}-spec`, "once", fingerprint) === "write") {
|
|
35956
|
-
await api.request("POST",
|
|
36118
|
+
await api.request("POST", path80, {
|
|
35957
36119
|
name: this.name(entry),
|
|
35958
36120
|
apiVersion: "v1.2",
|
|
35959
36121
|
spec,
|
|
@@ -35962,14 +36124,14 @@ var init_northflank = __esm({
|
|
|
35962
36124
|
});
|
|
35963
36125
|
await gate.record(`${stage}-spec`, "accepted");
|
|
35964
36126
|
}
|
|
35965
|
-
const detail = data(await api.request("GET",
|
|
36127
|
+
const detail = data(await api.request("GET", path80));
|
|
35966
36128
|
if (specDigest(detail.spec) !== fingerprint)
|
|
35967
36129
|
throw new NorthflankFailure("Northflank blueprint specification drifted.");
|
|
35968
36130
|
await gate.record(`${stage}-spec`, "accepted");
|
|
35969
36131
|
if (await begin(gate, `${stage}-run`, "once", fingerprint) === "write") {
|
|
35970
36132
|
try {
|
|
35971
36133
|
const run2 = data(
|
|
35972
|
-
await api.request("POST", [...
|
|
36134
|
+
await api.request("POST", [...path80, "runs"], {
|
|
35973
36135
|
name: owned.previewId ?? `preview-${entry.session.generation}`,
|
|
35974
36136
|
arguments: { devrouterOperation: operation }
|
|
35975
36137
|
})
|
|
@@ -35990,15 +36152,15 @@ var init_northflank = __esm({
|
|
|
35990
36152
|
if (!step) return null;
|
|
35991
36153
|
let id5 = step.ref;
|
|
35992
36154
|
if (!id5) {
|
|
35993
|
-
id5 = await this.findRun(
|
|
36155
|
+
id5 = await this.findRun(path80, operation);
|
|
35994
36156
|
if (!id5) return null;
|
|
35995
36157
|
await gate.record(`${stage}-run`, "accepted", id5);
|
|
35996
36158
|
}
|
|
35997
|
-
const run = data(await api.request("GET", [...
|
|
36159
|
+
const run = data(await api.request("GET", [...path80, "runs", id5]));
|
|
35998
36160
|
if (specDigest(run.spec) !== fingerprint || northflankRecord(run.arguments).devrouterOperation !== operation || run.environmentId !== (owned.previewId ?? `preview-${entry.session.generation}`))
|
|
35999
36161
|
throw new NorthflankFailure("Northflank executed an unexpected specification or operation.");
|
|
36000
36162
|
if (owned.previewId) {
|
|
36001
|
-
const previews = await api.list([...
|
|
36163
|
+
const previews = await api.list([...path80, "previews"], "previewEnvironments");
|
|
36002
36164
|
if (previews.length !== 1 || previews[0].id !== owned.previewId)
|
|
36003
36165
|
throw new NorthflankFailure("Northflank run changed the generation environment.");
|
|
36004
36166
|
}
|
|
@@ -36073,33 +36235,33 @@ var init_northflank = __esm({
|
|
|
36073
36235
|
const candidates = await this.namedBlueprints(entry);
|
|
36074
36236
|
return this.receipt(owned, candidates.length === 0);
|
|
36075
36237
|
}
|
|
36076
|
-
const
|
|
36077
|
-
const blueprint = await this.options.api.request("GET",
|
|
36238
|
+
const path80 = ["preview-blueprints", owned.blueprintId];
|
|
36239
|
+
const blueprint = await this.options.api.request("GET", path80);
|
|
36078
36240
|
if (!blueprint && !owned.blueprintObserved && !owned.blueprintRejected)
|
|
36079
36241
|
return this.receipt(owned);
|
|
36080
36242
|
if (blueprint) {
|
|
36081
36243
|
if (!owned.blueprintObserved)
|
|
36082
36244
|
owned = await store.update((current) => ({ ...current, blueprintObserved: true }));
|
|
36083
|
-
const runs = await this.options.api.list([...
|
|
36245
|
+
const runs = await this.options.api.list([...path80, "runs"], "runs");
|
|
36084
36246
|
for (const run of runs.filter((row) => row.concluded !== true)) {
|
|
36085
36247
|
const id5 = northflankIdentifier(run.id);
|
|
36086
36248
|
const step = `abort-${digest3(id5).slice(0, 12)}`;
|
|
36087
36249
|
if (await begin(gate, step, "convergent") === "write") {
|
|
36088
|
-
await this.options.api.request("POST", [...
|
|
36250
|
+
await this.options.api.request("POST", [...path80, "runs", id5, "abort"]);
|
|
36089
36251
|
await gate.record(step, "accepted", id5);
|
|
36090
36252
|
}
|
|
36091
36253
|
}
|
|
36092
36254
|
if (effect2.kind === "cancel") return this.receipt(owned, true);
|
|
36093
|
-
const previews = await this.options.api.list([...
|
|
36255
|
+
const previews = await this.options.api.list([...path80, "previews"], "previewEnvironments");
|
|
36094
36256
|
for (const preview of previews) {
|
|
36095
36257
|
const id5 = northflankIdentifier(preview.id);
|
|
36096
36258
|
const step = `delete-${digest3(id5).slice(0, 12)}`;
|
|
36097
36259
|
if (await begin(gate, step, "convergent") === "write") {
|
|
36098
|
-
await this.options.api.request("DELETE", [...
|
|
36260
|
+
await this.options.api.request("DELETE", [...path80, "previews", id5]);
|
|
36099
36261
|
await gate.record(step, "accepted", id5);
|
|
36100
36262
|
}
|
|
36101
36263
|
}
|
|
36102
|
-
if ((await this.options.api.list([...
|
|
36264
|
+
if ((await this.options.api.list([...path80, "previews"], "previewEnvironments")).length)
|
|
36103
36265
|
return this.receipt(owned);
|
|
36104
36266
|
let cleanedDomains = 0;
|
|
36105
36267
|
for (const resource of owned.resources.filter((item) => item.kind === "domains")) {
|
|
@@ -36112,7 +36274,7 @@ var init_northflank = __esm({
|
|
|
36112
36274
|
}
|
|
36113
36275
|
}
|
|
36114
36276
|
if (await begin(gate, "delete-blueprint", "convergent") === "write") {
|
|
36115
|
-
await this.options.api.request("DELETE",
|
|
36277
|
+
await this.options.api.request("DELETE", path80);
|
|
36116
36278
|
await gate.record("delete-blueprint", "accepted");
|
|
36117
36279
|
}
|
|
36118
36280
|
}
|
|
@@ -36334,10 +36496,10 @@ __export(installation_exports, {
|
|
|
36334
36496
|
loadPreviewInstallation: () => loadPreviewInstallation
|
|
36335
36497
|
});
|
|
36336
36498
|
function readFile(file) {
|
|
36337
|
-
const stat =
|
|
36499
|
+
const stat = import_node_fs57.default.lstatSync(file);
|
|
36338
36500
|
if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024)
|
|
36339
36501
|
throw new Error("Preview control files must be regular files of at most 1 MiB.");
|
|
36340
|
-
return
|
|
36502
|
+
return import_node_fs57.default.readFileSync(file, "utf8");
|
|
36341
36503
|
}
|
|
36342
36504
|
function text5(value, pattern) {
|
|
36343
36505
|
if (typeof value !== "string" || !pattern.test(value))
|
|
@@ -36350,8 +36512,8 @@ function integer2(value, min, max) {
|
|
|
36350
36512
|
return value;
|
|
36351
36513
|
}
|
|
36352
36514
|
function loadPreviewInstallation(filename, options = {}) {
|
|
36353
|
-
const root =
|
|
36354
|
-
const raw =
|
|
36515
|
+
const root = import_node_path70.default.dirname(import_node_fs57.default.realpathSync(filename));
|
|
36516
|
+
const raw = object5(JSON.parse(readFile(filename)), [
|
|
36355
36517
|
"version",
|
|
36356
36518
|
"installationId",
|
|
36357
36519
|
"state",
|
|
@@ -36386,10 +36548,10 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36386
36548
|
return value;
|
|
36387
36549
|
};
|
|
36388
36550
|
};
|
|
36389
|
-
const statePolicy =
|
|
36551
|
+
const statePolicy = object5(raw.state, ["containerUrl"], ["tokenEnv", "federated"]);
|
|
36390
36552
|
if (statePolicy.tokenEnv === void 0 === (statePolicy.federated === void 0))
|
|
36391
36553
|
throw new Error("Preview state requires exactly one installed authentication method.");
|
|
36392
|
-
const federated = statePolicy.federated === void 0 ? void 0 :
|
|
36554
|
+
const federated = statePolicy.federated === void 0 ? void 0 : object5(statePolicy.federated, ["tenantIdEnv", "clientIdEnv", "assertionEnv"]);
|
|
36393
36555
|
const accessToken = federated ? azureFederatedPreviewToken({
|
|
36394
36556
|
tenantId: credential(federated.tenantIdEnv),
|
|
36395
36557
|
clientId: credential(federated.clientIdEnv),
|
|
@@ -36405,13 +36567,13 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36405
36567
|
if (!Array.isArray(raw.projects) || raw.projects.length < 1 || raw.projects.length > 16)
|
|
36406
36568
|
throw new Error("Preview installation requires 1-16 registered projects.");
|
|
36407
36569
|
const projects = raw.projects.map((input2) => {
|
|
36408
|
-
const row =
|
|
36570
|
+
const row = object5(
|
|
36409
36571
|
input2,
|
|
36410
36572
|
["key", "forge", "config", "manifest", "northflank", "hourlyCents", "acceptance"],
|
|
36411
36573
|
["images"]
|
|
36412
36574
|
);
|
|
36413
36575
|
const key = text5(row.key, /^[a-z][a-z0-9-]{0,62}$/);
|
|
36414
|
-
const forgePolicy =
|
|
36576
|
+
const forgePolicy = object5(
|
|
36415
36577
|
row.forge,
|
|
36416
36578
|
["kind", "host", "apiUrl", "repository", "projectId", "botId", "tokenEnv"],
|
|
36417
36579
|
["controllerProjectId"]
|
|
@@ -36431,10 +36593,10 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36431
36593
|
fetch: options.fetch
|
|
36432
36594
|
});
|
|
36433
36595
|
const control = (input3) => {
|
|
36434
|
-
const ref2 =
|
|
36596
|
+
const ref2 = object5(input3, ["file", "sha256"]);
|
|
36435
36597
|
const filename2 = text5(ref2.file, /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/);
|
|
36436
|
-
const file =
|
|
36437
|
-
if (!file.startsWith(`${root}${
|
|
36598
|
+
const file = import_node_fs57.default.realpathSync(import_node_path70.default.join(root, filename2));
|
|
36599
|
+
if (!file.startsWith(`${root}${import_node_path70.default.sep}`))
|
|
36438
36600
|
throw new Error("Preview control file escapes installation directory.");
|
|
36439
36601
|
const source = readFile(file), expected = text5(ref2.sha256, /^[a-f0-9]{64}$/);
|
|
36440
36602
|
if (digest4(source) !== expected)
|
|
@@ -36442,7 +36604,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36442
36604
|
return { source, digest: expected };
|
|
36443
36605
|
};
|
|
36444
36606
|
const local = control(row.config), remote = control(row.manifest), config = parseRepoConfigSource(local.source, ".devrouter.yml"), manifest = parsePreviewManifest(remote.source);
|
|
36445
|
-
const northflank =
|
|
36607
|
+
const northflank = object5(row.northflank, [
|
|
36446
36608
|
"projectId",
|
|
36447
36609
|
"tokenEnv",
|
|
36448
36610
|
"graph",
|
|
@@ -36450,7 +36612,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36450
36612
|
"runtimeSecrets"
|
|
36451
36613
|
]);
|
|
36452
36614
|
const graph = northflank.graph;
|
|
36453
|
-
const qualifications =
|
|
36615
|
+
const qualifications = object5(
|
|
36454
36616
|
northflank.qualification,
|
|
36455
36617
|
[...northflankQualificationKeys],
|
|
36456
36618
|
["outputExec"]
|
|
@@ -36470,7 +36632,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36470
36632
|
for (const id5 of Object.keys(manifest.resources)) integer2(rates[id5], 1, 1e5);
|
|
36471
36633
|
if (Object.keys(rates).some((id5) => !manifest.resources[id5]))
|
|
36472
36634
|
throw new Error("Preview cost names an unknown resource.");
|
|
36473
|
-
const acceptance =
|
|
36635
|
+
const acceptance = object5(row.acceptance, ["command", "environment"]);
|
|
36474
36636
|
if (!Array.isArray(acceptance.command) || acceptance.command.length < 1 || acceptance.command.length > 32 || acceptance.command.some(
|
|
36475
36637
|
(arg) => typeof arg !== "string" || !arg || arg.length > 4096 || arg.includes("\0")
|
|
36476
36638
|
))
|
|
@@ -36496,7 +36658,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36496
36658
|
return credential(secrets[ref2])();
|
|
36497
36659
|
},
|
|
36498
36660
|
accept: async (entry, urls) => {
|
|
36499
|
-
const result = (0,
|
|
36661
|
+
const result = (0, import_node_child_process43.spawnSync)(command[0], command.slice(1), {
|
|
36500
36662
|
cwd: root,
|
|
36501
36663
|
shell: false,
|
|
36502
36664
|
timeout: 3e4,
|
|
@@ -36514,7 +36676,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36514
36676
|
});
|
|
36515
36677
|
if (result.error || result.status !== 0) return false;
|
|
36516
36678
|
try {
|
|
36517
|
-
const proof =
|
|
36679
|
+
const proof = object5(JSON.parse(result.stdout), [
|
|
36518
36680
|
"generation",
|
|
36519
36681
|
"revision",
|
|
36520
36682
|
"urls",
|
|
@@ -36537,7 +36699,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36537
36699
|
source,
|
|
36538
36700
|
...aliases2?.length ? { aliases: aliases2 } : {}
|
|
36539
36701
|
});
|
|
36540
|
-
const imagePolicy = row.images === void 0 ? void 0 :
|
|
36702
|
+
const imagePolicy = row.images === void 0 ? void 0 : object5(row.images, [
|
|
36541
36703
|
"platform",
|
|
36542
36704
|
"platformQualified",
|
|
36543
36705
|
"producer",
|
|
@@ -36551,14 +36713,14 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36551
36713
|
if (!Array.isArray(imageEnvironment) || imageEnvironment.length > 32)
|
|
36552
36714
|
throw new Error("Invalid image resolver environment.");
|
|
36553
36715
|
const imageEnvNames = imageEnvironment.map(envName);
|
|
36554
|
-
const producer = imagePolicy ?
|
|
36716
|
+
const producer = imagePolicy ? object5(imagePolicy.producer, ["repository", "workflow", "controlRevision"]) : void 0;
|
|
36555
36717
|
if (imagePolicy && (!Array.isArray(imagePolicy.files) || imagePolicy.files.length > 32))
|
|
36556
36718
|
throw new Error("Invalid reviewed image resolver files.");
|
|
36557
36719
|
const imageFiles = imagePolicy ? imagePolicy.files.map((input3) => {
|
|
36558
|
-
const item =
|
|
36720
|
+
const item = object5(input3, ["file", "sha256"]);
|
|
36559
36721
|
const verified = control(input3);
|
|
36560
36722
|
return {
|
|
36561
|
-
path:
|
|
36723
|
+
path: import_node_fs57.default.realpathSync(import_node_path70.default.join(root, item.file)),
|
|
36562
36724
|
sha256: verified.digest
|
|
36563
36725
|
};
|
|
36564
36726
|
}) : [];
|
|
@@ -36673,7 +36835,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36673
36835
|
}
|
|
36674
36836
|
},
|
|
36675
36837
|
now,
|
|
36676
|
-
workerId: (0,
|
|
36838
|
+
workerId: (0, import_node_crypto39.randomUUID)(),
|
|
36677
36839
|
policy: {
|
|
36678
36840
|
installationId,
|
|
36679
36841
|
maxActive,
|
|
@@ -36780,7 +36942,7 @@ function loadPreviewInstallation(filename, options = {}) {
|
|
|
36780
36942
|
}
|
|
36781
36943
|
async function initializePreviewInstallation(installationId, store) {
|
|
36782
36944
|
const poolKey = `installations/${installationId}/pool`, witnessKey = `installations/${installationId}/initialized`;
|
|
36783
|
-
if (await store.read(witnessKey, (raw) =>
|
|
36945
|
+
if (await store.read(witnessKey, (raw) => object5(raw, ["installationId"])))
|
|
36784
36946
|
throw new Error(
|
|
36785
36947
|
"Preview installation is already initialized; missing state requires operator recovery."
|
|
36786
36948
|
);
|
|
@@ -36789,14 +36951,14 @@ async function initializePreviewInstallation(installationId, store) {
|
|
|
36789
36951
|
await store.compareAndSwap(witnessKey, null, { installationId });
|
|
36790
36952
|
await store.compareAndSwap(poolKey, null, createPreviewPool(installationId));
|
|
36791
36953
|
}
|
|
36792
|
-
var
|
|
36954
|
+
var import_node_child_process43, import_node_crypto39, import_node_fs57, import_node_path70, MAX_COMMAND_AGE_MS, digest4, envName;
|
|
36793
36955
|
var init_installation = __esm({
|
|
36794
36956
|
"src/core/preview/installation.ts"() {
|
|
36795
36957
|
"use strict";
|
|
36796
|
-
|
|
36797
|
-
|
|
36798
|
-
|
|
36799
|
-
|
|
36958
|
+
import_node_child_process43 = require("child_process");
|
|
36959
|
+
import_node_crypto39 = require("crypto");
|
|
36960
|
+
import_node_fs57 = __toESM(require("fs"));
|
|
36961
|
+
import_node_path70 = __toESM(require("path"));
|
|
36800
36962
|
init_repo_config();
|
|
36801
36963
|
init_command();
|
|
36802
36964
|
init_controller2();
|
|
@@ -36813,7 +36975,7 @@ var init_installation = __esm({
|
|
|
36813
36975
|
init_state();
|
|
36814
36976
|
init_azure_blob();
|
|
36815
36977
|
MAX_COMMAND_AGE_MS = 15 * 6e4;
|
|
36816
|
-
digest4 = (source) => (0,
|
|
36978
|
+
digest4 = (source) => (0, import_node_crypto39.createHash)("sha256").update(source).digest("hex");
|
|
36817
36979
|
envName = (value) => {
|
|
36818
36980
|
if (typeof value !== "string" || !/^DEVROUTER_PREVIEW_[A-Z0-9_]+$/.test(value))
|
|
36819
36981
|
throw new Error("Preview credential references require scoped environment names.");
|
|
@@ -36830,16 +36992,16 @@ __export(preview_exports, {
|
|
|
36830
36992
|
runPreviewPlanCommand: () => runPreviewPlanCommand
|
|
36831
36993
|
});
|
|
36832
36994
|
function readSource(repoPath, filename) {
|
|
36833
|
-
if (
|
|
36995
|
+
if (import_node_path71.default.isAbsolute(filename))
|
|
36834
36996
|
throw new Error("Preview source path must be repository-relative.");
|
|
36835
|
-
const root =
|
|
36997
|
+
const root = import_node_fs58.default.realpathSync(repoPath);
|
|
36836
36998
|
const file = assertPathWithinRepo(filename, root, "preview source");
|
|
36837
|
-
const stat =
|
|
36999
|
+
const stat = import_node_fs58.default.lstatSync(file);
|
|
36838
37000
|
if (stat.isSymbolicLink() || !stat.isFile() || stat.size > 1024 * 1024) {
|
|
36839
37001
|
throw new Error("Preview source must be a regular file of at most 1 MiB.");
|
|
36840
37002
|
}
|
|
36841
|
-
assertPathWithinRepo(
|
|
36842
|
-
return JSON.parse(
|
|
37003
|
+
assertPathWithinRepo(import_node_fs58.default.realpathSync(file), root, "preview source");
|
|
37004
|
+
return JSON.parse(import_node_fs58.default.readFileSync(file, "utf8"));
|
|
36843
37005
|
}
|
|
36844
37006
|
async function runPreviewPlanCommand(options) {
|
|
36845
37007
|
const repoPath = resolveRepoPath(options.repo);
|
|
@@ -36854,13 +37016,13 @@ async function runPreviewPlanCommand(options) {
|
|
|
36854
37016
|
`);
|
|
36855
37017
|
return;
|
|
36856
37018
|
}
|
|
36857
|
-
const localConfig =
|
|
37019
|
+
const localConfig = import_node_fs58.default.readFileSync(import_node_path71.default.join(repoPath, ".devrouter.yml"), "utf8");
|
|
36858
37020
|
const report = buildPreviewPlan({
|
|
36859
37021
|
repoPath,
|
|
36860
37022
|
config: loadRepoConfig(repoPath, () => localConfig),
|
|
36861
37023
|
manifest,
|
|
36862
37024
|
manifestDigest: digest5,
|
|
36863
|
-
localConfigDigest: (0,
|
|
37025
|
+
localConfigDigest: (0, import_node_crypto40.createHash)("sha256").update(localConfig).digest("hex"),
|
|
36864
37026
|
...options.alias === void 0 ? {} : { aliases: options.alias.split(",") },
|
|
36865
37027
|
...options.source === void 0 ? {} : { source: readSource(repoPath, options.source) }
|
|
36866
37028
|
});
|
|
@@ -36879,7 +37041,7 @@ async function runPreviewPlanCommand(options) {
|
|
|
36879
37041
|
}
|
|
36880
37042
|
}
|
|
36881
37043
|
async function runPreviewInitCommand(options) {
|
|
36882
|
-
const repoPath =
|
|
37044
|
+
const repoPath = import_node_fs58.default.realpathSync(resolveRepoPath(options.repo));
|
|
36883
37045
|
if (options.integration === "gitlab") return renderGitLabPreviewIntegration(repoPath, options);
|
|
36884
37046
|
if (options.integration) return renderPreviewIntegration(repoPath, options);
|
|
36885
37047
|
loadRepoConfig(repoPath);
|
|
@@ -36902,10 +37064,10 @@ async function runPreviewInitCommand(options) {
|
|
|
36902
37064
|
allowedUnions: []
|
|
36903
37065
|
}
|
|
36904
37066
|
};
|
|
36905
|
-
const content = (0,
|
|
37067
|
+
const content = (0, import_yaml12.stringify)(manifest);
|
|
36906
37068
|
if (options.write) {
|
|
36907
|
-
const file =
|
|
36908
|
-
|
|
37069
|
+
const file = import_node_path71.default.join(repoPath, ".devrouter.preview.yml");
|
|
37070
|
+
import_node_fs58.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
36909
37071
|
}
|
|
36910
37072
|
if (options.json) {
|
|
36911
37073
|
printJSON({
|
|
@@ -36970,12 +37132,12 @@ async function runPreviewInstallationCommand(action2, options) {
|
|
|
36970
37132
|
}
|
|
36971
37133
|
function previewAsset(name) {
|
|
36972
37134
|
const candidates = [
|
|
36973
|
-
|
|
36974
|
-
|
|
37135
|
+
import_node_path71.default.resolve(__dirname, "..", "assets", "preview", name),
|
|
37136
|
+
import_node_path71.default.resolve(__dirname, "..", "..", "assets", "preview", name)
|
|
36975
37137
|
];
|
|
36976
|
-
const file = candidates.find((file2) =>
|
|
37138
|
+
const file = candidates.find((file2) => import_node_fs58.default.existsSync(file2));
|
|
36977
37139
|
if (!file) throw new Error("Installed preview integration asset is missing.");
|
|
36978
|
-
return
|
|
37140
|
+
return import_node_fs58.default.readFileSync(file, "utf8");
|
|
36979
37141
|
}
|
|
36980
37142
|
function renderPreviewAsset(name, replacements) {
|
|
36981
37143
|
return previewAsset(name).replace(/__([A-Z_]+)__/g, (_match, key) => {
|
|
@@ -37010,9 +37172,9 @@ async function renderPreviewIntegration(repoPath, options) {
|
|
|
37010
37172
|
const filename = `.github/workflows/devrouter-preview${options.sweeper ? "-sweep" : ""}.yml`;
|
|
37011
37173
|
if (options.write) {
|
|
37012
37174
|
const file = assertPathWithinRepo(filename, repoPath, "preview workflow");
|
|
37013
|
-
|
|
37014
|
-
assertPathWithinRepo(
|
|
37015
|
-
|
|
37175
|
+
import_node_fs58.default.mkdirSync(import_node_path71.default.dirname(file), { recursive: true });
|
|
37176
|
+
assertPathWithinRepo(import_node_fs58.default.realpathSync(import_node_path71.default.dirname(file)), repoPath, "preview workflow parent");
|
|
37177
|
+
import_node_fs58.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
|
|
37016
37178
|
}
|
|
37017
37179
|
if (options.json)
|
|
37018
37180
|
printJSON({
|
|
@@ -37030,7 +37192,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37030
37192
|
throw new Error(
|
|
37031
37193
|
"GitLab integration requires reviewed --controller-ref and --controller-image digest."
|
|
37032
37194
|
);
|
|
37033
|
-
const integrity = `sha256-${(0,
|
|
37195
|
+
const integrity = `sha256-${(0, import_node_crypto40.createHash)("sha256").update(previewAsset("gitlab-template.yml")).digest("base64")}`;
|
|
37034
37196
|
const replacements = {
|
|
37035
37197
|
CONTROLLER_REF: String(options.controllerRef),
|
|
37036
37198
|
CONTROLLER_IMAGE: String(options.controllerImage),
|
|
@@ -37039,7 +37201,7 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37039
37201
|
const content = renderPreviewAsset("gitlab.yml", replacements);
|
|
37040
37202
|
const filename = ".gitlab-ci.yml";
|
|
37041
37203
|
if (options.write)
|
|
37042
|
-
|
|
37204
|
+
import_node_fs58.default.writeFileSync(assertPathWithinRepo(filename, repoPath, "GitLab preview caller"), content, {
|
|
37043
37205
|
flag: "wx",
|
|
37044
37206
|
mode: 384
|
|
37045
37207
|
});
|
|
@@ -37054,14 +37216,14 @@ async function renderGitLabPreviewIntegration(repoPath, options) {
|
|
|
37054
37216
|
});
|
|
37055
37217
|
else process.stdout.write(content);
|
|
37056
37218
|
}
|
|
37057
|
-
var
|
|
37219
|
+
var import_node_crypto40, import_node_fs58, import_node_path71, import_yaml12;
|
|
37058
37220
|
var init_preview = __esm({
|
|
37059
37221
|
"src/commands/preview.ts"() {
|
|
37060
37222
|
"use strict";
|
|
37061
|
-
|
|
37062
|
-
|
|
37063
|
-
|
|
37064
|
-
|
|
37223
|
+
import_node_crypto40 = require("crypto");
|
|
37224
|
+
import_node_fs58 = __toESM(require("fs"));
|
|
37225
|
+
import_node_path71 = __toESM(require("path"));
|
|
37226
|
+
import_yaml12 = require("yaml");
|
|
37065
37227
|
init_output();
|
|
37066
37228
|
init_paths();
|
|
37067
37229
|
init_manifest();
|
|
@@ -37352,7 +37514,7 @@ function sanitizeRouterId(value) {
|
|
|
37352
37514
|
return value.replace(/[^a-zA-Z0-9_-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
37353
37515
|
}
|
|
37354
37516
|
function repoHash(repoPath) {
|
|
37355
|
-
return (0,
|
|
37517
|
+
return (0, import_node_crypto41.createHash)("sha1").update(import_node_path72.default.resolve(repoPath)).digest("hex").slice(0, 12);
|
|
37356
37518
|
}
|
|
37357
37519
|
function asDockerApp(app) {
|
|
37358
37520
|
return app.runtime === "docker";
|
|
@@ -37431,11 +37593,11 @@ function prepareDockerOverlay(repoPath, appName, apps, publishTcpPorts = false)
|
|
|
37431
37593
|
if (dockerApps.length === 0) {
|
|
37432
37594
|
throw new Error("No docker apps selected to prepare compose overlay.");
|
|
37433
37595
|
}
|
|
37434
|
-
const cachePath =
|
|
37435
|
-
|
|
37436
|
-
const overlayPath =
|
|
37596
|
+
const cachePath = import_node_path72.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
|
|
37597
|
+
import_node_fs59.default.mkdirSync(cachePath, { recursive: true });
|
|
37598
|
+
const overlayPath = import_node_path72.default.join(cachePath, "compose.devrouter.yml");
|
|
37437
37599
|
const overlayDocument = buildOverlayDocument(dockerApps, publishTcpPorts);
|
|
37438
|
-
|
|
37600
|
+
import_node_fs59.default.writeFileSync(overlayPath, import_yaml13.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
|
|
37439
37601
|
return {
|
|
37440
37602
|
overlayPath,
|
|
37441
37603
|
composeFiles: ensureComposeFiles(dockerApps),
|
|
@@ -37449,7 +37611,7 @@ function runDockerComposeUp(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37449
37611
|
fileArgs.push("-f", resolved2);
|
|
37450
37612
|
}
|
|
37451
37613
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "up", "-d", "--wait", ...services];
|
|
37452
|
-
const result = (0,
|
|
37614
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37453
37615
|
encoding: "utf-8",
|
|
37454
37616
|
cwd: repoPath
|
|
37455
37617
|
});
|
|
@@ -37477,7 +37639,7 @@ function queryRunningComposeServices(repoPath, composeFiles2, overlayPath, servi
|
|
|
37477
37639
|
"--services",
|
|
37478
37640
|
...services
|
|
37479
37641
|
];
|
|
37480
|
-
const result = (0,
|
|
37642
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37481
37643
|
encoding: "utf-8",
|
|
37482
37644
|
cwd: repoPath
|
|
37483
37645
|
});
|
|
@@ -37503,7 +37665,7 @@ function runDockerComposeStop(repoPath, composeFiles2, overlayPath, services) {
|
|
|
37503
37665
|
fileArgs.push("-f", resolved2);
|
|
37504
37666
|
}
|
|
37505
37667
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "stop", ...services];
|
|
37506
|
-
const result = (0,
|
|
37668
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37507
37669
|
encoding: "utf-8",
|
|
37508
37670
|
cwd: repoPath
|
|
37509
37671
|
});
|
|
@@ -37529,7 +37691,7 @@ function runDockerComposeLogs(repoPath, composeFiles2, overlayPath, services, ta
|
|
|
37529
37691
|
String(tail),
|
|
37530
37692
|
...services
|
|
37531
37693
|
];
|
|
37532
|
-
(0,
|
|
37694
|
+
(0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37533
37695
|
stdio: "inherit",
|
|
37534
37696
|
cwd: repoPath
|
|
37535
37697
|
});
|
|
@@ -37541,7 +37703,7 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37541
37703
|
fileArgs.push("-f", resolved2);
|
|
37542
37704
|
}
|
|
37543
37705
|
const args = ["compose", ...fileArgs, "-f", overlayPath, "port", service, String(internalPort)];
|
|
37544
|
-
const result = (0,
|
|
37706
|
+
const result = (0, import_node_child_process44.spawnSync)("docker", args, {
|
|
37545
37707
|
encoding: "utf-8",
|
|
37546
37708
|
cwd: repoPath
|
|
37547
37709
|
});
|
|
@@ -37555,15 +37717,15 @@ function queryMappedPort(repoPath, composeFiles2, overlayPath, service, internal
|
|
|
37555
37717
|
const port = Number(match[1]);
|
|
37556
37718
|
return Number.isInteger(port) && port > 0 ? port : void 0;
|
|
37557
37719
|
}
|
|
37558
|
-
var
|
|
37720
|
+
var import_node_child_process44, import_node_crypto41, import_node_fs59, import_node_path72, import_yaml13;
|
|
37559
37721
|
var init_docker_run = __esm({
|
|
37560
37722
|
"src/core/docker-run.ts"() {
|
|
37561
37723
|
"use strict";
|
|
37562
|
-
|
|
37563
|
-
|
|
37564
|
-
|
|
37565
|
-
|
|
37566
|
-
|
|
37724
|
+
import_node_child_process44 = require("child_process");
|
|
37725
|
+
import_node_crypto41 = require("crypto");
|
|
37726
|
+
import_node_fs59 = __toESM(require("fs"));
|
|
37727
|
+
import_node_path72 = __toESM(require("path"));
|
|
37728
|
+
import_yaml13 = __toESM(require("yaml"));
|
|
37567
37729
|
init_docker_error_guidance();
|
|
37568
37730
|
init_paths();
|
|
37569
37731
|
init_router();
|
|
@@ -37652,7 +37814,7 @@ function isProcessRunning(pid) {
|
|
|
37652
37814
|
}
|
|
37653
37815
|
}
|
|
37654
37816
|
function readProcessTree(rootPid) {
|
|
37655
|
-
const result = (0,
|
|
37817
|
+
const result = (0, import_node_child_process45.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
|
|
37656
37818
|
if (result.status !== 0) {
|
|
37657
37819
|
return [rootPid];
|
|
37658
37820
|
}
|
|
@@ -37763,12 +37925,12 @@ function detectListeningPorts(pids) {
|
|
|
37763
37925
|
if (pids.length === 0) {
|
|
37764
37926
|
return [];
|
|
37765
37927
|
}
|
|
37766
|
-
const result = (0,
|
|
37928
|
+
const result = (0, import_node_child_process45.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
|
|
37767
37929
|
encoding: "utf-8"
|
|
37768
37930
|
});
|
|
37769
37931
|
if (result.error && result.error.code === "ENOENT") {
|
|
37770
37932
|
if (process.platform === "linux") {
|
|
37771
|
-
const ssResult = (0,
|
|
37933
|
+
const ssResult = (0, import_node_child_process45.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
|
|
37772
37934
|
if (ssResult.status === 0 && ssResult.stdout) {
|
|
37773
37935
|
return parseSsListeningPorts(ssResult.stdout, new Set(pids));
|
|
37774
37936
|
}
|
|
@@ -37827,7 +37989,7 @@ async function runHostApp(repoPath, app, extraEnv = {}, secretManager, env, work
|
|
|
37827
37989
|
app.hostRun.command,
|
|
37828
37990
|
true
|
|
37829
37991
|
) : app.hostRun.command;
|
|
37830
|
-
const child = (0,
|
|
37992
|
+
const child = (0, import_node_child_process45.spawn)(spawnCommand, {
|
|
37831
37993
|
cwd: commandCwd,
|
|
37832
37994
|
stdio: "inherit",
|
|
37833
37995
|
shell: true,
|
|
@@ -38195,7 +38357,7 @@ async function execWithAppEnv(options) {
|
|
|
38195
38357
|
options.command[0],
|
|
38196
38358
|
true
|
|
38197
38359
|
);
|
|
38198
|
-
child = (0,
|
|
38360
|
+
child = (0, import_node_child_process45.spawn)(wrapped, {
|
|
38199
38361
|
cwd: deps.repoPath,
|
|
38200
38362
|
stdio: "inherit",
|
|
38201
38363
|
shell: true,
|
|
@@ -38209,7 +38371,7 @@ async function execWithAppEnv(options) {
|
|
|
38209
38371
|
false
|
|
38210
38372
|
);
|
|
38211
38373
|
const [cmd, ...wrappedArgs] = wrapped;
|
|
38212
|
-
child = (0,
|
|
38374
|
+
child = (0, import_node_child_process45.spawn)(cmd, wrappedArgs, {
|
|
38213
38375
|
cwd: deps.repoPath,
|
|
38214
38376
|
stdio: "inherit",
|
|
38215
38377
|
shell: false,
|
|
@@ -38217,7 +38379,7 @@ async function execWithAppEnv(options) {
|
|
|
38217
38379
|
});
|
|
38218
38380
|
}
|
|
38219
38381
|
} else if (options.shell) {
|
|
38220
|
-
child = (0,
|
|
38382
|
+
child = (0, import_node_child_process45.spawn)(options.command[0], {
|
|
38221
38383
|
cwd: deps.repoPath,
|
|
38222
38384
|
stdio: "inherit",
|
|
38223
38385
|
shell: true,
|
|
@@ -38225,7 +38387,7 @@ async function execWithAppEnv(options) {
|
|
|
38225
38387
|
});
|
|
38226
38388
|
} else {
|
|
38227
38389
|
const [command, ...args] = options.command;
|
|
38228
|
-
child = (0,
|
|
38390
|
+
child = (0, import_node_child_process45.spawn)(command, args, {
|
|
38229
38391
|
cwd: deps.repoPath,
|
|
38230
38392
|
stdio: "inherit",
|
|
38231
38393
|
shell: false,
|
|
@@ -38246,11 +38408,11 @@ async function execWithAppEnv(options) {
|
|
|
38246
38408
|
deps.stopDeps();
|
|
38247
38409
|
}
|
|
38248
38410
|
}
|
|
38249
|
-
var
|
|
38411
|
+
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
38412
|
var init_app_run = __esm({
|
|
38251
38413
|
"src/core/app-run.ts"() {
|
|
38252
38414
|
"use strict";
|
|
38253
|
-
|
|
38415
|
+
import_node_child_process45 = require("child_process");
|
|
38254
38416
|
import_node_net6 = __toESM(require("net"));
|
|
38255
38417
|
import_node_process = require("process");
|
|
38256
38418
|
import_promises = require("readline/promises");
|
|
@@ -38396,7 +38558,7 @@ function canonicalJson(value) {
|
|
|
38396
38558
|
`;
|
|
38397
38559
|
}
|
|
38398
38560
|
function sha256Hex(raw) {
|
|
38399
|
-
return (0,
|
|
38561
|
+
return (0, import_node_crypto42.createHash)("sha256").update(raw).digest("hex");
|
|
38400
38562
|
}
|
|
38401
38563
|
function candidateId(candidate) {
|
|
38402
38564
|
const identity2 = {
|
|
@@ -38458,7 +38620,7 @@ function validateCandidate(value, index, action2, legacy) {
|
|
|
38458
38620
|
}
|
|
38459
38621
|
}
|
|
38460
38622
|
for (const key of ["repo", "path", "commonDir", "gitDir"]) {
|
|
38461
|
-
if (!
|
|
38623
|
+
if (!import_node_path73.default.isAbsolute(candidate[key])) {
|
|
38462
38624
|
throw new Error(`${label2}.${key} must be an absolute path`);
|
|
38463
38625
|
}
|
|
38464
38626
|
}
|
|
@@ -38564,7 +38726,7 @@ function validateManifest(value) {
|
|
|
38564
38726
|
return root;
|
|
38565
38727
|
}
|
|
38566
38728
|
function readManifest(file) {
|
|
38567
|
-
const raw =
|
|
38729
|
+
const raw = import_node_fs60.default.readFileSync(file);
|
|
38568
38730
|
let parsed;
|
|
38569
38731
|
try {
|
|
38570
38732
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -38603,7 +38765,7 @@ function selectManifest(file, expectedSha256, ids2) {
|
|
|
38603
38765
|
return canonicalJson(subset);
|
|
38604
38766
|
}
|
|
38605
38767
|
function gitLine(cwd, args) {
|
|
38606
|
-
const result = (0,
|
|
38768
|
+
const result = (0, import_node_child_process46.spawnSync)("git", ["-C", cwd, ...args], {
|
|
38607
38769
|
encoding: "utf-8",
|
|
38608
38770
|
env: { ...process.env, GIT_OPTIONAL_LOCKS: "0", LC_ALL: "C" }
|
|
38609
38771
|
});
|
|
@@ -38611,7 +38773,7 @@ function gitLine(cwd, args) {
|
|
|
38611
38773
|
return result.status === 0 && !result.error && output2 ? output2 : void 0;
|
|
38612
38774
|
}
|
|
38613
38775
|
function readWorktreeIdentity(worktreePath) {
|
|
38614
|
-
if (!
|
|
38776
|
+
if (!import_node_fs60.default.existsSync(worktreePath)) return void 0;
|
|
38615
38777
|
const real = comparableWorkspacePath(worktreePath);
|
|
38616
38778
|
const commonDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
38617
38779
|
const gitDir = gitLine(real, ["rev-parse", "--path-format=absolute", "--git-dir"]);
|
|
@@ -38631,13 +38793,13 @@ function identityMismatch(expected, actual) {
|
|
|
38631
38793
|
function unmanagedActivityEpoch(worktreePath, gitDir) {
|
|
38632
38794
|
let latest;
|
|
38633
38795
|
for (const file of [
|
|
38634
|
-
|
|
38635
|
-
|
|
38636
|
-
|
|
38796
|
+
import_node_path73.default.join(gitDir, "index"),
|
|
38797
|
+
import_node_path73.default.join(gitDir, "HEAD"),
|
|
38798
|
+
import_node_path73.default.join(gitDir, "logs", "HEAD"),
|
|
38637
38799
|
worktreePath
|
|
38638
38800
|
]) {
|
|
38639
38801
|
try {
|
|
38640
|
-
const seconds = Math.floor(
|
|
38802
|
+
const seconds = Math.floor(import_node_fs60.default.statSync(file).mtimeMs / 1e3);
|
|
38641
38803
|
latest = latest === void 0 ? seconds : Math.max(latest, seconds);
|
|
38642
38804
|
} catch {
|
|
38643
38805
|
}
|
|
@@ -38691,12 +38853,12 @@ function buildReclaimManifest(report, createdAtEpoch) {
|
|
|
38691
38853
|
return canonicalJson(manifest);
|
|
38692
38854
|
}
|
|
38693
38855
|
function receiptPath(commonDir, manifestSha256, id5) {
|
|
38694
|
-
return
|
|
38856
|
+
return import_node_path73.default.join(commonDir, "worktree-reclaim", "receipts", manifestSha256, `${id5}.json`);
|
|
38695
38857
|
}
|
|
38696
38858
|
function matchingReceipt(candidate, manifestSha256) {
|
|
38697
38859
|
try {
|
|
38698
38860
|
const receipt = JSON.parse(
|
|
38699
|
-
|
|
38861
|
+
import_node_fs60.default.readFileSync(receiptPath(candidate.commonDir, manifestSha256, candidate.id), "utf-8")
|
|
38700
38862
|
);
|
|
38701
38863
|
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
38864
|
} catch {
|
|
@@ -38705,7 +38867,7 @@ function matchingReceipt(candidate, manifestSha256) {
|
|
|
38705
38867
|
}
|
|
38706
38868
|
function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
38707
38869
|
const file = receiptPath(candidate.commonDir, manifestSha256, candidate.id);
|
|
38708
|
-
|
|
38870
|
+
import_node_fs60.default.mkdirSync(import_node_path73.default.dirname(file), { recursive: true });
|
|
38709
38871
|
writeFileAtomically(
|
|
38710
38872
|
file,
|
|
38711
38873
|
canonicalJson({
|
|
@@ -38723,7 +38885,7 @@ function writeReceipt(candidate, manifestSha256, steps, nowEpoch) {
|
|
|
38723
38885
|
);
|
|
38724
38886
|
}
|
|
38725
38887
|
function runVetoCommand(command, worktreePath) {
|
|
38726
|
-
const result = (0,
|
|
38888
|
+
const result = (0, import_node_child_process46.spawnSync)(command, [worktreePath], {
|
|
38727
38889
|
stdio: ["ignore", "ignore", "inherit"],
|
|
38728
38890
|
timeout: VETO_TIMEOUT_MS
|
|
38729
38891
|
});
|
|
@@ -38736,9 +38898,9 @@ function runVetoCommand(command, worktreePath) {
|
|
|
38736
38898
|
return result.status === 0 && !result.error && result.signal === null;
|
|
38737
38899
|
}
|
|
38738
38900
|
function assertVetoCommand(command) {
|
|
38739
|
-
if (!
|
|
38901
|
+
if (!import_node_path73.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
|
|
38740
38902
|
try {
|
|
38741
|
-
|
|
38903
|
+
import_node_fs60.default.accessSync(command, import_node_fs60.default.constants.X_OK);
|
|
38742
38904
|
} catch {
|
|
38743
38905
|
throw new Error(`--veto-command '${command}' is missing or not executable`);
|
|
38744
38906
|
}
|
|
@@ -38764,7 +38926,7 @@ function preflightManifestApply(options, action2, nowEpoch) {
|
|
|
38764
38926
|
return { manifest, manifestSha256, now };
|
|
38765
38927
|
}
|
|
38766
38928
|
function deleteBranchIfUnmoved(candidate, steps) {
|
|
38767
|
-
const exists2 = (0,
|
|
38929
|
+
const exists2 = (0, import_node_child_process46.spawnSync)(
|
|
38768
38930
|
"git",
|
|
38769
38931
|
["-C", candidate.repo, "show-ref", "--verify", "--quiet", candidate.branchRef],
|
|
38770
38932
|
{ encoding: "utf-8" }
|
|
@@ -38773,7 +38935,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38773
38935
|
if (exists2.status !== 0) {
|
|
38774
38936
|
throw new Error(`cannot read branch ${candidate.branch}: ${(exists2.stderr ?? "").trim()}`);
|
|
38775
38937
|
}
|
|
38776
|
-
const result = (0,
|
|
38938
|
+
const result = (0, import_node_child_process46.spawnSync)(
|
|
38777
38939
|
"git",
|
|
38778
38940
|
["-C", candidate.repo, "update-ref", "-d", candidate.branchRef, candidate.head],
|
|
38779
38941
|
{ encoding: "utf-8" }
|
|
@@ -38782,7 +38944,7 @@ function deleteBranchIfUnmoved(candidate, steps) {
|
|
|
38782
38944
|
return `branch ${candidate.branch} no longer points at the approved HEAD; it was kept for review`;
|
|
38783
38945
|
}
|
|
38784
38946
|
steps.push("branch-deleted");
|
|
38785
|
-
(0,
|
|
38947
|
+
(0, import_node_child_process46.spawnSync)(
|
|
38786
38948
|
"git",
|
|
38787
38949
|
["-C", candidate.repo, "config", "--remove-section", `branch.${candidate.branch}`],
|
|
38788
38950
|
{ encoding: "utf-8" }
|
|
@@ -38820,7 +38982,7 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38820
38982
|
outcome.status = "not-attempted";
|
|
38821
38983
|
continue;
|
|
38822
38984
|
}
|
|
38823
|
-
if (!
|
|
38985
|
+
if (!import_node_fs60.default.existsSync(candidate.path) && matchingReceipt(candidate, manifestSha256)) {
|
|
38824
38986
|
outcome.status = "already-done";
|
|
38825
38987
|
continue;
|
|
38826
38988
|
}
|
|
@@ -38889,14 +39051,14 @@ async function applyReclaimManifest(options, dependencies) {
|
|
|
38889
39051
|
}
|
|
38890
39052
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
38891
39053
|
}
|
|
38892
|
-
var
|
|
39054
|
+
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
39055
|
var init_worktree_reclaim = __esm({
|
|
38894
39056
|
"src/core/worktree-reclaim.ts"() {
|
|
38895
39057
|
"use strict";
|
|
38896
|
-
|
|
38897
|
-
|
|
38898
|
-
|
|
38899
|
-
|
|
39058
|
+
import_node_child_process46 = require("child_process");
|
|
39059
|
+
import_node_crypto42 = require("crypto");
|
|
39060
|
+
import_node_fs60 = __toESM(require("fs"));
|
|
39061
|
+
import_node_path73 = __toESM(require("path"));
|
|
38900
39062
|
init_atomic_file();
|
|
38901
39063
|
init_workspace();
|
|
38902
39064
|
MANIFEST_KIND = "worktree-reclaim-manifest";
|
|
@@ -39016,8 +39178,8 @@ function checkoutOf(workingDir) {
|
|
|
39016
39178
|
return workingDir.replace(/\/+$/, "").replace(/\/\.devcontainer$/, "");
|
|
39017
39179
|
}
|
|
39018
39180
|
function isInsideOrEqual(parent, child) {
|
|
39019
|
-
const relative2 =
|
|
39020
|
-
return relative2 === "" || !relative2.startsWith("..") && !
|
|
39181
|
+
const relative2 = import_node_path74.default.relative(parent, child);
|
|
39182
|
+
return relative2 === "" || !relative2.startsWith("..") && !import_node_path74.default.isAbsolute(relative2);
|
|
39021
39183
|
}
|
|
39022
39184
|
function isAnonymousVolume(volume) {
|
|
39023
39185
|
return /^[0-9a-f]{64}$/.test(volume.name) && !volume.labels[PROJECT_LABEL];
|
|
@@ -39029,9 +39191,9 @@ function vanishedInsideTrees(checkout, context) {
|
|
|
39029
39191
|
(prefix) => checkout !== prefix && isInsideOrEqual(prefix, checkout)
|
|
39030
39192
|
);
|
|
39031
39193
|
if (!lexical || context.exists(checkout)) return "out-of-scope";
|
|
39032
|
-
let ancestor =
|
|
39194
|
+
let ancestor = import_node_path74.default.dirname(checkout);
|
|
39033
39195
|
while (!context.exists(ancestor)) {
|
|
39034
|
-
const parent =
|
|
39196
|
+
const parent = import_node_path74.default.dirname(ancestor);
|
|
39035
39197
|
if (parent === ancestor) return "out-of-scope";
|
|
39036
39198
|
ancestor = parent;
|
|
39037
39199
|
}
|
|
@@ -39039,16 +39201,16 @@ function vanishedInsideTrees(checkout, context) {
|
|
|
39039
39201
|
if (ancestorReal === void 0 || !isInsideOrEqual(treesReal, ancestorReal)) {
|
|
39040
39202
|
return "out-of-scope";
|
|
39041
39203
|
}
|
|
39042
|
-
for (let current = ancestor; ; current =
|
|
39204
|
+
for (let current = ancestor; ; current = import_node_path74.default.dirname(current)) {
|
|
39043
39205
|
const real = context.realpath(current);
|
|
39044
39206
|
if (real === void 0 || real === treesReal || !isInsideOrEqual(treesReal, real)) break;
|
|
39045
|
-
if (context.exists(
|
|
39207
|
+
if (context.exists(import_node_path74.default.join(current, ".git"))) return "inside-worktree";
|
|
39046
39208
|
}
|
|
39047
39209
|
return "vanished";
|
|
39048
39210
|
}
|
|
39049
39211
|
function resolved(file, context) {
|
|
39050
39212
|
const real = context.realpath(file);
|
|
39051
|
-
return real && real !==
|
|
39213
|
+
return real && real !== import_node_path74.default.resolve(file) ? [import_node_path74.default.resolve(file), real] : [import_node_path74.default.resolve(file)];
|
|
39052
39214
|
}
|
|
39053
39215
|
function relation(entry, checkout, context) {
|
|
39054
39216
|
const entries = resolved(entry, context);
|
|
@@ -39153,21 +39315,21 @@ function readLeftoverContext(repoPath) {
|
|
|
39153
39315
|
resetWorkspaceRuntimeCaches();
|
|
39154
39316
|
const snapshots = getWorkspaceRegistrySnapshots();
|
|
39155
39317
|
return {
|
|
39156
|
-
treesPath:
|
|
39318
|
+
treesPath: import_node_path74.default.join(repoPath, "trees"),
|
|
39157
39319
|
worktreePaths: listGitWorktrees(repoPath).map((worktree) => worktree.path),
|
|
39158
39320
|
ownershipPaths: listWorkspaceOwnership(repoPath).map((record6) => record6.worktreePath),
|
|
39159
39321
|
providerPaths: listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
39160
39322
|
registriesReadable: snapshots.unavailable.length === 0,
|
|
39161
39323
|
realpath: (file) => {
|
|
39162
39324
|
try {
|
|
39163
|
-
return
|
|
39325
|
+
return import_node_fs61.default.realpathSync.native(file);
|
|
39164
39326
|
} catch {
|
|
39165
39327
|
return void 0;
|
|
39166
39328
|
}
|
|
39167
39329
|
},
|
|
39168
39330
|
exists: (file) => {
|
|
39169
39331
|
try {
|
|
39170
|
-
|
|
39332
|
+
import_node_fs61.default.lstatSync(file);
|
|
39171
39333
|
return true;
|
|
39172
39334
|
} catch (error) {
|
|
39173
39335
|
return error.code !== "ENOENT";
|
|
@@ -39231,7 +39393,7 @@ function validateLeftoverManifest(value) {
|
|
|
39231
39393
|
throw new Error(`manifest schemaVersion must be ${SCHEMA_VERSION2}`);
|
|
39232
39394
|
}
|
|
39233
39395
|
requireString(root.repo, "manifest repo");
|
|
39234
|
-
if (!
|
|
39396
|
+
if (!import_node_path74.default.isAbsolute(root.repo)) throw new Error("manifest repo must be an absolute path");
|
|
39235
39397
|
requireString(root.daemonId, "manifest daemonId");
|
|
39236
39398
|
if (!Number.isInteger(root.createdAtEpoch) || root.createdAtEpoch < 0) {
|
|
39237
39399
|
throw new Error("manifest createdAtEpoch must be a non-negative integer");
|
|
@@ -39253,7 +39415,7 @@ function validateLeftoverManifest(value) {
|
|
|
39253
39415
|
);
|
|
39254
39416
|
requireString(candidate.project, `${label2}.project`);
|
|
39255
39417
|
requireString(candidate.checkout, `${label2}.checkout`);
|
|
39256
|
-
if (!
|
|
39418
|
+
if (!import_node_path74.default.isAbsolute(candidate.checkout)) {
|
|
39257
39419
|
throw new Error(`${label2}.checkout must be an absolute path`);
|
|
39258
39420
|
}
|
|
39259
39421
|
const members = [
|
|
@@ -39291,7 +39453,7 @@ function validateLeftoverManifest(value) {
|
|
|
39291
39453
|
return root;
|
|
39292
39454
|
}
|
|
39293
39455
|
function readLeftoverManifest(file) {
|
|
39294
|
-
const raw =
|
|
39456
|
+
const raw = import_node_fs61.default.readFileSync(file);
|
|
39295
39457
|
let parsed;
|
|
39296
39458
|
try {
|
|
39297
39459
|
parsed = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(raw));
|
|
@@ -39305,7 +39467,7 @@ function readLeftoverManifest(file) {
|
|
|
39305
39467
|
return { raw, manifest };
|
|
39306
39468
|
}
|
|
39307
39469
|
function gitCommonDir(repo) {
|
|
39308
|
-
const result = (0,
|
|
39470
|
+
const result = (0, import_node_child_process47.spawnSync)(
|
|
39309
39471
|
"git",
|
|
39310
39472
|
["-C", repo, "rev-parse", "--path-format=absolute", "--git-common-dir"],
|
|
39311
39473
|
{ encoding: "utf-8" }
|
|
@@ -39334,7 +39496,7 @@ function currentRemovals(candidate, inventory, context) {
|
|
|
39334
39496
|
throw new LeftoverSkip("changed", "the checkout folder exists again");
|
|
39335
39497
|
}
|
|
39336
39498
|
const mounted = new Set(inventory.containers.flatMap((container) => container.volumes));
|
|
39337
|
-
const ours = (
|
|
39499
|
+
const ours = (object6) => object6.labels[PROJECT_LABEL] === candidate.project && object6.name.startsWith(`${candidate.project}_`);
|
|
39338
39500
|
current = {
|
|
39339
39501
|
project: candidate.project,
|
|
39340
39502
|
checkout: candidate.checkout,
|
|
@@ -39473,11 +39635,11 @@ function applyLeftoverManifest(options, dependencies = {}) {
|
|
|
39473
39635
|
return { manifestSha256, dryRun: !options.yes, targets };
|
|
39474
39636
|
}
|
|
39475
39637
|
function leftoverReceiptPath(commonDir, manifestSha256, id5) {
|
|
39476
|
-
return
|
|
39638
|
+
return import_node_path74.default.join(commonDir, "devrouter-leftovers", "receipts", manifestSha256, `${id5}.json`);
|
|
39477
39639
|
}
|
|
39478
39640
|
function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEpoch) {
|
|
39479
39641
|
const file = leftoverReceiptPath(commonDir, manifestSha256, candidate.id);
|
|
39480
|
-
|
|
39642
|
+
import_node_fs61.default.mkdirSync(import_node_path74.default.dirname(file), { recursive: true });
|
|
39481
39643
|
writeFileAtomically(
|
|
39482
39644
|
file,
|
|
39483
39645
|
canonicalJson({
|
|
@@ -39493,13 +39655,13 @@ function writeLeftoverReceipt(commonDir, manifestSha256, candidate, steps, nowEp
|
|
|
39493
39655
|
})
|
|
39494
39656
|
);
|
|
39495
39657
|
}
|
|
39496
|
-
var
|
|
39658
|
+
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
39659
|
var init_docker_leftovers = __esm({
|
|
39498
39660
|
"src/core/docker-leftovers.ts"() {
|
|
39499
39661
|
"use strict";
|
|
39500
|
-
|
|
39501
|
-
|
|
39502
|
-
|
|
39662
|
+
import_node_child_process47 = require("child_process");
|
|
39663
|
+
import_node_fs61 = __toESM(require("fs"));
|
|
39664
|
+
import_node_path74 = __toESM(require("path"));
|
|
39503
39665
|
init_atomic_file();
|
|
39504
39666
|
init_devpod_mutation();
|
|
39505
39667
|
init_devpod_workspaces();
|
|
@@ -39520,7 +39682,7 @@ var init_docker_leftovers = __esm({
|
|
|
39520
39682
|
DockerListingBoundError = class extends Error {
|
|
39521
39683
|
};
|
|
39522
39684
|
defaultDockerRunner = (args) => {
|
|
39523
|
-
const result = (0,
|
|
39685
|
+
const result = (0, import_node_child_process47.spawnSync)("docker", args, {
|
|
39524
39686
|
encoding: "utf-8",
|
|
39525
39687
|
timeout: 6e4,
|
|
39526
39688
|
maxBuffer: 256 * 1024 * 1024
|
|
@@ -39551,13 +39713,13 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39551
39713
|
const startedAt = Date.now();
|
|
39552
39714
|
let rootStat;
|
|
39553
39715
|
try {
|
|
39554
|
-
rootStat =
|
|
39716
|
+
rootStat = import_node_fs62.default.lstatSync(worktreePath);
|
|
39555
39717
|
} catch (error) {
|
|
39556
39718
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39557
39719
|
}
|
|
39558
39720
|
let rootEntries;
|
|
39559
39721
|
try {
|
|
39560
|
-
rootEntries =
|
|
39722
|
+
rootEntries = import_node_fs62.default.readdirSync(worktreePath, { withFileTypes: true });
|
|
39561
39723
|
} catch (error) {
|
|
39562
39724
|
return { status: "unknown", reason: describeError(error, worktreePath) };
|
|
39563
39725
|
}
|
|
@@ -39583,10 +39745,10 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39583
39745
|
timedOut = true;
|
|
39584
39746
|
break;
|
|
39585
39747
|
}
|
|
39586
|
-
const entryPath =
|
|
39748
|
+
const entryPath = import_node_path75.default.join(dirPath, entry.name);
|
|
39587
39749
|
let entryStat;
|
|
39588
39750
|
try {
|
|
39589
|
-
entryStat =
|
|
39751
|
+
entryStat = import_node_fs62.default.lstatSync(entryPath);
|
|
39590
39752
|
} catch (error) {
|
|
39591
39753
|
if (error?.code === "ENOENT") continue;
|
|
39592
39754
|
unreadableReason = describeIncompleteWalk(error);
|
|
@@ -39596,7 +39758,7 @@ function measureWorktreeConsumption(worktreePath, options) {
|
|
|
39596
39758
|
if (!entryStat.isDirectory()) continue;
|
|
39597
39759
|
let childEntries;
|
|
39598
39760
|
try {
|
|
39599
|
-
childEntries =
|
|
39761
|
+
childEntries = import_node_fs62.default.readdirSync(entryPath, { withFileTypes: true });
|
|
39600
39762
|
} catch (error) {
|
|
39601
39763
|
unreadableReason = describeIncompleteWalk(error);
|
|
39602
39764
|
break;
|
|
@@ -39660,12 +39822,12 @@ function describeError(error, worktreePath) {
|
|
|
39660
39822
|
}
|
|
39661
39823
|
return `could not stat worktree path '${worktreePath}': ${error?.message ?? String(error)}`;
|
|
39662
39824
|
}
|
|
39663
|
-
var
|
|
39825
|
+
var import_node_fs62, import_node_path75, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
|
|
39664
39826
|
var init_workspace_consumption = __esm({
|
|
39665
39827
|
"src/core/workspace-consumption.ts"() {
|
|
39666
39828
|
"use strict";
|
|
39667
|
-
|
|
39668
|
-
|
|
39829
|
+
import_node_fs62 = __toESM(require("fs"));
|
|
39830
|
+
import_node_path75 = __toESM(require("path"));
|
|
39669
39831
|
init_devpod_environment();
|
|
39670
39832
|
DEFAULT_DEADLINE_MS = 1e4;
|
|
39671
39833
|
BLOCK_SIZE_BYTES = 512;
|
|
@@ -39751,7 +39913,7 @@ function evaluateWorkspaceActivity(evidence, cutoff) {
|
|
|
39751
39913
|
}
|
|
39752
39914
|
function readGitSnapshot(worktree, commandRunner) {
|
|
39753
39915
|
const comparablePath = comparableWorkspacePath(worktree.path);
|
|
39754
|
-
if (worktree.prunable || !
|
|
39916
|
+
if (worktree.prunable || !import_node_fs63.default.existsSync(comparablePath)) {
|
|
39755
39917
|
return { worktree, checkout: "missing", head: null, committerDate: null };
|
|
39756
39918
|
}
|
|
39757
39919
|
const head = gitOutput(comparablePath, ["rev-parse", "--verify", "HEAD"], commandRunner);
|
|
@@ -40324,7 +40486,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40324
40486
|
containers2 = measureContainersFn(worktreePaths);
|
|
40325
40487
|
} catch (error) {
|
|
40326
40488
|
const reason2 = `container measurement failed: ${describeCause(error)}`;
|
|
40327
|
-
containers2 = new Map(worktreePaths.map((
|
|
40489
|
+
containers2 = new Map(worktreePaths.map((path80) => [path80, unknownContainers(reason2)]));
|
|
40328
40490
|
}
|
|
40329
40491
|
}
|
|
40330
40492
|
const rows2 = records.map((record6) => {
|
|
@@ -40383,7 +40545,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40383
40545
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40384
40546
|
);
|
|
40385
40547
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40386
|
-
const disposable =
|
|
40548
|
+
const disposable = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40387
40549
|
const [primary, ...linked] = worktrees;
|
|
40388
40550
|
const safetyFor = (worktree, worktreePath, evidence) => toSafety(
|
|
40389
40551
|
classify({
|
|
@@ -40391,7 +40553,7 @@ function buildWorkspaceCleanupReport(options = {}, dependencies = {}) {
|
|
|
40391
40553
|
branch: worktree?.branch,
|
|
40392
40554
|
primary: primary !== void 0 && sameWorkspacePath(primary.path, worktreePath),
|
|
40393
40555
|
locked: worktree?.locked ?? false,
|
|
40394
|
-
missing: !worktree || worktree.prunable || !
|
|
40556
|
+
missing: !worktree || worktree.prunable || !import_node_fs63.default.existsSync(worktreePath),
|
|
40395
40557
|
runtimeEvidence: evidence,
|
|
40396
40558
|
forge,
|
|
40397
40559
|
extraDisposablePatterns: disposable
|
|
@@ -40452,7 +40614,7 @@ function readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies) {
|
|
|
40452
40614
|
}
|
|
40453
40615
|
const sources = (dependencies.readRuntimeSources ?? readRuntimeSources)(repoPath);
|
|
40454
40616
|
const cutoffEpoch = Math.floor(Date.now() / 1e3) - parseInactiveFor(inactiveFor).seconds;
|
|
40455
|
-
const gitDir = (0,
|
|
40617
|
+
const gitDir = (0, import_node_child_process48.spawnSync)(
|
|
40456
40618
|
"git",
|
|
40457
40619
|
["-C", worktreePath, "rev-parse", "--path-format=absolute", "--git-dir"],
|
|
40458
40620
|
{ encoding: "utf-8", env: READ_ONLY_GIT_ENV2 }
|
|
@@ -40472,7 +40634,7 @@ function classifyExactPath(repoPath, worktreePath, evidence, forge, extraDisposa
|
|
|
40472
40634
|
branch: worktree?.branch,
|
|
40473
40635
|
primary: worktrees[0] !== void 0 && sameWorkspacePath(worktrees[0].path, worktreePath),
|
|
40474
40636
|
locked: worktree?.locked ?? false,
|
|
40475
|
-
missing: !worktree || worktree.prunable || !
|
|
40637
|
+
missing: !worktree || worktree.prunable || !import_node_fs63.default.existsSync(worktreePath),
|
|
40476
40638
|
runtimeEvidence: evidence.runtimeEvidence,
|
|
40477
40639
|
forge,
|
|
40478
40640
|
extraDisposablePatterns
|
|
@@ -40498,7 +40660,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40498
40660
|
dependencies.listForge ?? ((identity2) => listForgeChanges(identity2))
|
|
40499
40661
|
);
|
|
40500
40662
|
const forge = evidence.status === "not-checked" ? { status: "unavailable", reason: "forge not checked" } : evidence;
|
|
40501
|
-
const disposable =
|
|
40663
|
+
const disposable = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.disposable ?? [] : [];
|
|
40502
40664
|
const paths = evidenceCache(
|
|
40503
40665
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
40504
40666
|
);
|
|
@@ -40517,7 +40679,7 @@ function prepareReclaimVerdicts(repo, inactiveFor, dependencies = {}) {
|
|
|
40517
40679
|
}
|
|
40518
40680
|
function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
40519
40681
|
const repoPath = resolveRepoPath(repo);
|
|
40520
|
-
const configured =
|
|
40682
|
+
const configured = import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
40521
40683
|
const patterns = configured?.trim ?? [];
|
|
40522
40684
|
const paths = evidenceCache(
|
|
40523
40685
|
(worktreePath) => readPathEvidence(repoPath, worktreePath, inactiveFor, dependencies)
|
|
@@ -40542,13 +40704,13 @@ function prepareTrimChecks(repo, inactiveFor, dependencies = {}) {
|
|
|
40542
40704
|
isActive: (worktreePath) => paths.last(worktreePath).active
|
|
40543
40705
|
};
|
|
40544
40706
|
}
|
|
40545
|
-
var
|
|
40707
|
+
var import_node_child_process48, import_node_fs63, import_node_path76, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
|
|
40546
40708
|
var init_workspace_cleanup = __esm({
|
|
40547
40709
|
"src/core/workspace-cleanup.ts"() {
|
|
40548
40710
|
"use strict";
|
|
40549
|
-
|
|
40550
|
-
|
|
40551
|
-
|
|
40711
|
+
import_node_child_process48 = require("child_process");
|
|
40712
|
+
import_node_fs63 = __toESM(require("fs"));
|
|
40713
|
+
import_node_path76 = __toESM(require("path"));
|
|
40552
40714
|
init_devpod_workspaces();
|
|
40553
40715
|
init_docker_leftovers();
|
|
40554
40716
|
init_duration();
|
|
@@ -40571,7 +40733,7 @@ var init_workspace_cleanup = __esm({
|
|
|
40571
40733
|
];
|
|
40572
40734
|
defaultCommandRunner = (command, args, input2) => {
|
|
40573
40735
|
const environment = command === "git" ? READ_ONLY_GIT_ENV2 : { ...process.env, LC_ALL: "C" };
|
|
40574
|
-
const result = (0,
|
|
40736
|
+
const result = (0, import_node_child_process48.spawnSync)(command, args, {
|
|
40575
40737
|
encoding: "utf-8",
|
|
40576
40738
|
env: environment,
|
|
40577
40739
|
...input2 === void 0 ? {} : { input: input2 }
|
|
@@ -40696,7 +40858,7 @@ function journalVetoes(record6) {
|
|
|
40696
40858
|
}
|
|
40697
40859
|
function readTraefikWindow(cutoffMs) {
|
|
40698
40860
|
const since = String(Math.floor(cutoffMs / 1e3));
|
|
40699
|
-
const run = (args, maxBuffer) => (0,
|
|
40861
|
+
const run = (args, maxBuffer) => (0, import_node_child_process49.spawnSync)("docker", ["logs", "--timestamps", ...args, ROUTER_CONTAINER_NAME], {
|
|
40700
40862
|
encoding: "utf-8",
|
|
40701
40863
|
maxBuffer,
|
|
40702
40864
|
...networkDockerOptions()
|
|
@@ -40865,13 +41027,13 @@ function setIdlePin(repoPath, pinned) {
|
|
|
40865
41027
|
}
|
|
40866
41028
|
);
|
|
40867
41029
|
}
|
|
40868
|
-
var
|
|
41030
|
+
var import_node_child_process49, import_node_fs64, import_node_path77, DEFAULT_IDLE_FOR, ACTIVITY_FILES, IdleStopSkipped, defaultDependencies;
|
|
40869
41031
|
var init_workspace_idle = __esm({
|
|
40870
41032
|
"src/core/workspace-idle.ts"() {
|
|
40871
41033
|
"use strict";
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
|
|
41034
|
+
import_node_child_process49 = require("child_process");
|
|
41035
|
+
import_node_fs64 = __toESM(require("fs"));
|
|
41036
|
+
import_node_path77 = __toESM(require("path"));
|
|
40875
41037
|
init_devpod_environment();
|
|
40876
41038
|
init_devpod_workspaces();
|
|
40877
41039
|
init_duration();
|
|
@@ -40892,7 +41054,7 @@ var init_workspace_idle = __esm({
|
|
|
40892
41054
|
readJournals: () => listReliabilityOperations(),
|
|
40893
41055
|
journalModifiedMs: (record6) => {
|
|
40894
41056
|
try {
|
|
40895
|
-
return
|
|
41057
|
+
return import_node_fs64.default.statSync(reliabilityOperationPath(record6.identity)).mtimeMs;
|
|
40896
41058
|
} catch {
|
|
40897
41059
|
return void 0;
|
|
40898
41060
|
}
|
|
@@ -40900,7 +41062,7 @@ var init_workspace_idle = __esm({
|
|
|
40900
41062
|
registryPaths: () => listMergedRuntimeWorkspaces().map((workspace) => workspace.source.localFolder),
|
|
40901
41063
|
inspectContainers: () => inspectWorkspaceContainers(),
|
|
40902
41064
|
statActivity: (containerId) => {
|
|
40903
|
-
const result = (0,
|
|
41065
|
+
const result = (0, import_node_child_process49.spawnSync)(
|
|
40904
41066
|
"docker",
|
|
40905
41067
|
["exec", containerId, "stat", "-c", "%Y", ...ACTIVITY_FILES],
|
|
40906
41068
|
{
|
|
@@ -40915,7 +41077,7 @@ var init_workspace_idle = __esm({
|
|
|
40915
41077
|
};
|
|
40916
41078
|
},
|
|
40917
41079
|
readTraefik: readTraefikWindow,
|
|
40918
|
-
isConfiguredCheckout: (repoPath) =>
|
|
41080
|
+
isConfiguredCheckout: (repoPath) => import_node_fs64.default.existsSync(import_node_path77.default.join(repoPath, ".devrouter.yml")),
|
|
40919
41081
|
gitCommonDir: (repoPath) => {
|
|
40920
41082
|
try {
|
|
40921
41083
|
return resolveGitCommonDir(repoPath);
|
|
@@ -41006,20 +41168,20 @@ function warnMissingWorkspaceOwnership(repoPath) {
|
|
|
41006
41168
|
);
|
|
41007
41169
|
}
|
|
41008
41170
|
function defaultWorktreePath(mainRepo, ws) {
|
|
41009
|
-
return
|
|
41171
|
+
return import_node_path78.default.join(mainRepo, "trees", ws);
|
|
41010
41172
|
}
|
|
41011
41173
|
function assertDefaultWorktreeRootIgnored(mainRepo) {
|
|
41012
|
-
const ignored = (0,
|
|
41174
|
+
const ignored = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
|
|
41013
41175
|
encoding: "utf-8"
|
|
41014
41176
|
});
|
|
41015
41177
|
if (ignored.status !== 0) {
|
|
41016
41178
|
throw new Error(
|
|
41017
|
-
`Default worktree root '${
|
|
41179
|
+
`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
41180
|
);
|
|
41019
41181
|
}
|
|
41020
41182
|
}
|
|
41021
41183
|
function legacyDefaultWorktreePath(mainRepo, ws) {
|
|
41022
|
-
return
|
|
41184
|
+
return import_node_path78.default.join(import_node_path78.default.dirname(mainRepo), `${import_node_path78.default.basename(mainRepo)}-${ws}`);
|
|
41023
41185
|
}
|
|
41024
41186
|
function teardownFallbackPath(mainRepo, workspace) {
|
|
41025
41187
|
const candidates = [
|
|
@@ -41131,7 +41293,7 @@ function assertFullDownPreflight(mainRepo, target) {
|
|
|
41131
41293
|
if (sameWorkspacePath(target.worktreePath, mainRepo)) {
|
|
41132
41294
|
throw new Error("Refusing to remove the primary Git checkout.");
|
|
41133
41295
|
}
|
|
41134
|
-
if (!target.worktree || target.worktree.prunable || !
|
|
41296
|
+
if (!target.worktree || target.worktree.prunable || !import_node_fs65.default.existsSync(target.worktreePath)) return;
|
|
41135
41297
|
if (target.worktree.locked) {
|
|
41136
41298
|
throw new Error(
|
|
41137
41299
|
`Worktree '${target.worktreePath}' is locked; unlock it before workspace down.`
|
|
@@ -41163,9 +41325,9 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41163
41325
|
(candidate) => defaultWorktreePath(mainRepo, candidate)
|
|
41164
41326
|
);
|
|
41165
41327
|
const generatedPath = candidatePaths.find(
|
|
41166
|
-
(candidate) => !
|
|
41328
|
+
(candidate) => !import_node_fs65.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
|
|
41167
41329
|
);
|
|
41168
|
-
const selectedPath = opts.path ?
|
|
41330
|
+
const selectedPath = opts.path ? import_node_path78.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
|
|
41169
41331
|
if (!selectedPath) {
|
|
41170
41332
|
throw new Error(`Could not allocate a collision-safe worktree path for branch '${branch}'.`);
|
|
41171
41333
|
}
|
|
@@ -41174,7 +41336,7 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41174
41336
|
`Branch '${branch}' already uses worktree '${existingBranch.path}', not '${selectedPath}'.`
|
|
41175
41337
|
);
|
|
41176
41338
|
}
|
|
41177
|
-
if (
|
|
41339
|
+
if (import_node_fs65.default.existsSync(selectedPath)) {
|
|
41178
41340
|
const registered = worktrees.find(
|
|
41179
41341
|
(worktree) => sameWorkspacePath(worktree.path, selectedPath)
|
|
41180
41342
|
);
|
|
@@ -41193,11 +41355,11 @@ async function workspaceUp(branch, opts = {}) {
|
|
|
41193
41355
|
return selectedPath;
|
|
41194
41356
|
}
|
|
41195
41357
|
if (!opts.path) assertDefaultWorktreeRootIgnored(mainRepo);
|
|
41196
|
-
const add2 = (0,
|
|
41358
|
+
const add2 = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
|
|
41197
41359
|
encoding: "utf-8"
|
|
41198
41360
|
});
|
|
41199
41361
|
if (add2.status !== 0) {
|
|
41200
|
-
const addNew = (0,
|
|
41362
|
+
const addNew = (0, import_node_child_process50.spawnSync)(
|
|
41201
41363
|
"git",
|
|
41202
41364
|
["-C", mainRepo, "worktree", "add", "-b", branch, selectedPath],
|
|
41203
41365
|
{ encoding: "utf-8" }
|
|
@@ -41337,8 +41499,8 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41337
41499
|
}
|
|
41338
41500
|
const result = await mutateWorkspaceRuntime("delete", resolved2, worktrees, opts.quiet);
|
|
41339
41501
|
if (removeWorktree) {
|
|
41340
|
-
if (resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41341
|
-
const rm = (0,
|
|
41502
|
+
if (resolved2.worktree && !resolved2.worktree.prunable && import_node_fs65.default.existsSync(resolved2.worktreePath)) {
|
|
41503
|
+
const rm = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved2.worktreePath], {
|
|
41342
41504
|
encoding: "utf-8"
|
|
41343
41505
|
});
|
|
41344
41506
|
if (rm.status !== 0) {
|
|
@@ -41356,7 +41518,7 @@ async function runWorkspaceLifecycle(action2, target, opts = {}) {
|
|
|
41356
41518
|
}
|
|
41357
41519
|
return result;
|
|
41358
41520
|
};
|
|
41359
|
-
return resolved2.worktree && !resolved2.worktree.prunable &&
|
|
41521
|
+
return resolved2.worktree && !resolved2.worktree.prunable && import_node_fs65.default.existsSync(resolved2.worktreePath) ? withLifecycleOperationLock(resolved2.worktreePath, operation) : operation();
|
|
41360
41522
|
}
|
|
41361
41523
|
async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRemove, steps) {
|
|
41362
41524
|
await withLifecycleOperationLock(worktreePath, async () => {
|
|
@@ -41382,7 +41544,7 @@ async function reclaimWorktreeExactPath(mainRepo, worktreePath, verify, afterRem
|
|
|
41382
41544
|
);
|
|
41383
41545
|
steps.push("runtime-deleted");
|
|
41384
41546
|
}
|
|
41385
|
-
const rm = (0,
|
|
41547
|
+
const rm = (0, import_node_child_process50.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", worktreePath], {
|
|
41386
41548
|
encoding: "utf-8"
|
|
41387
41549
|
});
|
|
41388
41550
|
if (rm.status !== 0) {
|
|
@@ -41403,13 +41565,13 @@ async function workspaceStop(target, opts = {}) {
|
|
|
41403
41565
|
async function workspaceDown(target, opts = {}) {
|
|
41404
41566
|
return runWorkspaceLifecycle("down", target, opts);
|
|
41405
41567
|
}
|
|
41406
|
-
var
|
|
41568
|
+
var import_node_child_process50, import_node_fs65, import_node_path78, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
|
|
41407
41569
|
var init_workspace_lifecycle = __esm({
|
|
41408
41570
|
"src/core/workspace-lifecycle.ts"() {
|
|
41409
41571
|
"use strict";
|
|
41410
|
-
|
|
41411
|
-
|
|
41412
|
-
|
|
41572
|
+
import_node_child_process50 = require("child_process");
|
|
41573
|
+
import_node_fs65 = __toESM(require("fs"));
|
|
41574
|
+
import_node_path78 = __toESM(require("path"));
|
|
41413
41575
|
init_devpod_mutation();
|
|
41414
41576
|
init_devpod_workspaces();
|
|
41415
41577
|
init_devsy_mutation();
|
|
@@ -41428,7 +41590,7 @@ var init_workspace_lifecycle = __esm({
|
|
|
41428
41590
|
|
|
41429
41591
|
// src/core/worktree-trim.ts
|
|
41430
41592
|
function listIgnoredPaths(worktreePath) {
|
|
41431
|
-
const result = (0,
|
|
41593
|
+
const result = (0, import_node_child_process51.spawnSync)(
|
|
41432
41594
|
"git",
|
|
41433
41595
|
[
|
|
41434
41596
|
"-C",
|
|
@@ -41512,19 +41674,19 @@ function buildTrimManifest(report, patterns, createdAtEpoch) {
|
|
|
41512
41674
|
return canonicalJson(manifest);
|
|
41513
41675
|
}
|
|
41514
41676
|
function isInside(parent, child) {
|
|
41515
|
-
const relative2 =
|
|
41516
|
-
return relative2 !== "" && !relative2.startsWith("..") && !
|
|
41677
|
+
const relative2 = import_node_path79.default.relative(parent, child);
|
|
41678
|
+
return relative2 !== "" && !relative2.startsWith("..") && !import_node_path79.default.isAbsolute(relative2);
|
|
41517
41679
|
}
|
|
41518
41680
|
function exists(file) {
|
|
41519
41681
|
try {
|
|
41520
|
-
|
|
41682
|
+
import_node_fs66.default.lstatSync(file);
|
|
41521
41683
|
return true;
|
|
41522
41684
|
} catch {
|
|
41523
41685
|
return false;
|
|
41524
41686
|
}
|
|
41525
41687
|
}
|
|
41526
41688
|
function hasTrackedFiles(worktreePath, relative2) {
|
|
41527
|
-
const result = (0,
|
|
41689
|
+
const result = (0, import_node_child_process51.spawnSync)(
|
|
41528
41690
|
"git",
|
|
41529
41691
|
["-C", worktreePath, "--literal-pathspecs", "ls-files", "-z", "--", relative2],
|
|
41530
41692
|
{ encoding: "utf-8", env: { ...process.env, GIT_OPTIONAL_LOCKS: "0" } }
|
|
@@ -41532,10 +41694,10 @@ function hasTrackedFiles(worktreePath, relative2) {
|
|
|
41532
41694
|
return result.status !== 0 || Boolean(result.error) || result.stdout.length > 0;
|
|
41533
41695
|
}
|
|
41534
41696
|
function trimOnePath(candidate, relative2, patterns, steps) {
|
|
41535
|
-
const target =
|
|
41697
|
+
const target = import_node_path79.default.join(candidate.path, relative2);
|
|
41536
41698
|
let stat;
|
|
41537
41699
|
try {
|
|
41538
|
-
stat =
|
|
41700
|
+
stat = import_node_fs66.default.lstatSync(target);
|
|
41539
41701
|
} catch (error) {
|
|
41540
41702
|
if (error.code === "ENOENT") {
|
|
41541
41703
|
steps.push(`gone:${relative2}`);
|
|
@@ -41547,7 +41709,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41547
41709
|
steps.push(`skipped-symlink:${relative2}`);
|
|
41548
41710
|
return;
|
|
41549
41711
|
}
|
|
41550
|
-
if (!isInside(
|
|
41712
|
+
if (!isInside(import_node_fs66.default.realpathSync.native(candidate.path), import_node_fs66.default.realpathSync.native(target))) {
|
|
41551
41713
|
steps.push(`skipped-outside:${relative2}`);
|
|
41552
41714
|
return;
|
|
41553
41715
|
}
|
|
@@ -41560,7 +41722,7 @@ function trimOnePath(candidate, relative2, patterns, steps) {
|
|
|
41560
41722
|
return;
|
|
41561
41723
|
}
|
|
41562
41724
|
try {
|
|
41563
|
-
|
|
41725
|
+
import_node_fs66.default.rmSync(target, { recursive: true, force: true });
|
|
41564
41726
|
} catch (error) {
|
|
41565
41727
|
steps.push(`partial:${relative2}`);
|
|
41566
41728
|
throw error;
|
|
@@ -41600,7 +41762,7 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41600
41762
|
continue;
|
|
41601
41763
|
}
|
|
41602
41764
|
const listed = candidate.paths ?? [];
|
|
41603
|
-
if (listed.every((relative2) => !exists(
|
|
41765
|
+
if (listed.every((relative2) => !exists(import_node_path79.default.join(candidate.path, relative2))) && matchingReceipt(candidate, manifestSha256)) {
|
|
41604
41766
|
outcome.status = "already-done";
|
|
41605
41767
|
continue;
|
|
41606
41768
|
}
|
|
@@ -41624,7 +41786,7 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41624
41786
|
if (!options.yes) {
|
|
41625
41787
|
verify();
|
|
41626
41788
|
outcome.status = "would-trim";
|
|
41627
|
-
const present = listed.filter((relative2) => exists(
|
|
41789
|
+
const present = listed.filter((relative2) => exists(import_node_path79.default.join(candidate.path, relative2)));
|
|
41628
41790
|
outcome.reason = present.length ? `would remove: ${present.join(", ")}` : "nothing present";
|
|
41629
41791
|
continue;
|
|
41630
41792
|
}
|
|
@@ -41661,13 +41823,13 @@ async function applyTrimManifest(options, dependencies) {
|
|
|
41661
41823
|
}
|
|
41662
41824
|
return { manifestSha256, dryRun: !options.yes, targets, stoppedEarly };
|
|
41663
41825
|
}
|
|
41664
|
-
var
|
|
41826
|
+
var import_node_child_process51, import_node_fs66, import_node_path79;
|
|
41665
41827
|
var init_worktree_trim = __esm({
|
|
41666
41828
|
"src/core/worktree-trim.ts"() {
|
|
41667
41829
|
"use strict";
|
|
41668
|
-
|
|
41669
|
-
|
|
41670
|
-
|
|
41830
|
+
import_node_child_process51 = require("child_process");
|
|
41831
|
+
import_node_fs66 = __toESM(require("fs"));
|
|
41832
|
+
import_node_path79 = __toESM(require("path"));
|
|
41671
41833
|
init_reliability_lifecycle();
|
|
41672
41834
|
init_worktree_reclaim();
|
|
41673
41835
|
init_worktree_safety();
|
|
@@ -41735,7 +41897,7 @@ function runWorkspaceLsCommand(options) {
|
|
|
41735
41897
|
}
|
|
41736
41898
|
function writeManifestOutput(manifest, output2) {
|
|
41737
41899
|
if (output2) {
|
|
41738
|
-
|
|
41900
|
+
import_node_fs67.default.writeFileSync(output2, manifest, { flag: "wx" });
|
|
41739
41901
|
process.stdout.write(`${sha256Hex(manifest)} ${output2}
|
|
41740
41902
|
`);
|
|
41741
41903
|
} else {
|
|
@@ -41765,7 +41927,7 @@ function runWorkspaceCleanupCommand(options) {
|
|
|
41765
41927
|
throw new Error("--manifest requires --all-worktrees and --check-merged.");
|
|
41766
41928
|
}
|
|
41767
41929
|
const createdAtEpoch = Math.floor(Date.now() / 1e3);
|
|
41768
|
-
const worktrees =
|
|
41930
|
+
const worktrees = import_node_fs67.default.existsSync(import_node_path80.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
|
|
41769
41931
|
const manifest = action2 === "trim" ? buildTrimManifest(
|
|
41770
41932
|
report,
|
|
41771
41933
|
{ trim: worktrees?.trim ?? [], disposable: worktrees?.disposable },
|
|
@@ -41803,7 +41965,7 @@ async function runWorkspaceIdleCommand(options) {
|
|
|
41803
41965
|
if (options.stop) {
|
|
41804
41966
|
const paths = idleSweepPaths();
|
|
41805
41967
|
if (!process.stderr.isTTY) muteLifecycleProgressHeartbeat();
|
|
41806
|
-
|
|
41968
|
+
import_node_fs67.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
|
|
41807
41969
|
const result = await withFileLock(paths.lock, { activity: "idle sweep" }, async () => {
|
|
41808
41970
|
try {
|
|
41809
41971
|
const swept = await stopIdleEnvironments(
|
|
@@ -41905,7 +42067,7 @@ async function runWorkspaceJournalSettleCommand(options) {
|
|
|
41905
42067
|
function runWorkspaceManifestHashCommand(file) {
|
|
41906
42068
|
let leftover = false;
|
|
41907
42069
|
try {
|
|
41908
|
-
leftover = isLeftoverManifest(JSON.parse(
|
|
42070
|
+
leftover = isLeftoverManifest(JSON.parse(import_node_fs67.default.readFileSync(file, "utf-8")));
|
|
41909
42071
|
} catch {
|
|
41910
42072
|
}
|
|
41911
42073
|
const { raw } = leftover ? readLeftoverManifest(file) : readManifest(file);
|
|
@@ -42002,12 +42164,12 @@ async function runWorkspaceTrimCommand(options) {
|
|
|
42002
42164
|
process.exitCode = 1;
|
|
42003
42165
|
}
|
|
42004
42166
|
}
|
|
42005
|
-
var
|
|
42167
|
+
var import_node_fs67, import_node_path80;
|
|
42006
42168
|
var init_workspace2 = __esm({
|
|
42007
42169
|
"src/commands/workspace.ts"() {
|
|
42008
42170
|
"use strict";
|
|
42009
|
-
|
|
42010
|
-
|
|
42171
|
+
import_node_fs67 = __toESM(require("fs"));
|
|
42172
|
+
import_node_path80 = __toESM(require("path"));
|
|
42011
42173
|
init_docker_leftovers();
|
|
42012
42174
|
init_file_lock();
|
|
42013
42175
|
init_idle_sweep();
|
|
@@ -42065,7 +42227,7 @@ var init_version = __esm({
|
|
|
42065
42227
|
|
|
42066
42228
|
// src/cli.ts
|
|
42067
42229
|
var import_commander = require("commander");
|
|
42068
|
-
var CLI_VERSION = true ? "0.6.
|
|
42230
|
+
var CLI_VERSION = true ? "0.6.2" : "0.0.0-dev";
|
|
42069
42231
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
42070
42232
|
function withErrorHandling(action2) {
|
|
42071
42233
|
return async (...args) => {
|
|
@@ -42159,7 +42321,7 @@ program.command("up").description("Ensure devnet and start shared Traefik (reser
|
|
|
42159
42321
|
await runUpCommand2();
|
|
42160
42322
|
})
|
|
42161
42323
|
);
|
|
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(
|
|
42324
|
+
program.command("ensure").description("Start and prove a primary or linked checkout's environment and routes").argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42163
42325
|
withErrorHandling(async (repoPath, _options, command) => {
|
|
42164
42326
|
const options = command.opts();
|
|
42165
42327
|
const { runEnsureCommand: runEnsureCommand2 } = await Promise.resolve().then(() => (init_ensure(), ensure_exports));
|
|
@@ -42168,6 +42330,7 @@ program.command("ensure").description("Start and prove a primary or linked check
|
|
|
42168
42330
|
profile: options.profile,
|
|
42169
42331
|
variant: options.variant,
|
|
42170
42332
|
repair: options.repair,
|
|
42333
|
+
initializeNew: options.initializeNew,
|
|
42171
42334
|
open: Boolean(options.open),
|
|
42172
42335
|
json: Boolean(options.json)
|
|
42173
42336
|
});
|
|
@@ -42432,7 +42595,7 @@ workspaceCommand2.command("up").description(
|
|
|
42432
42595
|
);
|
|
42433
42596
|
workspaceCommand2.command("ensure").description(
|
|
42434
42597
|
"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(
|
|
42598
|
+
).argument("[path]", "Git checkout path (defaults to current directory)").option("--profile <name>", "Start only this profile's apps/dependencies from .devrouter.yml").option("--variant <name>", "Select a declared managed runtime variant").option("--repair", "Repair a degraded managed runtime from its recorded profile").option("--initialize-new", "Initialize one fresh disposable managed environment explicitly").option("--open", "Open HTTP routes after readiness succeeds").option("--json", "Output JSON").action(
|
|
42436
42599
|
withErrorHandling(
|
|
42437
42600
|
async (worktreePath, _options, command) => {
|
|
42438
42601
|
const options = command.opts();
|
|
@@ -42442,6 +42605,7 @@ workspaceCommand2.command("ensure").description(
|
|
|
42442
42605
|
profile: options.profile,
|
|
42443
42606
|
variant: options.variant,
|
|
42444
42607
|
repair: options.repair,
|
|
42608
|
+
initializeNew: options.initializeNew,
|
|
42445
42609
|
open: Boolean(options.open),
|
|
42446
42610
|
json: Boolean(options.json)
|
|
42447
42611
|
});
|
|
@@ -42588,10 +42752,10 @@ workspaceCommand2.command("down").description("Delete a workspace's runtime and
|
|
|
42588
42752
|
workspaceCommand2.command("journal").description("Inspect and recover workspace lifecycle journals").command("settle").description(
|
|
42589
42753
|
"Settle an interrupted lifecycle operation as unobservable so ensure and stop can proceed"
|
|
42590
42754
|
).argument("[path]", "Checkout path (defaults to current directory)").option("--json", "Output JSON").action(
|
|
42591
|
-
withErrorHandling(async (
|
|
42755
|
+
withErrorHandling(async (path80, _options, command) => {
|
|
42592
42756
|
const options = command.opts();
|
|
42593
42757
|
const { runWorkspaceJournalSettleCommand: runWorkspaceJournalSettleCommand2 } = await Promise.resolve().then(() => (init_workspace2(), workspace_exports));
|
|
42594
|
-
await runWorkspaceJournalSettleCommand2({ ...
|
|
42758
|
+
await runWorkspaceJournalSettleCommand2({ ...path80 ? { path: path80 } : {}, ...options });
|
|
42595
42759
|
})
|
|
42596
42760
|
);
|
|
42597
42761
|
function parseVersionRequest(argv) {
|