@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.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.1" : "0.0.0-dev";
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.1" : "0.0.0-dev";
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")) invalidRequest();
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, import_node_child_process20.spawnSync)("docker", ["port", containerId, `${target}/tcp`], {
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, import_node_crypto18.createHash)("sha256").update(JSON.stringify(canonical)).digest("hex");
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 import_node_child_process20, import_node_crypto18, PORT_LOOKUP_TIMEOUT_MS, PORT_LOOKUP_MAX_BUFFER, LOOPBACK_BINDING;
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
- import_node_child_process20 = require("child_process");
15084
- import_node_crypto18 = require("crypto");
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 (!import_node_fs31.default.existsSync(filePath) || !import_node_fs31.default.lstatSync(filePath).isFile()) return void 0;
15096
- return import_node_fs31.default.readFileSync(filePath);
15280
+ if (!import_node_fs32.default.existsSync(filePath) || !import_node_fs32.default.lstatSync(filePath).isFile()) return void 0;
15281
+ return import_node_fs32.default.readFileSync(filePath);
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, import_node_crypto19.createHash)("sha256").update(adapter).digest("hex");
15287
+ return (0, import_node_crypto20.createHash)("sha256").update(adapter).digest("hex");
15103
15288
  }
15104
15289
  function resolveManagedPostStartPlan(repoPath) {
15105
- const adapterPath = import_node_path39.default.join(repoPath, MANAGED_ADAPTER_PATH);
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 = import_node_path39.default.join(repoPath, ".devcontainer", "Dockerfile");
15109
- const devcontainerPath = import_node_path39.default.join(repoPath, ".devcontainer", "devcontainer.json");
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, import_node_child_process21.spawnSync)(
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 import_node_child_process21, import_node_crypto19, import_node_fs31, import_node_path39, MANAGED_MARKER, MANAGED_ADAPTER_PATH, RUNTIME_HELPER_PATH;
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
- import_node_child_process21 = require("child_process");
15197
- import_node_crypto19 = require("crypto");
15198
- import_node_fs31 = __toESM(require("fs"));
15199
- import_node_path39 = __toESM(require("path"));
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 = import_node_fs32.default.lstatSync(directory);
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 import_node_path40.default.join(
16254
+ return import_node_path41.default.join(
16113
16255
  DEVROUTER_HOME,
16114
16256
  "lifecycle-diagnostics",
16115
- `${(0, import_node_crypto20.createHash)("sha256").update(identity2.repoPath).digest("hex")}.json`
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(import_node_path40.default.dirname(file))) return void 0;
16123
- descriptor = import_node_fs32.default.openSync(
16264
+ if (!privateDirectory(import_node_path41.default.dirname(file))) return void 0;
16265
+ descriptor = import_node_fs33.default.openSync(
16124
16266
  file,
16125
- import_node_fs32.default.constants.O_RDONLY | import_node_fs32.default.constants.O_NOFOLLOW | import_node_fs32.default.constants.O_NONBLOCK
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 = import_node_fs32.default.fstatSync(descriptor);
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 = import_node_fs32.default.readSync(descriptor, buffer, 0, buffer.length, 0);
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, import_node_util11.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)
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) import_node_fs32.default.closeSync(descriptor);
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, import_node_util11.isDeepStrictEqual)(before, after) || !(0, import_node_util11.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(
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 import_node_crypto20, import_node_fs32, import_node_path40, import_node_util11, MAX_TAIL_BYTES, MAX_RECEIPT_BYTES, PACKAGE_TASK, LifecycleDiagnosticRecorder;
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
- import_node_crypto20 = require("crypto");
16191
- import_node_fs32 = __toESM(require("fs"));
16192
- import_node_path40 = __toESM(require("path"));
16193
- import_node_util11 = require("util");
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, import_node_util11.stripVTControlCharacters)(raw).trim();
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, import_node_util11.isDeepStrictEqual)(reliabilityFence(record6.state), this.request.fence) || record6.worker && record6.worker.id !== this.request.workerId)
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
- import_node_fs32.default.mkdirSync(import_node_path40.default.dirname(file), { recursive: true, mode: 448 });
16288
- if (!privateDirectory(import_node_path40.default.dirname(file))) return;
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 import_node_fs33.default.readdirSync("/proc")) {
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 = import_node_fs33.default.readFileSync(`/proc/${entry}/stat`, "utf8");
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 = import_node_path41.default.join(__dirname, "devrouter-lifecycle-worker.js");
16357
- if (!import_node_fs33.default.existsSync(workerPath))
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, import_node_child_process22.fork)(workerPath, [], {
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, import_node_crypto21.randomUUID)(), operationId: (0, import_node_crypto21.randomUUID)(), workerId: (0, import_node_crypto21.randomUUID)() };
16790
+ return { requestId: (0, import_node_crypto22.randomUUID)(), operationId: (0, import_node_crypto22.randomUUID)(), workerId: (0, import_node_crypto22.randomUUID)() };
16649
16791
  }
16650
- var import_node_child_process22, import_node_crypto21, import_node_fs33, import_node_path41, OUTPUT_BUFFER_LIMIT, DEFAULT_OUTPUT_PAGE_BYTES, LifecycleOutput, LifecycleWorkerAdmissionBusyError;
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
- import_node_child_process22 = require("child_process");
16655
- import_node_crypto21 = require("crypto");
16656
- import_node_fs33 = __toESM(require("fs"));
16657
- import_node_path41 = __toESM(require("path"));
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
- import_node_fs34.default.mkdirSync(DEVROUTER_HOME, { recursive: true });
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, import_node_child_process23.spawnSync)("devpod", [...args, ...binding.args], {
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 import_node_child_process23, import_node_fs34, import_node_path42, DEVPOD_MUTATION_LOCK_FILE, DEVPOD_MUTATION_WAIT_MS;
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
- import_node_child_process23 = require("child_process");
16871
- import_node_fs34 = __toESM(require("fs"));
16872
- import_node_path42 = __toESM(require("path"));
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 = import_node_path42.default.join(DEVROUTER_HOME, "devpod-mutation.lock");
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, import_node_child_process24.spawnSync)("docker", args, {
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, import_node_child_process24.spawnSync)(
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 (import_node_path43.default.basename(workingDir) !== ".devcontainer") return void 0;
17088
- return comparableWorkspacePath(import_node_path43.default.dirname(workingDir));
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 = import_node_path43.default.join(options.repoPath, ".devcontainer");
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 import_node_child_process24, import_node_path43, 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;
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
- import_node_child_process24 = require("child_process");
17150
- import_node_path43 = __toESM(require("path"));
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, import_node_child_process25.spawnSync)("curl", args, { encoding: "utf-8" });
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, import_node_child_process25.spawnSync)("curl", args, {
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 import_node_child_process25, DEFAULT_MAX_TIME_SECONDS, CONTROLLER_CURL_MAX_TIME_SECONDS, PARENT_TIMEOUT_PADDING_MS, CONTRACT_MAX_BUFFER, MIME_TOKEN_RE2;
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
- import_node_child_process25 = require("child_process");
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 import_node_child_process26, import_node_fs35;
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
- import_node_child_process26 = require("child_process");
17330
- import_node_fs35 = __toESM(require("fs"));
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, import_node_child_process27.spawnSync)("docker", ["exec", containerId, "cat", "/proc/self/mountinfo"], {
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 import_node_child_process27, NESTED_MOUNT_REASON, UNREADABLE_MOUNT_REASON;
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
- import_node_child_process27 = require("child_process");
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, import_node_child_process28.spawnSync)("docker", ["--host", endpoint, ...args], {
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 import_node_child_process28, NetworkInventoryError, MAX_IDS, MAX_OUTPUT_BYTES, FULL_ID, NETWORK_TEMPLATE, CONTAINER_TEMPLATE;
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
- import_node_child_process28 = require("child_process");
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 = import_node_fs36.default.readFileSync(import_node_path44.default.join(procRoot, "net/unix"), "utf8");
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 = import_node_fs36.default.readlinkSync(import_node_path44.default.join(procRoot, "self/ns/net"));
18532
- const pids = import_node_fs36.default.readdirSync(procRoot).filter((name) => /^\d+$/.test(name));
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 = import_node_path44.default.join(procRoot, pid);
18538
- if (import_node_path44.default.basename(import_node_fs36.default.readlinkSync(import_node_path44.default.join(root, "exe"))) !== "dockerd") continue;
18539
- if (import_node_fs36.default.readlinkSync(import_node_path44.default.join(root, "ns/net")) !== ownNamespace) continue;
18540
- const descriptors = import_node_fs36.default.readdirSync(import_node_path44.default.join(root, "fd"));
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 import_node_fs36.default.readlinkSync(import_node_path44.default.join(root, "fd", fd)) === inode;
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 import_node_fs36, import_node_path44;
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
- import_node_fs36 = __toESM(require("fs"));
18564
- import_node_path44 = __toESM(require("path"));
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, import_node_child_process29.spawnSync)("ip", ["-j", "-4", "route", "show", "table", "all"], {
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 import_node_child_process29, import_node_net3;
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
- import_node_child_process29 = require("child_process");
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 import_node_crypto22;
18914
+ var import_node_crypto23;
18773
18915
  var init_network_compose = __esm({
18774
18916
  "src/core/network-compose.ts"() {
18775
18917
  "use strict";
18776
- import_node_crypto22 = require("crypto");
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 = import_node_path45.default.join(plan.composeDirectory, OVERLAY);
18785
- const ignored = (0, import_node_child_process30.spawnSync)("git", [
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
- ${import_yaml4.default.stringify(overlay.overlay)}`;
18939
+ ${import_yaml5.default.stringify(overlay.overlay)}`;
18798
18940
  const assertOwnership = () => {
18799
- if (!import_node_fs37.default.existsSync(overlayPath)) return;
18800
- const stat = import_node_fs37.default.lstatSync(overlayPath);
18801
- if (!stat.isFile() || stat.size > MAX_BYTES3 || import_node_fs37.default.readFileSync(overlayPath, "utf8") !== bytes2)
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, import_node_crypto23.createHash)("sha256").update(contents).digest("hex")
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 import_node_child_process30, import_node_crypto23, import_node_fs37, import_node_path45, import_yaml4, OVERLAY, MARKER, MAX_BYTES3;
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
- import_node_child_process30 = require("child_process");
18830
- import_node_crypto23 = require("crypto");
18831
- import_node_fs37 = __toESM(require("fs"));
18832
- import_node_path45 = __toESM(require("path"));
18833
- import_yaml4 = __toESM(require("yaml"));
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 import_node_child_process31;
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
- import_node_child_process31 = require("child_process");
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 import_node_crypto24;
19006
+ var import_node_crypto25;
18865
19007
  var init_network_managed = __esm({
18866
19008
  "src/core/network-managed.ts"() {
18867
19009
  "use strict";
18868
- import_node_crypto24 = require("crypto");
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 import_node_child_process32, import_node_fs38, import_node_path46;
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
- import_node_child_process32 = require("child_process");
18943
- import_node_fs38 = __toESM(require("fs"));
18944
- import_node_path46 = __toESM(require("path"));
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: { profile: input2.profile, quiet: true },
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 = import_node_path47.default.join(DEVROUTER_HOME, "controller")) {
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, import_node_util12.isDeepStrictEqual)(state.operation, intent.recordedOperation)) return false;
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 ?? import_node_path47.default.join(DEVROUTER_HOME, "controller");
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, import_node_util12.isDeepStrictEqual)(target.totals, binding.execSteady?.totals))
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, import_node_util12.isDeepStrictEqual)(retained, target)) return null;
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, import_node_util12.isDeepStrictEqual)(record6.phaseSettlement, marker))
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, import_node_util12.isDeepStrictEqual)(record6.phaseSettlement, pending))
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 = import_node_path47.default.join(DEVROUTER_HOME, "controller"), controller, admission) {
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, import_node_util12.isDeepStrictEqual)(binding.execSteady, receipt))
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, import_node_util12.isDeepStrictEqual)(retained.totals, totals)) {
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(import_node_path47.default.join(DEVROUTER_HOME, "controller"));
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 = import_node_path47.default.join(DEVROUTER_HOME, "controller");
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, import_node_crypto25.randomUUID)(),
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 ?? [] } : { ...binding, requestId: input2.requestId, kind: "ensure" },
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 = import_node_path47.default.join(DEVROUTER_HOME, "controller"), nowMs = Date.now()) {
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 = import_node_path47.default.join(DEVROUTER_HOME, "controller")) {
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 import_node_crypto25, import_node_path47, import_node_util12, activeWorker, lockHeld, BUSY_LIFECYCLE_WAIT_MS, BUSY_LIFECYCLE_POLL_MS, CAPACITY_CLIENT_WAIT_MS, BUSY_LIFECYCLE_PROGRESS_MS;
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
- import_node_crypto25 = require("crypto");
19908
- import_node_path47 = __toESM(require("path"));
19909
- import_node_util12 = require("util");
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 import_node_util13, CapacityQueue;
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
- import_node_util13 = require("util");
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, import_node_util13.isDeepStrictEqual)(existingRequest, incomingRequest) || !(0, import_node_util13.isDeepStrictEqual)(existing.reservation, reservation) || !(0, import_node_util13.isDeepStrictEqual)(existing.admission, admission) || existing.autoResume !== autoResume)
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, import_node_util13.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) {
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, import_node_child_process33.spawnSync)("/usr/sbin/sysctl", ["-n", "kern.wake_abs_time"], {
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 import_node_child_process33;
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
- import_node_child_process33 = require("child_process");
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, import_node_util14.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy);
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, import_node_crypto26.randomBytes)(32);
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, import_node_util14.isDeepStrictEqual)(readCapacityPolicy(options.directory), policy)) return;
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(import_node_path48.default.join(enrollment.repoPath, ".devrouter.yml"));
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, import_node_util14.isDeepStrictEqual)(current, policy)) return void 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, import_node_util14.isDeepStrictEqual)(resolved2.environment, environment)) return void 0;
20604
- if (!(0, import_node_util14.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return void 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, import_node_util14.isDeepStrictEqual)(entry, resolved2.enrollment)))
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, import_node_util14.isDeepStrictEqual)(current, policy)) return false;
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, import_node_crypto26.randomUUID)(),
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, import_node_util14.isDeepStrictEqual)(current, policy))
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, import_node_util14.isDeepStrictEqual)(resolved2.environment, environment) || signal.aborted)
20899
+ if (!(0, import_node_util15.isDeepStrictEqual)(resolved2.environment, environment) || signal.aborted)
20742
20900
  throw new Error("Capacity submission binding changed.");
20743
- if (!(0, import_node_util14.isDeepStrictEqual)(readCapacityPolicy(options.directory), current))
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, import_node_util14.isDeepStrictEqual)(entry, resolved2.enrollment)))
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, import_node_crypto26.createHmac)("sha256", payloadKey).update(
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, import_node_crypto26.randomUUID)(),
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, import_node_util14.isDeepStrictEqual)(current, policy)) return;
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, import_node_util14.isDeepStrictEqual)(resolved2.environment, environment)) return;
20901
- if (!(0, import_node_util14.isDeepStrictEqual)(readCapacityPolicy(options.directory), current)) return;
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, import_node_util14.isDeepStrictEqual)(entry, resolved2.enrollment)))
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, import_node_crypto26.randomUUID)()}`
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, import_node_crypto26.randomUUID)(),
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 import_node_crypto26, import_node_path48, import_node_util14;
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
- import_node_crypto26 = require("crypto");
20999
- import_node_path48 = __toESM(require("path"));
21000
- import_node_util14 = require("util");
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, import_node_crypto27.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
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 = import_node_path49.default.join(environment.repoPath, ".devcontainer/devcontainer.json");
21319
+ const sourcePath = import_node_path50.default.join(environment.repoPath, ".devcontainer/devcontainer.json");
21160
21320
  const files = [
21161
- import_node_path49.default.join(commonDir, "devrouter/workspaces", `${environment.workspace}.json`),
21162
- import_node_path49.default.join(environment.repoPath, ".devrouter.yml"),
21163
- import_node_path49.default.join(gitDir, "devrouter-workspace"),
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
- import_node_path49.default.join(environment.repoPath, MANAGED_DEVCONTAINER_PATH)
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, import_node_crypto27.createHash)("sha256").update(persisted.contents[4]).digest("hex") !== state.sourceConfigSha256 || (0, import_node_crypto27.createHash)("sha256").update(persisted.contents[5]).digest("hex") !== state.effectiveConfigSha256)
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 = import_node_path49.default.join(environment.repoPath, ".devcontainer");
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) => !import_node_path49.default.isAbsolute(file)) || !hasExactComposeIdentity(container, {
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 import_node_crypto27, import_node_path49, OBSERVATION_INSPECT_TEMPLATE;
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
- import_node_crypto27 = require("crypto");
21360
- import_node_path49 = __toESM(require("path"));
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 import_node_crypto28, import_node_util15, ControllerSessions;
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
- import_node_crypto28 = require("crypto");
21389
- import_node_util15 = require("util");
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, import_node_util15.isDeepStrictEqual)(shared, environment))
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, import_node_crypto28.randomUUID)(),
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, import_node_util15.isDeepStrictEqual)(retained.environment, environment) || !(0, import_node_util15.isDeepStrictEqual)([...retained.requirements].sort(), required))
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, import_node_crypto28.randomUUID)(),
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 = import_node_path50.default.resolve(directory);
21771
- let current = import_node_path50.default.parse(absolute2).root;
21772
- for (const part of absolute2.slice(current.length).split(import_node_path50.default.sep)) {
21773
- current = import_node_path50.default.join(current, part);
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 = import_node_fs39.default.lstatSync(current);
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
- import_node_fs39.default.mkdirSync(current, { mode: 448 });
21940
+ import_node_fs40.default.mkdirSync(current, { mode: 448 });
21781
21941
  }
21782
21942
  }
21783
- const stat = import_node_fs39.default.lstatSync(absolute2);
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 = import_node_fs39.default.lstatSync(file);
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 = import_node_path50.default.join(options.directory, "control.sock");
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 = import_node_path50.default.join(options.directory, "owner.lock");
21972
+ const lockPath = import_node_path51.default.join(options.directory, "owner.lock");
21813
21973
  try {
21814
- const stat = import_node_fs39.default.lstatSync(lockPath);
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) import_node_fs39.default.unlinkSync(socketPath);
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
- import_node_fs39.default.chmodSync(socketPath, 384);
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 import_node_fs39, import_node_net4, import_node_path50, FRAME_BYTES;
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
- import_node_fs39 = __toESM(require("fs"));
22554
+ import_node_fs40 = __toESM(require("fs"));
22395
22555
  import_node_net4 = __toESM(require("net"));
22396
- import_node_path50 = __toESM(require("path"));
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 = import_node_path51.default.join(DEVROUTER_HOME, "controller");
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: import_node_path51.default.resolve(repo) } : {} },
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 import_node_path51;
22636
+ var import_node_path52;
22477
22637
  var init_controller = __esm({
22478
22638
  "src/commands/controller.ts"() {
22479
22639
  "use strict";
22480
- import_node_path51 = __toESM(require("path"));
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 ?? import_node_path52.default.join(DEVROUTER_HOME, "controller");
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 import_node_path52, POOL_PROBE_TIMEOUT_MS, CapacityReconcileRefusal;
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
- import_node_path52 = __toESM(require("path"));
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, import_node_path53.join)(repoPath, relPath);
22681
- (0, import_node_fs40.mkdirSync)((0, import_node_path53.dirname)(absolutePath), { recursive: true });
22682
- (0, import_node_fs40.writeFileSync)(absolutePath, content, "utf-8");
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, import_node_path53.join)(repoPath, AGENTS_MD);
22687
- if ((0, import_node_fs40.existsSync)(filePath)) {
22688
- const content = (0, import_node_fs40.readFileSync)(filePath, "utf-8");
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, import_node_fs40.writeFileSync)(filePath, updated, "utf-8");
22852
+ (0, import_node_fs41.writeFileSync)(filePath, updated, "utf-8");
22693
22853
  return { path: filePath, written: true };
22694
22854
  }
22695
- (0, import_node_fs40.writeFileSync)(filePath, `${content.trimEnd()}
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, import_node_fs40.writeFileSync)(filePath, `# AGENTS.md
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 import_node_fs40, import_node_path53, DEVROUTER_SENTINEL, DEVROUTER_END_SENTINEL, LEGACY_DEVROUTER_SECTION_END, AGENTS_MD, DEVROUTER_SKILL_REL_PATH, DEVROUTER_SKILL_CONTENT;
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
- import_node_fs40 = require("fs");
22716
- import_node_path53 = require("path");
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 (!import_node_fs41.default.existsSync(promptDirPath)) {
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 = import_node_fs41.default.readdirSync(promptDirPath, { withFileTypes: true });
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 = import_node_path54.default.join(promptDirPath, file.name);
24240
- const prompt = import_node_fs41.default.readFileSync(promptPath, "utf-8").trim();
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 import_node_path54.default.resolve(explicitPath);
24422
+ return import_node_path55.default.resolve(explicitPath);
24262
24423
  }
24263
- const entryFile = process.argv[1] ? import_node_path54.default.resolve(process.argv[1]) : __filename;
24264
- const entryDir = import_node_path54.default.dirname(entryFile);
24265
- const resolvedEntryDir = import_node_fs41.default.existsSync(entryFile) ? import_node_path54.default.dirname(import_node_fs41.default.realpathSync(entryFile)) : entryDir;
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
- import_node_path54.default.resolve(resolvedEntryDir, "..", UPGRADE_PROMPTS_DIR),
24268
- import_node_path54.default.resolve(entryDir, "..", UPGRADE_PROMPTS_DIR),
24269
- import_node_path54.default.resolve(__dirname, "..", UPGRADE_PROMPTS_DIR),
24270
- import_node_path54.default.resolve(__dirname, "..", "..", UPGRADE_PROMPTS_DIR),
24271
- import_node_path54.default.resolve(process.cwd(), UPGRADE_PROMPTS_DIR)
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) => import_node_fs41.default.existsSync(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 import_node_fs41, import_node_path54, SEMVER_RE, UPGRADE_PROMPTS_DIR;
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
- import_node_fs41 = __toESM(require("fs"));
24294
- import_node_path54 = __toESM(require("path"));
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 (!import_node_fs42.default.existsSync(composeFile)) {
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 = import_node_fs42.default.readFileSync(composeFile, "utf-8");
24457
- const parsed = import_yaml5.default.parse(raw);
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 = import_node_path55.default.join(repoPath, ".devcontainer");
24554
- if (!import_node_fs42.default.existsSync(devcontainerDir)) {
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(import_node_path55.default.join(devcontainerDir, "docker-compose.yml"), workspace);
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 = import_node_path55.default.join(devcontainerDir, "Dockerfile");
24585
- const dockerfileExists = import_node_fs42.default.existsSync(dockerfilePath);
24586
- const dockerfile = dockerfileExists ? import_node_fs42.default.readFileSync(dockerfilePath, "utf-8") : "";
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 import_node_fs42, import_node_path55, import_yaml5;
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
- import_node_fs42 = __toESM(require("fs"));
24649
- import_node_path55 = __toESM(require("path"));
24650
- import_yaml5 = __toESM(require("yaml"));
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 import_node_fs43;
24906
+ var import_node_fs44;
24746
24907
  var init_route_state = __esm({
24747
24908
  "src/core/route-state.ts"() {
24748
24909
  "use strict";
24749
- import_node_fs43 = __toESM(require("fs"));
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 = import_node_fs44.default.existsSync(configPath);
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 import_node_fs44;
25238
+ var import_node_fs45;
25078
25239
  var init_status = __esm({
25079
25240
  "src/core/status.ts"() {
25080
25241
  "use strict";
25081
- import_node_fs44 = __toESM(require("fs"));
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 = import_node_os6.default.homedir(), devrouterHome = DEVROUTER_HOME) {
25092
- const directory = import_node_path56.default.join(devrouterHome, "idle");
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: import_node_path56.default.join(home, "Library", "LaunchAgents", `${IDLE_SWEEP_LABEL}.plist`),
25255
+ plist: import_node_path57.default.join(home, "Library", "LaunchAgents", `${IDLE_SWEEP_LABEL}.plist`),
25095
25256
  directory,
25096
- log: import_node_path56.default.join(directory, "sweep.log"),
25097
- lastSweep: import_node_path56.default.join(directory, "last-sweep.json"),
25098
- lock: import_node_path56.default.join(directory, "sweep.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 = import_node_fs45.default.readFileSync(plistPath, "utf-8");
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, import_node_child_process34.spawnSync)("/bin/sh", ["-c", `command -v ${name}`], { encoding: "utf-8" });
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) => import_node_path56.default.dirname(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 ?? import_node_fs45.default.realpathSync(process.argv[1]);
25177
- import_node_fs45.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
25178
- import_node_fs45.default.mkdirSync(import_node_path56.default.dirname(paths.plist), { recursive: true });
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
- import_node_fs45.default.writeFileSync(paths.plist, contents, { mode: 420 });
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 (!import_node_fs45.default.existsSync(paths.plist)) return false;
25358
+ if (!import_node_fs46.default.existsSync(paths.plist)) return false;
25198
25359
  (input2.launchctl ?? defaultLaunchctl)(["bootout", `${launchDomain()}/${IDLE_SWEEP_LABEL}`]);
25199
- import_node_fs45.default.rmSync(paths.plist, { force: true });
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
- import_node_fs45.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
25215
- import_node_fs45.default.writeFileSync(paths.lastSweep, `${JSON.stringify(record6, null, 2)}
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(import_node_fs45.default.readFileSync(paths.lastSweep, "utf-8"));
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 import_node_child_process34, import_node_fs45, import_node_os6, import_node_path56, IDLE_SWEEP_LABEL, SWEEP_INTERVAL_SECONDS, SYSTEM_PATH, defaultLaunchctl;
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
- import_node_child_process34 = require("child_process");
25270
- import_node_fs45 = __toESM(require("fs"));
25271
- import_node_os6 = __toESM(require("os"));
25272
- import_node_path56 = __toESM(require("path"));
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, import_node_child_process34.spawnSync)("launchctl", args, { encoding: "utf-8" });
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, import_node_child_process35.spawnSync)(command, args, {
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 = import_node_path57.default.join(repoPath, "package.json");
25350
- if (!import_node_fs46.default.existsSync(packagePath)) {
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(import_node_fs46.default.readFileSync(packagePath, "utf-8"));
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 import_node_fs46.default.realpathSync(value);
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 (!import_node_fs46.default.statSync(filePath).isFile()) {
25627
+ if (!import_node_fs47.default.statSync(filePath).isFile()) {
25467
25628
  return false;
25468
25629
  }
25469
- import_node_fs46.default.accessSync(filePath, import_node_fs46.default.constants.X_OK);
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}${import_node_path57.default.sep}`)) {
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, import_node_child_process35.spawnSync)(executable, ["-V"], {
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.1" : "0.0.0-dev");
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(import_node_path57.default.delimiter)) {
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 = import_node_path57.default.join(dir, "devrouter");
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 import_node_child_process35, import_node_fs46, import_node_path57, DEVSY_DISABLE_TELEMETRY, CLI_PATH_PROBE_TIMEOUT_MS, INSTALLED_CLI_VERSION_RE;
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
- import_node_child_process35 = require("child_process");
25673
- import_node_fs46 = __toESM(require("fs"));
25674
- import_node_path57 = __toESM(require("path"));
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 = import_node_path58.default.join(comparableRepo, "trees") + import_node_path58.default.sep;
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 = `${import_node_path58.default.basename(comparableRepo)}-`;
25698
- return import_node_path58.default.dirname(comparableWorktree) === import_node_path58.default.dirname(comparableRepo) && import_node_path58.default.basename(comparableWorktree).startsWith(legacyPrefix);
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 import_node_path58;
26111
+ var import_node_path59;
25951
26112
  var init_workspace_gc = __esm({
25952
26113
  "src/core/workspace-gc.ts"() {
25953
26114
  "use strict";
25954
- import_node_path58 = __toESM(require("path"));
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 (!import_node_fs47.default.existsSync(absolutePath)) {
26185
+ if (!import_node_fs48.default.existsSync(absolutePath)) {
26025
26186
  continue;
26026
26187
  }
26027
26188
  try {
26028
- const raw = import_node_fs47.default.readFileSync(absolutePath, "utf-8");
26029
- const parsed = import_yaml6.default.parse(raw);
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.1" : "0.0.0-dev";
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: import_node_path59.default.resolve(repo.path, filePath)
26589
+ absolutePath: import_node_path60.default.resolve(repo.path, filePath)
26429
26590
  }))
26430
- ).filter((entry) => !import_node_fs47.default.existsSync(entry.absolutePath));
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: import_node_path59.default.resolve(repo.path, app.hostRun.cwd)
26474
- })).filter((entry) => !import_node_fs47.default.existsSync(entry.absolutePath));
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 import_node_fs47, import_node_path59, import_yaml6, POSTGRES_DEFAULTS, CAPACITY_RECOVERY_BY_CAUSE;
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
- import_node_fs47 = __toESM(require("fs"));
26623
- import_node_path59 = __toESM(require("path"));
26624
- import_yaml6 = __toESM(require("yaml"));
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, import_node_child_process36.spawnSync)("lsof", ["-nP", `-iTCP:${port}`, "-sTCP:LISTEN"], {
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, import_node_child_process36.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
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 import_node_child_process36;
27214
+ var import_node_child_process37;
27054
27215
  var init_ports = __esm({
27055
27216
  "src/util/ports.ts"() {
27056
27217
  "use strict";
27057
- import_node_child_process36 = require("child_process");
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 = import_node_path60.default.join(repoPath, ".devcontainer");
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, import_node_child_process37.spawnSync)(
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=${import_node_path60.default.join(repoPath, ".devcontainer")}`,
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, import_node_child_process37.spawnSync)("docker", ["port", containerId, `${port}/tcp`], {
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 import_node_child_process37, import_node_path60, LOOPBACK_UPSTREAM_HOSTS, ROUTED_TCP_PARAMS;
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
- import_node_child_process37 = require("child_process");
27531
- import_node_path60 = __toESM(require("path"));
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, import_node_child_process38.spawn)(command[0], command.slice(1), { env, stdio: "inherit" });
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 ? import_node_os7.constants.signals[signal] ?? 0 : 0));
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 import_node_child_process38, import_node_os7, HOST_PORT_ENV_PREFIX;
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
- import_node_child_process38 = require("child_process");
27673
- import_node_os7 = require("os");
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, import_node_crypto29.createHash)("sha256").update(comparableWorkspacePath(repoRoot)).digest("hex");
27723
- return import_node_path61.default.join(DEVROUTER_HOME, "harness", `${key}.json`);
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 = import_node_fs48.default.lstatSync(file);
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(import_node_fs48.default.readFileSync(file, "utf-8"));
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
- import_node_fs48.default.mkdirSync(import_node_path61.default.dirname(file), { recursive: true, mode: 448 });
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
- import_node_fs48.default.mkdirSync(import_node_path61.default.dirname(file), { recursive: true, mode: 448 });
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 import_node_crypto29, import_node_fs48, import_node_path61, HARNESS_CONTINUATION_MAX_ENTRIES, HARNESS_CONTINUATION_TTL_MS, HARNESS_CONTINUATION_LOCK_WAIT_MS, MAX_LEDGER_BYTES, MAX_TOOL_USE_ID_LENGTH, MAX_PHASE_LENGTH;
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
- import_node_crypto29 = require("crypto");
27825
- import_node_fs48 = __toESM(require("fs"));
27826
- import_node_path61 = __toESM(require("path"));
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 = import_node_path62.default.resolve(cwd);
28007
+ let current = import_node_path63.default.resolve(cwd);
27846
28008
  for (let depth = 0; depth < REPO_ROOT_MAX_DEPTH; depth += 1) {
27847
- if (import_node_fs49.default.existsSync(import_node_path62.default.join(current, ".devrouter.yml"))) {
28009
+ if (import_node_fs50.default.existsSync(import_node_path63.default.join(current, ".devrouter.yml"))) {
27848
28010
  return current;
27849
28011
  }
27850
- const parent = import_node_path62.default.dirname(current);
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 import_node_fs49, import_node_path62, HARNESS_GATE_DEFAULT_BUDGET_MS, HARNESS_GATE_MAX_BUDGET_MS, HARNESS_GATE_POLL_INTERVAL_MS, TRANSITIONAL_PHASES, REPO_ROOT_MAX_DEPTH;
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
- import_node_fs49 = __toESM(require("fs"));
27947
- import_node_path62 = __toESM(require("path"));
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, import_node_crypto30.createHash)("sha256").update(JSON.stringify(toolInput)).digest("hex");
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 import_node_crypto30, MAX_HOOK_PAYLOAD_BYTES, STDIN_TIMEOUT_MS, MAX_TOOL_USE_ID_LENGTH2, DEVROUTER_EXECUTABLES, LAUNCHER_WORDS, LAUNCHER_SUBCOMMANDS, COMMAND_WORD_LIMIT;
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
- import_node_crypto30 = require("crypto");
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, import_node_child_process39.spawnSync)("open", [url], { encoding: "utf-8" });
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 import_node_child_process39;
28604
+ var import_node_child_process40;
28443
28605
  var init_open = __esm({
28444
28606
  "src/commands/open.ts"() {
28445
28607
  "use strict";
28446
- import_node_child_process39 = require("child_process");
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, import_node_child_process40.spawn)("docker", args, { stdio: "inherit" });
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, import_node_child_process40.spawnSync)("docker", args, { stdio: "inherit" });
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 import_node_child_process40;
28672
+ var import_node_child_process41;
28511
28673
  var init_logs = __esm({
28512
28674
  "src/commands/logs.ts"() {
28513
28675
  "use strict";
28514
- import_node_child_process40 = require("child_process");
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 (!import_node_fs50.default.existsSync(filePath)) {
28720
+ if (!import_node_fs51.default.existsSync(filePath)) {
28559
28721
  return void 0;
28560
28722
  }
28561
28723
  try {
28562
- return JSON.parse(import_node_fs50.default.readFileSync(filePath, "utf-8"));
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 import_node_path63.default.relative(repoPath, filePath) || ".";
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 (import_node_fs50.default.existsSync(import_node_path63.default.join(repoPath, fileName))) {
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 = import_node_path63.default.join(repoPath, ".nvmrc");
28625
- if (import_node_fs50.default.existsSync(nvmrc)) {
28626
- const version = import_node_fs50.default.readFileSync(nvmrc, "utf-8").trim();
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) => !import_node_path63.default.isAbsolute(fileName) && !import_node_path63.default.normalize(fileName).startsWith("..")
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) => import_node_fs50.default.existsSync(import_node_path63.default.join(repoPath, 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 = import_yaml7.default.parse(import_node_fs50.default.readFileSync(import_node_path63.default.join(repoPath, fileName), "utf-8"));
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 = import_node_fs50.default.readdirSync(repoPath).filter((fileName) => /^\.env(\.|$)/.test(fileName)).sort().map((fileName) => {
28779
- const content = import_node_fs50.default.readFileSync(import_node_path63.default.join(repoPath, fileName), "utf-8");
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 = import_node_path63.default.join(repoPath, ".devcontainer");
28794
- if (!import_node_fs50.default.existsSync(dir)) {
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: import_node_fs50.default.readdirSync(dir).filter((fileName) => import_node_fs50.default.statSync(import_node_path63.default.join(dir, fileName)).isFile()).sort().map((fileName) => `.devcontainer/${fileName}`)
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 (!import_node_fs50.default.existsSync(configPath)) {
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 (import_node_fs50.default.existsSync(import_node_path63.default.join(repoPath, fileName))) {
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 = import_node_path63.default.join(repoPath, ".agents", "skills");
28853
- if (import_node_fs50.default.existsSync(skillsDir)) {
28854
- for (const name of import_node_fs50.default.readdirSync(skillsDir).sort()) {
28855
- const skillPath = import_node_path63.default.join(skillsDir, name, "SKILL.md");
28856
- if (import_node_fs50.default.existsSync(skillPath)) {
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(import_node_path63.default.join(repoPath, "package.json"));
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 import_node_fs50, import_node_path63, import_yaml7;
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
- import_node_fs50 = __toESM(require("fs"));
28923
- import_node_path63 = __toESM(require("path"));
28924
- import_yaml7 = __toESM(require("yaml"));
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) => !import_node_fs51.default.existsSync(import_node_path64.default.join(repoPath, 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 import_node_fs51, import_node_path64;
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
- import_node_fs51 = __toESM(require("fs"));
29258
- import_node_path64 = __toESM(require("path"));
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(import_node_path65.default.basename(repo.repoPath));
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 = import_node_path65.default.join(repoPath, file.relativePath);
29601
- if (!import_node_fs52.default.existsSync(absolutePath)) {
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 = import_node_fs52.default.readFileSync(absolutePath, "utf-8");
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 = import_node_path65.default.join(repoPath, file.relativePath);
29667
- import_node_fs52.default.mkdirSync(import_node_path65.default.dirname(absolutePath), { recursive: true });
29668
- import_node_fs52.default.writeFileSync(absolutePath, file.content, "utf-8");
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
- import_node_fs52.default.chmodSync(absolutePath, 493);
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 import_node_fs52, import_node_path65, MANAGED_MARKER2, DEFAULT_DEVROUTER_VERSION, DEFAULT_PNPM_VERSION, VALID_PACKAGE_VERSION_RE;
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
- import_node_fs52 = __toESM(require("fs"));
29713
- import_node_path65 = __toESM(require("path"));
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, import_yaml8.parseDocument)(source, {
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 (import_node_path66.default.isAbsolute(contractPath)) {
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 = import_node_fs53.default.lstatSync(absolutePath);
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 = import_node_fs53.default.realpathSync(repoPath);
30064
- const realContract = import_node_fs53.default.realpathSync(absolutePath);
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 = import_node_fs53.default.readFileSync(absolutePath, "utf-8");
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: import_node_path66.default.relative(repoPath, absolutePath).split(import_node_path66.default.sep).join("/")
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 import_node_fs53, import_node_path66, import_yaml8, CONTRACT_VERSION, MAX_CONTRACT_BYTES, MAX_APP_MAPPINGS, MAX_BINDING_KEYS, MAX_BINDING_VALUES, MAX_LITERAL_LENGTH, BINDING_KEY;
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
- import_node_fs53 = __toESM(require("fs"));
30091
- import_node_path66 = __toESM(require("path"));
30092
- import_yaml8 = require("yaml");
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(import_node_path67.default.resolve(options.output), `${JSON.stringify(report, null, 2)}
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: ${import_node_path67.default.resolve(output2)}
30332
+ if (output2) process.stdout.write(`Output: ${import_node_path68.default.resolve(output2)}
30171
30333
  `);
30172
30334
  }
30173
- var import_node_path67;
30335
+ var import_node_path68;
30174
30336
  var init_profile = __esm({
30175
30337
  "src/commands/profile.ts"() {
30176
30338
  "use strict";
30177
- import_node_path67 = __toESM(require("path"));
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, import_yaml9.parseDocument)(source, {
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 = import_node_path68.default.resolve(repoPath);
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 = import_node_fs54.default.lstatSync(manifestPath);
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 = import_node_fs54.default.realpathSync(resolvedRepo);
30575
- const realManifest = import_node_fs54.default.realpathSync(manifestPath);
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 = import_node_fs54.default.readFileSync(manifestPath, "utf-8");
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, import_node_crypto31.createHash)("sha256").update(source, "utf-8").digest("hex")
30745
+ digest: (0, import_node_crypto32.createHash)("sha256").update(source, "utf-8").digest("hex")
30584
30746
  };
30585
30747
  }
30586
- var import_node_crypto31, import_node_fs54, import_node_path68, import_yaml9, 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;
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
- import_node_crypto31 = require("crypto");
30591
- import_node_fs54 = __toESM(require("fs"));
30592
- import_node_path68 = __toESM(require("path"));
30593
- import_yaml9 = require("yaml");
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 object4(value, required, optional = []) {
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 = object4(
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 = object4(row.pendingDeadline, ["target", "commandId"]);
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 = object4(
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 = object4(row.source, ["head", "target", "mergeBase", "complete", "changes"]);
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 = object4(change, ["status", "path"], ["oldPath"]);
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 = object4(
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, import_yaml10.stringify)({
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 = object4(value, [
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 = object4(receipt, ["id", "admittedAt"]);
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 = object4(raw, ["createdAt", "recordedAt", "commandId"]);
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 = object4(
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 = object4(entry.identity, ["forgeHost", "projectId", "change"]);
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 = object4(
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 = object4(rawStep, ["name", "mode", "state", "at"], ["ref", "fingerprint"]);
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 import_yaml10, PreviewStateConflict;
31878
+ var import_yaml11, PreviewStateConflict;
31717
31879
  var init_state = __esm({
31718
31880
  "src/core/preview/state.ts"() {
31719
31881
  "use strict";
31720
- import_yaml10 = require("yaml");
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, import_node_crypto32.createHash)("sha256").update(JSON.stringify([identity2.forgeHost, identity2.projectId, identity2.change])).digest("hex");
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 import_node_crypto32, PreviewAdmissionSuperseded, PreviewEngine;
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
- import_node_crypto32 = require("crypto");
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, import_node_crypto32.createHash)("sha256").update(receipt).digest("hex").slice(0, 24);
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, path79, body, maxBytes) {
32463
- if (!path79 || path79.startsWith("/") || path79.split("?")[0].split("/").some((part) => [".", ".."].includes(decodeURIComponent(part))) || path79.includes("\\") || path79.includes("#"))
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(path79, this.base);
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(path79, options = {}) {
32667
+ async pages(path80, options = {}) {
32506
32668
  const rows2 = [];
32507
32669
  for (let page = 1; page <= 100; page++) {
32508
- const separator = path79.includes("?") ? "&" : "?";
32670
+ const separator = path80.includes("?") ? "&" : "?";
32509
32671
  const result = await this.request(
32510
32672
  "GET",
32511
- `${path79}${separator}per_page=100&page=${page}`,
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 = object4(
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 = object4(row.identity, ["forgeHost", "projectId", "change"]);
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 = object4(item, ["id", "at"]);
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 = object4(
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 import_node_crypto33, PreviewController;
32747
+ var import_node_crypto34, PreviewController;
32586
32748
  var init_controller2 = __esm({
32587
32749
  "src/core/preview/controller.ts"() {
32588
32750
  "use strict";
32589
- import_node_crypto33 = require("crypto");
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, import_node_crypto33.createHash)("sha256").update(body).digest("hex"), now = this.options.now();
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, import_node_crypto33.randomUUID)();
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 path79 = `${this.repo}/issues/comments/${forgeId(previousId)}`;
33144
- const comment = forgeObject((await this.http.request("GET", path79)).data);
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", path79, { body });
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 path79 = assertRepoRelativePath(row.new_path, "GitLab changed file"), oldPath = assertRepoRelativePath(row.old_path, "GitLab old file");
33324
- if (row.renamed_file) return { status: "R", path: path79, oldPath };
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: path79
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, import_node_crypto34.createHash)("sha256").update(canonicalizeImageConfiguration(configuration), "utf-8").digest("hex")}`;
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 import_node_crypto34, 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;
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
- import_node_crypto34 = require("crypto");
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 = import_node_fs55.default.lstatSync(file.path);
33851
- if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 1024 * 1024 || (0, import_node_crypto35.createHash)("sha256").update(import_node_fs55.default.readFileSync(file.path)).digest("hex") !== file.sha256)
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, import_node_crypto35.createHash)("sha256").update(
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, import_node_child_process41.spawnSync)(options.command[0], options.command.slice(1), {
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 = object4(invoke("resolve"), ["receipts"], ["pending"]);
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 import_node_child_process41, import_node_crypto35, import_node_fs55;
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
- import_node_child_process41 = require("child_process");
33930
- import_node_crypto35 = require("crypto");
33931
- import_node_fs55 = __toESM(require("fs"));
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, import_node_crypto36.createHash)("sha256").update(id5).digest("hex").slice(0, 6)}.${policy.baseDomain}`;
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, import_node_crypto36.createHash)("sha256").update(id5).digest("hex").slice(0, 10)}`;
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, import_node_crypto36.createHash)("sha256").update(JSON.stringify({ spec, runtimeSecrets })).digest("hex");
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 import_node_crypto36, 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;
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
- import_node_crypto36 = require("crypto");
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 = object4(
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 = object4(row.apiWait, ["until", "exhausted"]);
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 = object4(raw, ["reference", "kind", "id", "name"], ["uid"]);
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, import_node_crypto37.createHash)("sha256").update(JSON.stringify(value)).digest("hex");
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 import_node_crypto37, resourceKinds, NorthflankOwnershipStore, northflankQualificationKeys, NorthflankFailure, NorthflankFenced, NorthflankPreviewProvider, nativeKinds, emptySpec;
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
- import_node_crypto37 = require("crypto");
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, import_node_crypto37.randomBytes)(settings.bytes).toString(settings.encoding);
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 path79 = ["preview-blueprints", owned.blueprintId];
35912
- const id5 = step.ref ?? await this.findRun(path79, operation);
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", [...path79, "runs", id5]);
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(path79, operation) {
36099
+ async findRun(path80, operation) {
35938
36100
  let match;
35939
- for (const summary of await this.options.api.list([...path79, "runs"], "runs")) {
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", [...path79, "runs", id5]));
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 path79 = ["preview-blueprints", northflankIdentifier(owned.blueprintId)];
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", path79, {
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", path79));
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", [...path79, "runs"], {
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(path79, operation);
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", [...path79, "runs", id5]));
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([...path79, "previews"], "previewEnvironments");
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 path79 = ["preview-blueprints", owned.blueprintId];
36077
- const blueprint = await this.options.api.request("GET", path79);
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([...path79, "runs"], "runs");
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", [...path79, "runs", id5, "abort"]);
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([...path79, "previews"], "previewEnvironments");
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", [...path79, "previews", id5]);
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([...path79, "previews"], "previewEnvironments")).length)
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", path79);
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 = import_node_fs56.default.lstatSync(file);
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 import_node_fs56.default.readFileSync(file, "utf8");
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 = import_node_path69.default.dirname(import_node_fs56.default.realpathSync(filename));
36354
- const raw = object4(JSON.parse(readFile(filename)), [
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 = object4(raw.state, ["containerUrl"], ["tokenEnv", "federated"]);
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 : object4(statePolicy.federated, ["tenantIdEnv", "clientIdEnv", "assertionEnv"]);
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 = object4(
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 = object4(
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 = object4(input3, ["file", "sha256"]);
36596
+ const ref2 = object5(input3, ["file", "sha256"]);
36435
36597
  const filename2 = text5(ref2.file, /^(?!\/)(?!.*(?:^|\/)\.\.(?:\/|$))[^\\\0]+$/);
36436
- const file = import_node_fs56.default.realpathSync(import_node_path69.default.join(root, filename2));
36437
- if (!file.startsWith(`${root}${import_node_path69.default.sep}`))
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 = object4(row.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 = object4(
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 = object4(row.acceptance, ["command", "environment"]);
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, import_node_child_process42.spawnSync)(command[0], command.slice(1), {
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 = object4(JSON.parse(result.stdout), [
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 : object4(row.images, [
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 ? object4(imagePolicy.producer, ["repository", "workflow", "controlRevision"]) : void 0;
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 = object4(input3, ["file", "sha256"]);
36720
+ const item = object5(input3, ["file", "sha256"]);
36559
36721
  const verified = control(input3);
36560
36722
  return {
36561
- path: import_node_fs56.default.realpathSync(import_node_path69.default.join(root, item.file)),
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, import_node_crypto38.randomUUID)(),
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) => object4(raw, ["installationId"])))
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 import_node_child_process42, import_node_crypto38, import_node_fs56, import_node_path69, MAX_COMMAND_AGE_MS, digest4, envName;
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
- import_node_child_process42 = require("child_process");
36797
- import_node_crypto38 = require("crypto");
36798
- import_node_fs56 = __toESM(require("fs"));
36799
- import_node_path69 = __toESM(require("path"));
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, import_node_crypto38.createHash)("sha256").update(source).digest("hex");
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 (import_node_path70.default.isAbsolute(filename))
36995
+ if (import_node_path71.default.isAbsolute(filename))
36834
36996
  throw new Error("Preview source path must be repository-relative.");
36835
- const root = import_node_fs57.default.realpathSync(repoPath);
36997
+ const root = import_node_fs58.default.realpathSync(repoPath);
36836
36998
  const file = assertPathWithinRepo(filename, root, "preview source");
36837
- const stat = import_node_fs57.default.lstatSync(file);
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(import_node_fs57.default.realpathSync(file), root, "preview source");
36842
- return JSON.parse(import_node_fs57.default.readFileSync(file, "utf8"));
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 = import_node_fs57.default.readFileSync(import_node_path70.default.join(repoPath, ".devrouter.yml"), "utf8");
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, import_node_crypto39.createHash)("sha256").update(localConfig).digest("hex"),
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 = import_node_fs57.default.realpathSync(resolveRepoPath(options.repo));
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, import_yaml11.stringify)(manifest);
37067
+ const content = (0, import_yaml12.stringify)(manifest);
36906
37068
  if (options.write) {
36907
- const file = import_node_path70.default.join(repoPath, ".devrouter.preview.yml");
36908
- import_node_fs57.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
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
- import_node_path70.default.resolve(__dirname, "..", "assets", "preview", name),
36974
- import_node_path70.default.resolve(__dirname, "..", "..", "assets", "preview", name)
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) => import_node_fs57.default.existsSync(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 import_node_fs57.default.readFileSync(file, "utf8");
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
- import_node_fs57.default.mkdirSync(import_node_path70.default.dirname(file), { recursive: true });
37014
- assertPathWithinRepo(import_node_fs57.default.realpathSync(import_node_path70.default.dirname(file)), repoPath, "preview workflow parent");
37015
- import_node_fs57.default.writeFileSync(file, content, { flag: "wx", mode: 384 });
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, import_node_crypto39.createHash)("sha256").update(previewAsset("gitlab-template.yml")).digest("base64")}`;
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
- import_node_fs57.default.writeFileSync(assertPathWithinRepo(filename, repoPath, "GitLab preview caller"), content, {
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 import_node_crypto39, import_node_fs57, import_node_path70, import_yaml11;
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
- import_node_crypto39 = require("crypto");
37062
- import_node_fs57 = __toESM(require("fs"));
37063
- import_node_path70 = __toESM(require("path"));
37064
- import_yaml11 = require("yaml");
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, import_node_crypto40.createHash)("sha1").update(import_node_path71.default.resolve(repoPath)).digest("hex").slice(0, 12);
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 = import_node_path71.default.join(CACHE_DIR, repoHash(repoPath), sanitizeRouterId(appName));
37435
- import_node_fs58.default.mkdirSync(cachePath, { recursive: true });
37436
- const overlayPath = import_node_path71.default.join(cachePath, "compose.devrouter.yml");
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
- import_node_fs58.default.writeFileSync(overlayPath, import_yaml12.default.stringify(overlayDocument, { lineWidth: 0 }), "utf-8");
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, import_node_child_process43.spawnSync)("docker", args, {
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, import_node_child_process43.spawnSync)("docker", args, {
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, import_node_child_process43.spawnSync)("docker", args, {
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, import_node_child_process43.spawnSync)("docker", args, {
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, import_node_child_process43.spawnSync)("docker", args, {
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 import_node_child_process43, import_node_crypto40, import_node_fs58, import_node_path71, import_yaml12;
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
- import_node_child_process43 = require("child_process");
37563
- import_node_crypto40 = require("crypto");
37564
- import_node_fs58 = __toESM(require("fs"));
37565
- import_node_path71 = __toESM(require("path"));
37566
- import_yaml12 = __toESM(require("yaml"));
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, import_node_child_process44.spawnSync)("ps", ["-ax", "-o", "pid=,ppid="], { encoding: "utf-8" });
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, import_node_child_process44.spawnSync)("lsof", ["-nP", "-iTCP", "-sTCP:LISTEN", "-a", "-p", pids.join(",")], {
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, import_node_child_process44.spawnSync)("ss", ["-H", "-lntp", "-p"], { encoding: "utf-8" });
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, import_node_child_process44.spawn)(spawnCommand, {
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, import_node_child_process44.spawn)(wrapped, {
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, import_node_child_process44.spawn)(cmd, wrappedArgs, {
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, import_node_child_process44.spawn)(options.command[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, import_node_child_process44.spawn)(command, args, {
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 import_node_child_process44, import_node_net6, import_node_process, import_promises, POLL_INTERVAL_MS, DEFAULT_PORT_TIMEOUT_MS, PROCESS_TERMINATION_GRACE_MS;
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
- import_node_child_process44 = require("child_process");
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, import_node_crypto41.createHash)("sha256").update(raw).digest("hex");
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 (!import_node_path72.default.isAbsolute(candidate[key])) {
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 = import_node_fs59.default.readFileSync(file);
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, import_node_child_process45.spawnSync)("git", ["-C", cwd, ...args], {
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 (!import_node_fs59.default.existsSync(worktreePath)) return void 0;
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
- import_node_path72.default.join(gitDir, "index"),
38635
- import_node_path72.default.join(gitDir, "HEAD"),
38636
- import_node_path72.default.join(gitDir, "logs", "HEAD"),
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(import_node_fs59.default.statSync(file).mtimeMs / 1e3);
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 import_node_path72.default.join(commonDir, "worktree-reclaim", "receipts", manifestSha256, `${id5}.json`);
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
- import_node_fs59.default.readFileSync(receiptPath(candidate.commonDir, manifestSha256, candidate.id), "utf-8")
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
- import_node_fs59.default.mkdirSync(import_node_path72.default.dirname(file), { recursive: true });
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, import_node_child_process45.spawnSync)(command, [worktreePath], {
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 (!import_node_path72.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
38901
+ if (!import_node_path73.default.isAbsolute(command)) throw new Error("--veto-command must be an absolute path");
38740
38902
  try {
38741
- import_node_fs59.default.accessSync(command, import_node_fs59.default.constants.X_OK);
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, import_node_child_process45.spawnSync)(
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, import_node_child_process45.spawnSync)(
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, import_node_child_process45.spawnSync)(
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 (!import_node_fs59.default.existsSync(candidate.path) && matchingReceipt(candidate, manifestSha256)) {
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 import_node_child_process45, import_node_crypto41, import_node_fs59, import_node_path72, 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;
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
- import_node_child_process45 = require("child_process");
38897
- import_node_crypto41 = require("crypto");
38898
- import_node_fs59 = __toESM(require("fs"));
38899
- import_node_path72 = __toESM(require("path"));
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 = import_node_path73.default.relative(parent, child);
39020
- return relative2 === "" || !relative2.startsWith("..") && !import_node_path73.default.isAbsolute(relative2);
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 = import_node_path73.default.dirname(checkout);
39194
+ let ancestor = import_node_path74.default.dirname(checkout);
39033
39195
  while (!context.exists(ancestor)) {
39034
- const parent = import_node_path73.default.dirname(ancestor);
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 = import_node_path73.default.dirname(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(import_node_path73.default.join(current, ".git"))) return "inside-worktree";
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 !== import_node_path73.default.resolve(file) ? [import_node_path73.default.resolve(file), real] : [import_node_path73.default.resolve(file)];
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: import_node_path73.default.join(repoPath, "trees"),
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 import_node_fs60.default.realpathSync.native(file);
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
- import_node_fs60.default.lstatSync(file);
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 (!import_node_path73.default.isAbsolute(root.repo)) throw new Error("manifest repo must be an absolute path");
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 (!import_node_path73.default.isAbsolute(candidate.checkout)) {
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 = import_node_fs60.default.readFileSync(file);
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, import_node_child_process46.spawnSync)(
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 = (object5) => object5.labels[PROJECT_LABEL] === candidate.project && object5.name.startsWith(`${candidate.project}_`);
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 import_node_path73.default.join(commonDir, "devrouter-leftovers", "receipts", manifestSha256, `${id5}.json`);
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
- import_node_fs60.default.mkdirSync(import_node_path73.default.dirname(file), { recursive: true });
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 import_node_child_process46, import_node_fs60, import_node_path73, 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;
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
- import_node_child_process46 = require("child_process");
39501
- import_node_fs60 = __toESM(require("fs"));
39502
- import_node_path73 = __toESM(require("path"));
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, import_node_child_process46.spawnSync)("docker", args, {
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 = import_node_fs61.default.lstatSync(worktreePath);
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 = import_node_fs61.default.readdirSync(worktreePath, { withFileTypes: true });
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 = import_node_path74.default.join(dirPath, entry.name);
39748
+ const entryPath = import_node_path75.default.join(dirPath, entry.name);
39587
39749
  let entryStat;
39588
39750
  try {
39589
- entryStat = import_node_fs61.default.lstatSync(entryPath);
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 = import_node_fs61.default.readdirSync(entryPath, { withFileTypes: true });
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 import_node_fs61, import_node_path74, DEFAULT_DEADLINE_MS, BLOCK_SIZE_BYTES;
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
- import_node_fs61 = __toESM(require("fs"));
39668
- import_node_path74 = __toESM(require("path"));
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 || !import_node_fs62.default.existsSync(comparablePath)) {
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((path79) => [path79, unknownContainers(reason2)]));
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 = import_node_fs62.default.existsSync(import_node_path75.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.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 || !import_node_fs62.default.existsSync(worktreePath),
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, import_node_child_process47.spawnSync)(
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 || !import_node_fs62.default.existsSync(worktreePath),
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 = import_node_fs62.default.existsSync(import_node_path75.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees?.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 = import_node_fs62.default.existsSync(import_node_path75.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
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 import_node_child_process47, import_node_fs62, import_node_path75, READ_ONLY_GIT_ENV2, ACTIVITY_SOURCES, defaultCommandRunner;
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
- import_node_child_process47 = require("child_process");
40550
- import_node_fs62 = __toESM(require("fs"));
40551
- import_node_path75 = __toESM(require("path"));
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, import_node_child_process47.spawnSync)(command, args, {
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, import_node_child_process48.spawnSync)("docker", ["logs", "--timestamps", ...args, ROUTER_CONTAINER_NAME], {
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 import_node_child_process48, import_node_fs63, import_node_path76, DEFAULT_IDLE_FOR, ACTIVITY_FILES, IdleStopSkipped, defaultDependencies;
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
- import_node_child_process48 = require("child_process");
40873
- import_node_fs63 = __toESM(require("fs"));
40874
- import_node_path76 = __toESM(require("path"));
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 import_node_fs63.default.statSync(reliabilityOperationPath(record6.identity)).mtimeMs;
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, import_node_child_process48.spawnSync)(
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) => import_node_fs63.default.existsSync(import_node_path76.default.join(repoPath, ".devrouter.yml")),
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 import_node_path77.default.join(mainRepo, "trees", ws);
41171
+ return import_node_path78.default.join(mainRepo, "trees", ws);
41010
41172
  }
41011
41173
  function assertDefaultWorktreeRootIgnored(mainRepo) {
41012
- const ignored = (0, import_node_child_process49.spawnSync)("git", ["-C", mainRepo, "check-ignore", "-q", "--no-index", "trees/"], {
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 '${import_node_path77.default.join(mainRepo, "trees")}' is not ignored. Add 'trees/' to '${import_node_path77.default.join(mainRepo, ".gitignore")}' or use --path.`
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 import_node_path77.default.join(import_node_path77.default.dirname(mainRepo), `${import_node_path77.default.basename(mainRepo)}-${ws}`);
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 || !import_node_fs64.default.existsSync(target.worktreePath)) return;
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) => !import_node_fs64.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
41328
+ (candidate) => !import_node_fs65.default.existsSync(candidate) && !worktrees.some((worktree) => sameWorkspacePath(worktree.path, candidate))
41167
41329
  );
41168
- const selectedPath = opts.path ? import_node_path77.default.resolve(opts.path) : existingBranch?.path ?? generatedPath;
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 (import_node_fs64.default.existsSync(selectedPath)) {
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, import_node_child_process49.spawnSync)("git", ["-C", mainRepo, "worktree", "add", selectedPath, branch], {
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, import_node_child_process49.spawnSync)(
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 && import_node_fs64.default.existsSync(resolved2.worktreePath)) {
41341
- const rm = (0, import_node_child_process49.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", resolved2.worktreePath], {
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 && import_node_fs64.default.existsSync(resolved2.worktreePath) ? withLifecycleOperationLock(resolved2.worktreePath, operation) : operation();
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, import_node_child_process49.spawnSync)("git", ["-C", mainRepo, "worktree", "remove", worktreePath], {
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 import_node_child_process49, import_node_fs64, import_node_path77, WORKSPACE_ALLOCATION_LOCK_WAIT_MS;
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
- import_node_child_process49 = require("child_process");
41411
- import_node_fs64 = __toESM(require("fs"));
41412
- import_node_path77 = __toESM(require("path"));
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, import_node_child_process50.spawnSync)(
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 = import_node_path78.default.relative(parent, child);
41516
- return relative2 !== "" && !relative2.startsWith("..") && !import_node_path78.default.isAbsolute(relative2);
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
- import_node_fs65.default.lstatSync(file);
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, import_node_child_process50.spawnSync)(
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 = import_node_path78.default.join(candidate.path, relative2);
41697
+ const target = import_node_path79.default.join(candidate.path, relative2);
41536
41698
  let stat;
41537
41699
  try {
41538
- stat = import_node_fs65.default.lstatSync(target);
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(import_node_fs65.default.realpathSync.native(candidate.path), import_node_fs65.default.realpathSync.native(target))) {
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
- import_node_fs65.default.rmSync(target, { recursive: true, force: true });
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(import_node_path78.default.join(candidate.path, relative2))) && matchingReceipt(candidate, manifestSha256)) {
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(import_node_path78.default.join(candidate.path, relative2)));
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 import_node_child_process50, import_node_fs65, import_node_path78;
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
- import_node_child_process50 = require("child_process");
41669
- import_node_fs65 = __toESM(require("fs"));
41670
- import_node_path78 = __toESM(require("path"));
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
- import_node_fs66.default.writeFileSync(output2, manifest, { flag: "wx" });
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 = import_node_fs66.default.existsSync(import_node_path79.default.join(repoPath, ".devrouter.yml")) ? loadRepoConfig(repoPath).worktrees : void 0;
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
- import_node_fs66.default.mkdirSync(paths.directory, { recursive: true, mode: 448 });
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(import_node_fs66.default.readFileSync(file, "utf-8")));
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 import_node_fs66, import_node_path79;
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
- import_node_fs66 = __toESM(require("fs"));
42010
- import_node_path79 = __toESM(require("path"));
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.1" : "0.0.0-dev";
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 (path79, _options, command) => {
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({ ...path79 ? { path: path79 } : {}, ...options });
42758
+ await runWorkspaceJournalSettleCommand2({ ...path80 ? { path: path80 } : {}, ...options });
42595
42759
  })
42596
42760
  );
42597
42761
  function parseVersionRequest(argv) {