@boxes-dev/dvb 1.0.53 → 1.0.55

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.
Files changed (52) hide show
  1. package/dist/bin/dvb.cjs +821 -259
  2. package/dist/bin/dvb.cjs.map +1 -1
  3. package/dist/bin/dvbd.cjs +5 -5
  4. package/dist/devbox/commands/commandProvider.d.ts +6 -1
  5. package/dist/devbox/commands/commandProvider.d.ts.map +1 -1
  6. package/dist/devbox/commands/commandProvider.js +27 -2
  7. package/dist/devbox/commands/commandProvider.js.map +1 -1
  8. package/dist/devbox/commands/connect.d.ts.map +1 -1
  9. package/dist/devbox/commands/connect.js +35 -65
  10. package/dist/devbox/commands/connect.js.map +1 -1
  11. package/dist/devbox/commands/init/finalizeFlow.d.ts.map +1 -1
  12. package/dist/devbox/commands/init/finalizeFlow.js +9 -2
  13. package/dist/devbox/commands/init/finalizeFlow.js.map +1 -1
  14. package/dist/devbox/commands/init/index.d.ts.map +1 -1
  15. package/dist/devbox/commands/init/index.js +1 -0
  16. package/dist/devbox/commands/init/index.js.map +1 -1
  17. package/dist/devbox/commands/init/provider/modalRuntime.d.ts.map +1 -1
  18. package/dist/devbox/commands/init/provider/modalRuntime.js +262 -7
  19. package/dist/devbox/commands/init/provider/modalRuntime.js.map +1 -1
  20. package/dist/devbox/commands/init/provider/types.d.ts +1 -1
  21. package/dist/devbox/commands/init/provider/types.d.ts.map +1 -1
  22. package/dist/devbox/commands/init/remote.d.ts +2 -1
  23. package/dist/devbox/commands/init/remote.d.ts.map +1 -1
  24. package/dist/devbox/commands/init/remote.js +32 -2
  25. package/dist/devbox/commands/init/remote.js.map +1 -1
  26. package/dist/devbox/commands/init/setupPlanFlow.d.ts.map +1 -1
  27. package/dist/devbox/commands/init/setupPlanFlow.js +1 -18
  28. package/dist/devbox/commands/init/setupPlanFlow.js.map +1 -1
  29. package/dist/devbox/commands/mount.d.ts +35 -0
  30. package/dist/devbox/commands/mount.d.ts.map +1 -1
  31. package/dist/devbox/commands/mount.js +128 -35
  32. package/dist/devbox/commands/mount.js.map +1 -1
  33. package/dist/devbox/commands/mountSsh.d.ts +2 -0
  34. package/dist/devbox/commands/mountSsh.d.ts.map +1 -1
  35. package/dist/devbox/commands/mountSsh.js +21 -4
  36. package/dist/devbox/commands/mountSsh.js.map +1 -1
  37. package/dist/devbox/commands/provider/modalCommandContext.d.ts +22 -0
  38. package/dist/devbox/commands/provider/modalCommandContext.d.ts.map +1 -0
  39. package/dist/devbox/commands/provider/modalCommandContext.js +52 -0
  40. package/dist/devbox/commands/provider/modalCommandContext.js.map +1 -0
  41. package/dist/devbox/commands/provider/modalLifecycle.d.ts +1 -0
  42. package/dist/devbox/commands/provider/modalLifecycle.d.ts.map +1 -1
  43. package/dist/devbox/commands/provider/modalLifecycle.js +17 -0
  44. package/dist/devbox/commands/provider/modalLifecycle.js.map +1 -1
  45. package/dist/devbox/commands/providerClient.d.ts +3 -1
  46. package/dist/devbox/commands/providerClient.d.ts.map +1 -1
  47. package/dist/devbox/commands/providerClient.js +14 -13
  48. package/dist/devbox/commands/providerClient.js.map +1 -1
  49. package/dist/devbox/commands/sessions.d.ts.map +1 -1
  50. package/dist/devbox/commands/sessions.js +110 -30
  51. package/dist/devbox/commands/sessions.js.map +1 -1
  52. package/package.json +1 -1
package/dist/bin/dvb.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="5b27d1b2-cb5a-5370-b4ca-61330f7946e5")}catch(e){}}();
3
+ !function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="4d4f5269-c2cd-5397-a6d4-993b4d24cfdc")}catch(e){}}();
4
4
 
5
5
  var __create = Object.create;
6
6
  var __defProp = Object.defineProperty;
@@ -21725,7 +21725,7 @@ var require_ProcessDetector = __commonJS({
21725
21725
  exports2.processDetector = void 0;
21726
21726
  var api_1 = require_src();
21727
21727
  var semconv_1 = require_semconv5();
21728
- var os23 = require("os");
21728
+ var os24 = require("os");
21729
21729
  var ProcessDetector = class {
21730
21730
  detect(_config) {
21731
21731
  const attributes = {
@@ -21745,7 +21745,7 @@ var require_ProcessDetector = __commonJS({
21745
21745
  attributes[semconv_1.ATTR_PROCESS_COMMAND] = process.argv[1];
21746
21746
  }
21747
21747
  try {
21748
- const userInfo = os23.userInfo();
21748
+ const userInfo = os24.userInfo();
21749
21749
  attributes[semconv_1.ATTR_PROCESS_OWNER] = userInfo.username;
21750
21750
  } catch (e2) {
21751
21751
  api_1.diag.debug(`error obtaining process owner: ${e2}`);
@@ -37305,7 +37305,7 @@ var require_service_config = __commonJS({
37305
37305
  exports2.validateRetryThrottling = validateRetryThrottling;
37306
37306
  exports2.validateServiceConfig = validateServiceConfig;
37307
37307
  exports2.extractAndSelectServiceConfig = extractAndSelectServiceConfig;
37308
- var os23 = require("os");
37308
+ var os24 = require("os");
37309
37309
  var constants_1 = require_constants9();
37310
37310
  var DURATION_REGEX = /^\d+(\.\d{1,9})?s$/;
37311
37311
  var CLIENT_LANGUAGE_STRING = "node";
@@ -37604,7 +37604,7 @@ var require_service_config = __commonJS({
37604
37604
  if (Array.isArray(validatedConfig.clientHostname)) {
37605
37605
  let hostnameMatched = false;
37606
37606
  for (const hostname2 of validatedConfig.clientHostname) {
37607
- if (hostname2 === os23.hostname()) {
37607
+ if (hostname2 === os24.hostname()) {
37608
37608
  hostnameMatched = true;
37609
37609
  }
37610
37610
  }
@@ -51408,7 +51408,7 @@ var require_subchannel_call = __commonJS({
51408
51408
  Object.defineProperty(exports2, "__esModule", { value: true });
51409
51409
  exports2.Http2SubchannelCall = void 0;
51410
51410
  var http22 = require("http2");
51411
- var os23 = require("os");
51411
+ var os24 = require("os");
51412
51412
  var constants_1 = require_constants9();
51413
51413
  var metadata_1 = require_metadata();
51414
51414
  var stream_decoder_1 = require_stream_decoder();
@@ -51416,7 +51416,7 @@ var require_subchannel_call = __commonJS({
51416
51416
  var constants_2 = require_constants9();
51417
51417
  var TRACER_NAME = "subchannel_call";
51418
51418
  function getSystemErrorName(errno) {
51419
- for (const [name, num] of Object.entries(os23.constants.errno)) {
51419
+ for (const [name, num] of Object.entries(os24.constants.errno)) {
51420
51420
  if (num === errno) {
51421
51421
  return name;
51422
51422
  }
@@ -88683,8 +88683,8 @@ var init_otel = __esm({
88683
88683
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
88684
88684
  };
88685
88685
  readBuildMetadata = () => {
88686
- const rawPackageVersion = "1.0.53";
88687
- const rawGitSha = "cf1d2a8bda7651429d5043ead7b5caf47d35e42d";
88686
+ const rawPackageVersion = "1.0.55";
88687
+ const rawGitSha = "fd6acb6139b570fb0b4ff18a48c7dfe864bb6513";
88688
88688
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
88689
88689
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
88690
88690
  return { packageVersion, gitSha };
@@ -120672,9 +120672,9 @@ var init_sentry = __esm({
120672
120672
  sentryEnabled = false;
120673
120673
  uncaughtExceptionMonitorInstalled = false;
120674
120674
  readBuildMetadata2 = () => {
120675
- const rawPackageVersion = "1.0.53";
120676
- const rawGitSha = "cf1d2a8bda7651429d5043ead7b5caf47d35e42d";
120677
- const rawSentryRelease = "boxes-dev-dvb@1.0.53+cf1d2a8bda7651429d5043ead7b5caf47d35e42d";
120675
+ const rawPackageVersion = "1.0.55";
120676
+ const rawGitSha = "fd6acb6139b570fb0b4ff18a48c7dfe864bb6513";
120677
+ const rawSentryRelease = "boxes-dev-dvb@1.0.55+fd6acb6139b570fb0b4ff18a48c7dfe864bb6513";
120678
120678
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
120679
120679
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
120680
120680
  const sentryRelease = typeof rawSentryRelease === "string" ? rawSentryRelease : void 0;
@@ -182511,14 +182511,14 @@ var init_simple_client_node = __esm({
182511
182511
  "../common/temp/node_modules/.pnpm/node-gyp-build@4.8.4/node_modules/node-gyp-build/node-gyp-build.js"(exports2, module2) {
182512
182512
  var fs29 = __require("fs");
182513
182513
  var path38 = __require("path");
182514
- var os23 = __require("os");
182514
+ var os24 = __require("os");
182515
182515
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
182516
182516
  var vars = process.config && process.config.variables || {};
182517
182517
  var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
182518
182518
  var abi = process.versions.modules;
182519
182519
  var runtime = isElectron() ? "electron" : isNwjs() ? "node-webkit" : "node";
182520
- var arch2 = process.env.npm_config_arch || os23.arch();
182521
- var platform2 = process.env.npm_config_platform || os23.platform();
182520
+ var arch2 = process.env.npm_config_arch || os24.arch();
182521
+ var platform2 = process.env.npm_config_platform || os24.platform();
182522
182522
  var libc = process.env.LIBC || (isAlpine(platform2) ? "musl" : "glibc");
182523
182523
  var armv = process.env.ARM_VERSION || (arch2 === "arm64" ? "8" : vars.arm_version) || "";
182524
182524
  var uv = (process.versions.uv || "").split(".")[0];
@@ -197021,12 +197021,19 @@ var init_destroyLocalState = __esm({
197021
197021
  });
197022
197022
 
197023
197023
  // src/devbox/commands/commandProvider.ts
197024
- var normalizeBoxKey, resolveRegistryEntry, resolveCommandComputeProvider, assertCommandProviderCapability;
197024
+ var MODAL_CONNECT_CAPABILITIES, MODAL_MOUNT_CAPABILITIES, normalizeBoxKey, resolveRegistryEntry, resolveCommandComputeProvider, assertCommandProviderCapability, hasCommandProviderCapability;
197025
197025
  var init_commandProvider = __esm({
197026
197026
  "src/devbox/commands/commandProvider.ts"() {
197027
197027
  "use strict";
197028
197028
  init_src();
197029
197029
  init_destroyLocalState();
197030
+ MODAL_CONNECT_CAPABILITIES = /* @__PURE__ */ new Set([
197031
+ "exec.sessions.open",
197032
+ "exec.sessions.attach",
197033
+ "exec.sessions.list",
197034
+ "exec.sessions.kill"
197035
+ ]);
197036
+ MODAL_MOUNT_CAPABILITIES = /* @__PURE__ */ new Set(["files.read"]);
197030
197037
  normalizeBoxKey = (value) => {
197031
197038
  if (typeof value !== "string") return null;
197032
197039
  const trimmed = value.trim();
@@ -197081,7 +197088,10 @@ var init_commandProvider = __esm({
197081
197088
  if (provider === "sprites") {
197082
197089
  return;
197083
197090
  }
197084
- if (provider === "modal" && command === "connect" && capability === "exec.sessions.open") {
197091
+ if (provider === "modal" && command === "connect" && MODAL_CONNECT_CAPABILITIES.has(capability)) {
197092
+ return;
197093
+ }
197094
+ if (provider === "modal" && command === "mount" && MODAL_MOUNT_CAPABILITIES.has(capability)) {
197085
197095
  return;
197086
197096
  }
197087
197097
  throw new ProviderCapabilityError({
@@ -197091,14 +197101,30 @@ var init_commandProvider = __esm({
197091
197101
  message: `dvb ${command} does not support ${provider} devboxes yet.`
197092
197102
  });
197093
197103
  };
197104
+ hasCommandProviderCapability = ({
197105
+ provider,
197106
+ command,
197107
+ capability
197108
+ }) => {
197109
+ try {
197110
+ assertCommandProviderCapability({ provider, command, capability });
197111
+ return true;
197112
+ } catch (error2) {
197113
+ if (error2 instanceof ProviderCapabilityError && error2.code === "unsupported_capability") {
197114
+ return false;
197115
+ }
197116
+ throw error2;
197117
+ }
197118
+ };
197094
197119
  }
197095
197120
  });
197096
197121
 
197097
197122
  // src/devbox/commands/init/provider/modalRuntime.ts
197098
- var import_node_path16, import_ws3, SERVICE_BASE_DIR, SERVICE_META_SUFFIX, SERVICE_RUN_SUFFIX, SERVICE_PID_SUFFIX, SERVICE_LOG_SUFFIX, SERVICE_NAME_PATTERN, shellQuote2, MODAL_EXEC_WS_PATH2, MODAL_CONNECT_TOKEN_QUERY2, serviceMetaPath, serviceRunnerPath, servicePidPath, serviceLogPath, validateServiceName, isSandboxNotFoundError2, resolveReadPath, buildWsUrlFromConnectToken, decodeBase642, parseJsonRecord2, readCreateConnectToken2, ModalDaemonExecSocket, createModalInitRuntimeClient;
197123
+ var import_node_crypto8, import_node_path16, import_ws3, SERVICE_BASE_DIR, SERVICE_META_SUFFIX, SERVICE_RUN_SUFFIX, SERVICE_PID_SUFFIX, SERVICE_LOG_SUFFIX, SERVICE_NAME_PATTERN, shellQuote2, MODAL_EXEC_WS_PATH2, MODAL_CONNECT_TOKEN_QUERY2, MODAL_DAEMON_HANDSHAKE_TIMEOUT_MS, MODAL_DAEMON_REQUEST_TIMEOUT_MS, MODAL_DAEMON_TTY_HANDSHAKE_TIMEOUT_MS, MODAL_SANDBOX_RESOLVE_TIMEOUT_MS, serviceMetaPath, serviceRunnerPath, servicePidPath, serviceLogPath, validateServiceName, isSandboxNotFoundError2, resolveReadPath, buildWsUrlFromConnectToken, decodeBase642, parseJsonRecord2, readCreateConnectToken2, withTimeout2, connectModalDaemonWebSocket, awaitModalDaemonMessage, parseControlError, mapControlSessionRecord, ModalDaemonExecSocket, createModalInitRuntimeClient;
197099
197124
  var init_modalRuntime = __esm({
197100
197125
  "src/devbox/commands/init/provider/modalRuntime.ts"() {
197101
197126
  "use strict";
197127
+ import_node_crypto8 = require("node:crypto");
197102
197128
  import_node_path16 = __toESM(require("node:path"), 1);
197103
197129
  init_dist3();
197104
197130
  import_ws3 = __toESM(require("ws"), 1);
@@ -197112,6 +197138,10 @@ var init_modalRuntime = __esm({
197112
197138
  shellQuote2 = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
197113
197139
  MODAL_EXEC_WS_PATH2 = "/ws";
197114
197140
  MODAL_CONNECT_TOKEN_QUERY2 = "_modal_connect_token";
197141
+ MODAL_DAEMON_HANDSHAKE_TIMEOUT_MS = 1e4;
197142
+ MODAL_DAEMON_REQUEST_TIMEOUT_MS = 15e3;
197143
+ MODAL_DAEMON_TTY_HANDSHAKE_TIMEOUT_MS = 3e4;
197144
+ MODAL_SANDBOX_RESOLVE_TIMEOUT_MS = 3e4;
197115
197145
  serviceMetaPath = (service) => `${SERVICE_BASE_DIR}/${service}${SERVICE_META_SUFFIX}`;
197116
197146
  serviceRunnerPath = (service) => `${SERVICE_BASE_DIR}/${service}${SERVICE_RUN_SUFFIX}`;
197117
197147
  servicePidPath = (service) => `${SERVICE_BASE_DIR}/${service}${SERVICE_PID_SUFFIX}`;
@@ -197174,6 +197204,122 @@ var init_modalRuntime = __esm({
197174
197204
  }
197175
197205
  return candidate.createConnectToken.bind(candidate);
197176
197206
  };
197207
+ withTimeout2 = async (promise, timeoutMs, message) => {
197208
+ let timeout = null;
197209
+ try {
197210
+ return await Promise.race([
197211
+ promise,
197212
+ new Promise((_2, reject) => {
197213
+ timeout = setTimeout(() => {
197214
+ reject(new Error(message));
197215
+ }, timeoutMs);
197216
+ timeout.unref();
197217
+ })
197218
+ ]);
197219
+ } finally {
197220
+ if (timeout) {
197221
+ clearTimeout(timeout);
197222
+ }
197223
+ }
197224
+ };
197225
+ connectModalDaemonWebSocket = async (sandbox) => {
197226
+ const resolvedSandbox = await sandbox;
197227
+ const createConnectToken = readCreateConnectToken2(resolvedSandbox);
197228
+ const credentials = await createConnectToken();
197229
+ const wsUrl = buildWsUrlFromConnectToken(credentials);
197230
+ const ws = new import_ws3.default(wsUrl);
197231
+ await withTimeout2(
197232
+ new Promise((resolve2, reject) => {
197233
+ const onOpen = () => {
197234
+ ws.off("error", onError);
197235
+ resolve2();
197236
+ };
197237
+ const onError = (error2) => {
197238
+ ws.off("open", onOpen);
197239
+ reject(error2);
197240
+ };
197241
+ ws.once("open", onOpen);
197242
+ ws.once("error", onError);
197243
+ }),
197244
+ MODAL_DAEMON_HANDSHAKE_TIMEOUT_MS,
197245
+ "Timed out connecting to modal daemon websocket."
197246
+ );
197247
+ return ws;
197248
+ };
197249
+ awaitModalDaemonMessage = async (ws, matcher) => await withTimeout2(
197250
+ new Promise((resolve2, reject) => {
197251
+ const onMessage = (raw) => {
197252
+ const parsed = parseJsonRecord2(raw);
197253
+ if (!parsed) {
197254
+ return;
197255
+ }
197256
+ if (parsed.type === "error") {
197257
+ cleanup();
197258
+ const reason = typeof parsed.message === "string" ? parsed.message : "modal daemon error";
197259
+ reject(new Error(reason));
197260
+ return;
197261
+ }
197262
+ if (!matcher(parsed)) {
197263
+ return;
197264
+ }
197265
+ cleanup();
197266
+ resolve2(parsed);
197267
+ };
197268
+ const onClose = (code2, reason) => {
197269
+ cleanup();
197270
+ reject(
197271
+ new Error(
197272
+ `Modal daemon socket closed (${String(code2)}): ${reason.toString("utf8") || "no reason"}`
197273
+ )
197274
+ );
197275
+ };
197276
+ const onError = (error2) => {
197277
+ cleanup();
197278
+ reject(error2);
197279
+ };
197280
+ const cleanup = () => {
197281
+ ws.off("message", onMessage);
197282
+ ws.off("close", onClose);
197283
+ ws.off("error", onError);
197284
+ };
197285
+ ws.on("message", onMessage);
197286
+ ws.once("close", onClose);
197287
+ ws.once("error", onError);
197288
+ }),
197289
+ MODAL_DAEMON_REQUEST_TIMEOUT_MS,
197290
+ "Timed out waiting for modal daemon response."
197291
+ );
197292
+ parseControlError = (message) => {
197293
+ const errorPayload = message.error && typeof message.error === "object" ? message.error : null;
197294
+ const code2 = errorPayload && typeof errorPayload.code === "string" ? errorPayload.code : null;
197295
+ const text = errorPayload && typeof errorPayload.message === "string" ? errorPayload.message : typeof message.message === "string" ? message.message : "Modal daemon control request failed.";
197296
+ return { code: code2, text };
197297
+ };
197298
+ mapControlSessionRecord = (entry) => {
197299
+ if (!entry || typeof entry !== "object") {
197300
+ return null;
197301
+ }
197302
+ const record = entry;
197303
+ const id = typeof record.id === "string" ? record.id : "";
197304
+ if (!id) {
197305
+ return null;
197306
+ }
197307
+ const command = Array.isArray(record.command) ? record.command.map((part) => String(part)) : void 0;
197308
+ const createdAt = typeof record.createdAt === "string" ? record.createdAt : void 0;
197309
+ const lastActivityAt = typeof record.lastActivityAt === "string" ? record.lastActivityAt : void 0;
197310
+ const tty2 = typeof record.tty === "boolean" ? record.tty : void 0;
197311
+ const isActive = typeof record.isActive === "boolean" ? record.isActive : void 0;
197312
+ const bytesPerSecond = typeof record.bytesPerSecond === "number" ? record.bytesPerSecond : void 0;
197313
+ return {
197314
+ id,
197315
+ ...command ? { command } : {},
197316
+ ...createdAt ? { createdAt } : {},
197317
+ ...lastActivityAt ? { lastActivityAt } : {},
197318
+ ...tty2 !== void 0 ? { tty: tty2 } : {},
197319
+ ...isActive !== void 0 ? { isActive } : {},
197320
+ ...bytesPerSecond !== void 0 ? { bytesPerSecond } : {}
197321
+ };
197322
+ };
197177
197323
  ModalDaemonExecSocket = class {
197178
197324
  constructor(sandbox, options) {
197179
197325
  this.sandbox = sandbox;
@@ -197191,6 +197337,7 @@ var init_modalRuntime = __esm({
197191
197337
  ws = null;
197192
197338
  closed = false;
197193
197339
  pongListeners = /* @__PURE__ */ new Set();
197340
+ handshakeTimer = null;
197194
197341
  emit(type, event = {}) {
197195
197342
  for (const listener of this.listeners[type]) {
197196
197343
  listener(event);
@@ -197201,6 +197348,26 @@ var init_modalRuntime = __esm({
197201
197348
  listener();
197202
197349
  }
197203
197350
  }
197351
+ clearHandshakeTimer() {
197352
+ if (!this.handshakeTimer) {
197353
+ return;
197354
+ }
197355
+ clearTimeout(this.handshakeTimer);
197356
+ this.handshakeTimer = null;
197357
+ }
197358
+ startHandshakeTimer() {
197359
+ this.clearHandshakeTimer();
197360
+ this.handshakeTimer = setTimeout(() => {
197361
+ if (this.closed || this.readyState !== 0) {
197362
+ return;
197363
+ }
197364
+ this.emit("error", {
197365
+ data: new Error("Timed out waiting for modal tty session handshake.")
197366
+ });
197367
+ this.close();
197368
+ }, MODAL_DAEMON_TTY_HANDSHAKE_TIMEOUT_MS);
197369
+ this.handshakeTimer.unref();
197370
+ }
197204
197371
  emitMessagePayload(streamId, payload) {
197205
197372
  if (this.closed) return;
197206
197373
  const framed = new Uint8Array(payload.length + 1);
@@ -197218,6 +197385,7 @@ var init_modalRuntime = __esm({
197218
197385
  const type = typeof message.type === "string" ? message.type : "";
197219
197386
  if (type === "tty_ready") {
197220
197387
  const sessionId = typeof message.sessionId === "string" ? message.sessionId : "";
197388
+ this.clearHandshakeTimer();
197221
197389
  this.readyState = 1;
197222
197390
  this.emit("open");
197223
197391
  this.emit("message", {
@@ -197262,15 +197430,21 @@ var init_modalRuntime = __esm({
197262
197430
  const wsUrl = buildWsUrlFromConnectToken(credentials);
197263
197431
  const ws = new import_ws3.default(wsUrl);
197264
197432
  this.ws = ws;
197433
+ this.startHandshakeTimer();
197265
197434
  ws.on("open", () => {
197266
197435
  try {
197267
- this.sendJson({
197436
+ const authPayload = {
197268
197437
  type: "auth",
197269
197438
  mode: "tty",
197270
- command: this.options.cmd,
197271
197439
  cols: this.options.cols,
197272
197440
  rows: this.options.rows
197273
- });
197441
+ };
197442
+ if (this.options.sessionId) {
197443
+ authPayload.sessionId = this.options.sessionId;
197444
+ } else {
197445
+ authPayload.command = this.options.cmd;
197446
+ }
197447
+ this.sendJson(authPayload);
197274
197448
  } catch (error2) {
197275
197449
  this.emit("error", {
197276
197450
  data: error2 instanceof Error ? error2 : new Error(String(error2))
@@ -197287,17 +197461,20 @@ var init_modalRuntime = __esm({
197287
197461
  this.emitPong();
197288
197462
  });
197289
197463
  ws.on("error", (error2) => {
197464
+ this.clearHandshakeTimer();
197290
197465
  this.emit("error", {
197291
197466
  data: error2 instanceof Error ? error2 : new Error(String(error2))
197292
197467
  });
197293
197468
  });
197294
197469
  ws.on("close", (code2) => {
197470
+ this.clearHandshakeTimer();
197295
197471
  if (this.closed) return;
197296
197472
  this.closed = true;
197297
197473
  this.readyState = 3;
197298
197474
  this.emit("close", { code: code2 });
197299
197475
  });
197300
197476
  } catch (error2) {
197477
+ this.clearHandshakeTimer();
197301
197478
  const err = error2 instanceof Error ? error2 : new Error(String(error2));
197302
197479
  this.emit("error", { data: err });
197303
197480
  this.close();
@@ -197326,6 +197503,11 @@ var init_modalRuntime = __esm({
197326
197503
  cb?.();
197327
197504
  return;
197328
197505
  }
197506
+ if (record.type === "detach") {
197507
+ this.sendJson({ type: "detach" });
197508
+ cb?.();
197509
+ return;
197510
+ }
197329
197511
  }
197330
197512
  } catch {
197331
197513
  }
@@ -197347,6 +197529,7 @@ var init_modalRuntime = __esm({
197347
197529
  }
197348
197530
  close() {
197349
197531
  if (this.closed) return;
197532
+ this.clearHandshakeTimer();
197350
197533
  this.closed = true;
197351
197534
  this.readyState = 3;
197352
197535
  if (this.ws && this.ws.readyState <= import_ws3.default.OPEN) {
@@ -197425,7 +197608,11 @@ var init_modalRuntime = __esm({
197425
197608
  if (sandboxPromise) return sandboxPromise;
197426
197609
  sandboxPromise = (async () => {
197427
197610
  try {
197428
- const runningSandbox = await modal.sandboxes.fromName(appName, alias);
197611
+ const runningSandbox = await withTimeout2(
197612
+ modal.sandboxes.fromName(appName, alias),
197613
+ MODAL_SANDBOX_RESOLVE_TIMEOUT_MS,
197614
+ "Timed out resolving running modal sandbox by name."
197615
+ );
197429
197616
  sandboxId = runningSandbox.sandboxId;
197430
197617
  return runningSandbox;
197431
197618
  } catch (error2) {
@@ -197434,12 +197621,24 @@ var init_modalRuntime = __esm({
197434
197621
  }
197435
197622
  }
197436
197623
  if (ensureActive) {
197437
- const ensured = await ensureActive(intent);
197624
+ const ensured = await withTimeout2(
197625
+ ensureActive(intent),
197626
+ MODAL_SANDBOX_RESOLVE_TIMEOUT_MS,
197627
+ "Timed out waiting for modal devbox wake."
197628
+ );
197438
197629
  appName = ensured.appName;
197439
197630
  sandboxId = ensured.sandboxId;
197440
- return await modal.sandboxes.fromId(ensured.sandboxId);
197631
+ return await withTimeout2(
197632
+ modal.sandboxes.fromId(ensured.sandboxId),
197633
+ MODAL_SANDBOX_RESOLVE_TIMEOUT_MS,
197634
+ "Timed out resolving modal sandbox after wake."
197635
+ );
197441
197636
  }
197442
- return await modal.sandboxes.fromId(sandboxId);
197637
+ return await withTimeout2(
197638
+ modal.sandboxes.fromId(sandboxId),
197639
+ MODAL_SANDBOX_RESOLVE_TIMEOUT_MS,
197640
+ "Timed out resolving modal sandbox by id."
197641
+ );
197443
197642
  })().catch((error2) => {
197444
197643
  sandboxPromise = null;
197445
197644
  throw error2;
@@ -197696,10 +197895,102 @@ var init_modalRuntime = __esm({
197696
197895
  }
197697
197896
  ];
197698
197897
  };
197898
+ const parseKillTimeoutOption = (value) => {
197899
+ if (!value) return void 0;
197900
+ const trimmed = value.trim().toLowerCase();
197901
+ if (!trimmed) return void 0;
197902
+ const match2 = /^(\d+)(ms|s|m)?$/.exec(trimmed);
197903
+ if (!match2) return void 0;
197904
+ const amount = Number.parseInt(match2[1] ?? "", 10);
197905
+ if (!Number.isFinite(amount) || amount <= 0) {
197906
+ return void 0;
197907
+ }
197908
+ const unit = match2[2] ?? "ms";
197909
+ if (unit === "ms") return amount;
197910
+ if (unit === "s") return amount * 1e3;
197911
+ if (unit === "m") return amount * 6e4;
197912
+ return void 0;
197913
+ };
197914
+ const runControlRequest = async (requestPayload, expectedType) => {
197915
+ const ws = await connectModalDaemonWebSocket(resolveSandbox());
197916
+ const requestId = (0, import_node_crypto8.randomUUID)().replace(/-/g, "");
197917
+ try {
197918
+ ws.send(JSON.stringify({ type: "auth", mode: "control" }));
197919
+ await awaitModalDaemonMessage(
197920
+ ws,
197921
+ (message) => message.type === "control_ready"
197922
+ );
197923
+ ws.send(JSON.stringify({ ...requestPayload, requestId }));
197924
+ return await awaitModalDaemonMessage(
197925
+ ws,
197926
+ (message) => message.type === expectedType && message.requestId === requestId
197927
+ );
197928
+ } finally {
197929
+ if (ws.readyState === import_ws3.default.OPEN) {
197930
+ ws.close();
197931
+ } else if (ws.readyState === import_ws3.default.CONNECTING) {
197932
+ ws.terminate();
197933
+ }
197934
+ }
197935
+ };
197936
+ const listExecSessions2 = async (name) => {
197937
+ requireAlias(name);
197938
+ const response = await runControlRequest(
197939
+ { type: "sessions_list" },
197940
+ "sessions_list_result"
197941
+ );
197942
+ if (response.status !== "ok") {
197943
+ const { text } = parseControlError(response);
197944
+ throw new Error(text);
197945
+ }
197946
+ const records = Array.isArray(response.sessions) ? response.sessions : [];
197947
+ const sessions = [];
197948
+ for (const entry of records) {
197949
+ const mapped = mapControlSessionRecord(entry);
197950
+ if (!mapped) continue;
197951
+ sessions.push(mapped);
197952
+ }
197953
+ return sessions;
197954
+ };
197955
+ const killExecSession = async (name, sessionId, options) => {
197956
+ requireAlias(name);
197957
+ const timeoutMs = parseKillTimeoutOption(options?.timeout);
197958
+ const response = await runControlRequest(
197959
+ {
197960
+ type: "session_kill",
197961
+ sessionId,
197962
+ ...options?.signal ? { signal: options.signal } : {},
197963
+ ...typeof timeoutMs === "number" ? { timeoutMs } : {}
197964
+ },
197965
+ "session_kill_result"
197966
+ );
197967
+ if (response.status !== "ok") {
197968
+ const { code: code2, text } = parseControlError(response);
197969
+ if (code2 === "not_found") {
197970
+ throw new SpritesApiError(
197971
+ 404,
197972
+ "DELETE",
197973
+ `/v1/sprites/${encodeURIComponent(name)}/exec/${encodeURIComponent(sessionId)}`,
197974
+ text
197975
+ );
197976
+ }
197977
+ throw new Error(text);
197978
+ }
197979
+ return Array.isArray(response.events) ? response.events.filter((entry) => entry && typeof entry === "object").map((entry) => entry) : [{ event: "killed", session_id: sessionId }];
197980
+ };
197699
197981
  const openExecSession = (name, options) => {
197700
197982
  requireAlias(name);
197701
197983
  return new ModalDaemonExecSocket(resolveSandbox("shell"), options);
197702
197984
  };
197985
+ const attachExecSession = (name, sessionId) => {
197986
+ requireAlias(name);
197987
+ return new ModalDaemonExecSocket(resolveSandbox(), {
197988
+ cmd: [],
197989
+ tty: true,
197990
+ stdin: true,
197991
+ sessionId
197992
+ });
197993
+ };
197703
197994
  const createCheckpoint = async (_name, options) => {
197704
197995
  const sandbox = await resolveSandbox();
197705
197996
  const image = await sandbox.snapshotFilesystem();
@@ -197718,18 +198009,21 @@ var init_modalRuntime = __esm({
197718
198009
  writeFile: writeFile2,
197719
198010
  readFile: readFile3,
197720
198011
  exec,
198012
+ listExecSessions: listExecSessions2,
198013
+ killExecSession,
197721
198014
  createCheckpoint,
197722
198015
  getService,
197723
198016
  createService,
197724
198017
  startService: startService2,
197725
- openExecSession
198018
+ openExecSession,
198019
+ attachExecSession
197726
198020
  };
197727
198021
  };
197728
198022
  }
197729
198023
  });
197730
198024
 
197731
198025
  // src/devbox/commands/provider/modalLifecycle.ts
197732
- var DEFAULT_APP_NAME, DEFAULT_MODAL_DEVBOX_IMAGE, DEFAULT_TIMEOUT_MS, SANDBOX_LIST_PAGE_LIMIT, FINISHED_STATUS_LABELS, trimEnv3, decodeJwtExpMs, createSafeModalAuthTokenManager, installSafeModalAuthTokenManager, parsePositiveInt, resolveRegions, resolveAppName, resolveModalSandboxTimeoutMs, isNotFoundError, isModalAlreadyExistsError, withModalClient, resolveModalApp, listSandboxesRaw, formatSandboxStatus, isRunningSandbox, resolveImageFromTag, provisionModalSandbox, findModalSandbox, terminateModalSandboxesByAlias;
198026
+ var DEFAULT_APP_NAME, DEFAULT_MODAL_DEVBOX_IMAGE, DEFAULT_TIMEOUT_MS, SANDBOX_LIST_PAGE_LIMIT, MODAL_DAEMON_WRAPPER_PATH, MODAL_DAEMON_SUPERVISOR_ENTRYPOINT, FINISHED_STATUS_LABELS, trimEnv3, decodeJwtExpMs, createSafeModalAuthTokenManager, installSafeModalAuthTokenManager, parsePositiveInt, resolveRegions, resolveAppName, resolveModalSandboxTimeoutMs, isNotFoundError, isModalAlreadyExistsError, withModalClient, resolveModalApp, listSandboxesRaw, formatSandboxStatus, isRunningSandbox, resolveImageFromTag, provisionModalSandbox, findModalSandbox, terminateModalSandboxesByAlias;
197733
198027
  var init_modalLifecycle = __esm({
197734
198028
  "src/devbox/commands/provider/modalLifecycle.ts"() {
197735
198029
  "use strict";
@@ -197739,6 +198033,22 @@ var init_modalLifecycle = __esm({
197739
198033
  DEFAULT_MODAL_DEVBOX_IMAGE = "public.ecr.aws/d8m4p4w9/modal-devbox:latest";
197740
198034
  DEFAULT_TIMEOUT_MS = 24 * 60 * 60 * 1e3;
197741
198035
  SANDBOX_LIST_PAGE_LIMIT = 100;
198036
+ MODAL_DAEMON_WRAPPER_PATH = "/home/sprite/.devbox/daemon/run-daemon.sh";
198037
+ MODAL_DAEMON_SUPERVISOR_ENTRYPOINT = [
198038
+ "/bin/sh",
198039
+ "-lc",
198040
+ [
198041
+ "set -u",
198042
+ `wrapper=${JSON.stringify(MODAL_DAEMON_WRAPPER_PATH)}`,
198043
+ 'until [ -x "$wrapper" ]; do sleep 0.25; done',
198044
+ "while true; do",
198045
+ ' "$wrapper"',
198046
+ " status=$?",
198047
+ ' echo "sprite-daemon exited with status $status; restarting" >&2',
198048
+ " sleep 1",
198049
+ "done"
198050
+ ].join("\n")
198051
+ ];
197742
198052
  FINISHED_STATUS_LABELS = {
197743
198053
  1: "success",
197744
198054
  2: "failure",
@@ -197942,6 +198252,7 @@ var init_modalLifecycle = __esm({
197942
198252
  timeoutSecs,
197943
198253
  name: alias,
197944
198254
  ...regions.length > 0 ? { schedulerPlacement: { regions } } : {},
198255
+ entrypointArgs: MODAL_DAEMON_SUPERVISOR_ENTRYPOINT,
197945
198256
  enableSnapshot: true
197946
198257
  }
197947
198258
  });
@@ -198087,10 +198398,11 @@ var init_providerClient = __esm({
198087
198398
  appName,
198088
198399
  sandboxId,
198089
198400
  operationOptions,
198090
- ensureActive
198401
+ ensureActive,
198402
+ runtimeClient
198091
198403
  }) => {
198092
198404
  assertModalRuntimeCredentialPair(operationOptions);
198093
- const runtime = createModalInitRuntimeClient({
198405
+ const runtime = runtimeClient ?? createModalInitRuntimeClient({
198094
198406
  alias,
198095
198407
  appName,
198096
198408
  sandboxId,
@@ -198107,8 +198419,8 @@ var init_providerClient = __esm({
198107
198419
  writeFile: runtime.writeFile,
198108
198420
  readFile: runtime.readFile,
198109
198421
  exec: runtime.exec,
198110
- listExecSessions: async () => throwModalConnectUnsupported("listExecSessions (modal connect client)"),
198111
- killExecSession: async () => throwModalConnectUnsupported("killExecSession (modal connect client)"),
198422
+ listExecSessions: runtime.listExecSessions,
198423
+ killExecSession: runtime.killExecSession,
198112
198424
  createCheckpoint: runtime.createCheckpoint,
198113
198425
  listServices: async () => throwModalConnectUnsupported("listServices (modal connect client)"),
198114
198426
  getService: runtime.getService,
@@ -198116,7 +198428,7 @@ var init_providerClient = __esm({
198116
198428
  startService: runtime.startService,
198117
198429
  stopService: async () => throwModalConnectUnsupported("stopService (modal connect client)"),
198118
198430
  openExecSession: runtime.openExecSession,
198119
- attachExecSession: () => throwModalConnectUnsupported("attachExecSession (modal connect client)"),
198431
+ attachExecSession: runtime.attachExecSession,
198120
198432
  openProxySocket: () => throwModalConnectUnsupported("openProxySocket (modal connect client)")
198121
198433
  };
198122
198434
  };
@@ -198289,6 +198601,76 @@ var init_providerClient = __esm({
198289
198601
  }
198290
198602
  });
198291
198603
 
198604
+ // src/devbox/commands/provider/modalCommandContext.ts
198605
+ var resolveModalCommandContext;
198606
+ var init_modalCommandContext = __esm({
198607
+ "src/devbox/commands/provider/modalCommandContext.ts"() {
198608
+ "use strict";
198609
+ init_src();
198610
+ init_auth();
198611
+ init_controlPlane();
198612
+ init_providerClient();
198613
+ resolveModalCommandContext = async (options) => {
198614
+ const config4 = await loadConfig(
198615
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
198616
+ );
198617
+ const store = await createSecretStore(
198618
+ config4?.tokenStore,
198619
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
198620
+ );
198621
+ const modalCredentialContext = createProviderCredentialContext({
198622
+ mode: "auto",
198623
+ controlPlaneToken: await store.getControlPlaneToken()
198624
+ });
198625
+ let operationOptions = await resolveModalCommandOperationOptions({
198626
+ credentials: modalCredentialContext,
198627
+ cwd: options.cwd
198628
+ });
198629
+ if (operationOptions.credentialMode === "shared" && (!operationOptions.credentials.modalTokenId || !operationOptions.credentials.modalTokenSecret)) {
198630
+ const controlPlaneToken2 = await ensureControlPlaneToken(
198631
+ store,
198632
+ options.stage
198633
+ );
198634
+ if (controlPlaneToken2) {
198635
+ operationOptions = await resolveModalCommandOperationOptions({
198636
+ credentials: createProviderCredentialContext({
198637
+ mode: "auto",
198638
+ controlPlaneToken: controlPlaneToken2
198639
+ }),
198640
+ cwd: options.cwd
198641
+ });
198642
+ }
198643
+ }
198644
+ let controlPlaneToken = modalCredentialContext.controlPlaneToken;
198645
+ const ensureActive = async (intent) => {
198646
+ if (!controlPlaneToken) {
198647
+ controlPlaneToken = await ensureControlPlaneToken(store, options.stage);
198648
+ }
198649
+ if (!controlPlaneToken) {
198650
+ throw new Error(
198651
+ "Control plane authentication is required to wake modal devboxes. Run `dvb setup` and retry."
198652
+ );
198653
+ }
198654
+ const ensured = await ensureModalDevboxActive2(
198655
+ controlPlaneToken,
198656
+ options.alias,
198657
+ intent
198658
+ );
198659
+ return {
198660
+ appName: ensured.appName,
198661
+ sandboxId: ensured.sandboxId,
198662
+ woke: ensured.woke,
198663
+ wakeSource: ensured.wakeSource
198664
+ };
198665
+ };
198666
+ return {
198667
+ operationOptions,
198668
+ ensureActive
198669
+ };
198670
+ };
198671
+ }
198672
+ });
198673
+
198292
198674
  // src/devbox/commands/sessionUtils.ts
198293
198675
  var AUTO_SESSION_PREFIX, parseAutoSessionSuffix, getNextAutoSessionName, ensureUniqueAutoSessionName, shellQuote3, sanitizeSessionName, buildSessionLogPath, renameSessionLog;
198294
198676
  var init_sessionUtils = __esm({
@@ -198341,12 +198723,12 @@ var init_sessionUtils = __esm({
198341
198723
  });
198342
198724
 
198343
198725
  // src/devbox/commands/connect.ts
198344
- var import_node_child_process4, import_node_crypto8, import_node_os10, import_node_path17, import_node_readline3, import_promises13, DEFAULT_TTY_COLS, DEFAULT_TTY_ROWS, TERMINAL_INPUT_MODE_RESET, resetTerminalInputModes, openBrowser2, warnSetupStatus, resolveTtyEnv, formatEnvExports, parseEnvSize, readStreamSize, resolveTtySize, resolveSessionEnv, parseReachabilityState, runCommand, checkReachability, watchReachabilityWithScutil, watchReachabilityWithNotifyutil, waitForNetworkOnline, parseConnectArgs, parseConnectTarget, buildLoggingCommand, CONNECT_SHELL_CANDIDATES, resolveConnectShell, confirmNewSession, promptRenameSession, HEARTBEAT_INTERVAL_MS, HEARTBEAT_TIMEOUT_MS, INPUT_PROBE_TIMEOUT_MS, WS_OPEN_STATE, streamExecSession, runConnect;
198726
+ var import_node_child_process4, import_node_crypto9, import_node_os10, import_node_path17, import_node_readline3, import_promises13, DEFAULT_TTY_COLS, DEFAULT_TTY_ROWS, TERMINAL_INPUT_MODE_RESET, resetTerminalInputModes, openBrowser2, warnSetupStatus, resolveTtyEnv, formatEnvExports, parseEnvSize, readStreamSize, resolveTtySize, resolveSessionEnv, parseReachabilityState, runCommand, checkReachability, watchReachabilityWithScutil, watchReachabilityWithNotifyutil, waitForNetworkOnline, parseConnectArgs, parseConnectTarget, buildLoggingCommand, CONNECT_SHELL_CANDIDATES, resolveConnectShell, confirmNewSession, promptRenameSession, HEARTBEAT_INTERVAL_MS, HEARTBEAT_TIMEOUT_MS, INPUT_PROBE_TIMEOUT_MS, WS_OPEN_STATE, streamExecSession, runConnect;
198345
198727
  var init_connect2 = __esm({
198346
198728
  "src/devbox/commands/connect.ts"() {
198347
198729
  "use strict";
198348
198730
  import_node_child_process4 = require("node:child_process");
198349
- import_node_crypto8 = require("node:crypto");
198731
+ import_node_crypto9 = require("node:crypto");
198350
198732
  import_node_os10 = __toESM(require("node:os"), 1);
198351
198733
  import_node_path17 = require("node:path");
198352
198734
  import_node_readline3 = require("node:readline");
@@ -198355,7 +198737,6 @@ var init_connect2 = __esm({
198355
198737
  init_src();
198356
198738
  init_daemonClient();
198357
198739
  init_auth();
198358
- init_controlPlane();
198359
198740
  init_logger3();
198360
198741
  init_latency();
198361
198742
  init_osc();
@@ -198364,7 +198745,7 @@ var init_connect2 = __esm({
198364
198745
  init_boxSelect();
198365
198746
  init_commandProvider();
198366
198747
  init_providerClient();
198367
- init_modalLifecycle();
198748
+ init_modalCommandContext();
198368
198749
  init_sessionUtils();
198369
198750
  DEFAULT_TTY_COLS = 80;
198370
198751
  DEFAULT_TTY_ROWS = 24;
@@ -198705,7 +199086,8 @@ var init_connect2 = __esm({
198705
199086
  return { box, session };
198706
199087
  };
198707
199088
  buildLoggingCommand = (logPath, shellCommand) => [
198708
- 'mkdir -p "$HOME/.devbox/logs"',
199089
+ `log_dir=$(dirname ${shellQuote3(logPath)})`,
199090
+ 'mkdir -p "$log_dir"',
198709
199091
  "if command -v script >/dev/null 2>&1; then",
198710
199092
  ` exec script -q -f -a ${shellQuote3(logPath)} -c ${shellQuote3(shellCommand)}`,
198711
199093
  "else",
@@ -199282,93 +199664,42 @@ var init_connect2 = __esm({
199282
199664
  command: "connect",
199283
199665
  capability: "exec.sessions.open"
199284
199666
  });
199285
- const supportsAttachExecSession = computeProvider === "sprites";
199667
+ const supportsAttachExecSession = hasCommandProviderCapability({
199668
+ provider: computeProvider,
199669
+ command: "connect",
199670
+ capability: "exec.sessions.attach"
199671
+ });
199672
+ const supportsListExecSessions = hasCommandProviderCapability({
199673
+ provider: computeProvider,
199674
+ command: "connect",
199675
+ capability: "exec.sessions.list"
199676
+ });
199286
199677
  const supportsResizeControlMessages = computeProvider === "sprites" || computeProvider === "modal";
199287
- if (computeProvider === "modal") {
199288
- if (isDetached) {
199289
- throw new Error(
199290
- "`dvb connect --detach` is not supported for modal devboxes yet."
199291
- );
199292
- }
199293
- if (sessionName) {
199294
- throw new Error(
199295
- "Named sessions are not supported for modal devboxes yet. Re-run without `--name` or `<box>/<session>`."
199296
- );
199297
- }
199298
- autoNameRequested = false;
199299
- shouldLog2 = false;
199300
- }
199301
199678
  let client2;
199302
199679
  let networkTargetHost = null;
199303
199680
  if (computeProvider === "modal") {
199304
199681
  stage("Loading modal auth");
199305
- const config4 = await loadConfig(
199306
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
199307
- );
199308
- const store = await createSecretStore(
199309
- config4?.tokenStore,
199310
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
199311
- );
199312
- const modalCredentialContext = createProviderCredentialContext({
199313
- mode: "auto",
199314
- controlPlaneToken: await store.getControlPlaneToken()
199315
- });
199316
- let modalOperationOptions = await resolveModalCommandOperationOptions({
199317
- credentials: modalCredentialContext,
199318
- cwd: process.cwd()
199682
+ const modalContext = await resolveModalCommandContext({
199683
+ alias: spriteAlias,
199684
+ cwd: process.cwd(),
199685
+ stage
199319
199686
  });
199320
- if (modalOperationOptions.credentialMode === "shared" && (!modalOperationOptions.credentials.modalTokenId || !modalOperationOptions.credentials.modalTokenSecret)) {
199321
- const controlPlaneToken2 = await ensureControlPlaneToken(store, stage);
199322
- if (controlPlaneToken2) {
199323
- modalOperationOptions = await resolveModalCommandOperationOptions({
199324
- credentials: createProviderCredentialContext({
199325
- mode: "auto",
199326
- controlPlaneToken: controlPlaneToken2
199327
- }),
199328
- cwd: process.cwd()
199329
- });
199330
- }
199331
- }
199332
- let controlPlaneToken = modalCredentialContext.controlPlaneToken;
199333
199687
  const ensureActive = async (intent) => {
199334
- if (!controlPlaneToken) {
199335
- controlPlaneToken = await ensureControlPlaneToken(store, stage);
199336
- }
199337
- if (!controlPlaneToken) {
199338
- throw new Error(
199339
- "Control plane authentication is required to wake modal devboxes. Run `dvb setup` and retry."
199340
- );
199341
- }
199342
- const ensured = await ensureModalDevboxActive2(
199343
- controlPlaneToken,
199344
- spriteAlias,
199345
- intent
199346
- );
199688
+ const ensured2 = await modalContext.ensureActive(intent);
199347
199689
  return {
199348
- appName: ensured.appName,
199349
- sandboxId: ensured.sandboxId
199690
+ appName: ensured2.appName,
199691
+ sandboxId: ensured2.sandboxId
199350
199692
  };
199351
199693
  };
199352
- stage("Checking modal sandbox");
199353
- const sandbox = await findModalSandbox(
199354
- {
199355
- alias: spriteAlias,
199356
- includeFinished: true
199357
- },
199358
- modalOperationOptions
199359
- );
199360
- let appName = sandbox?.appName ?? "";
199361
- let sandboxId = sandbox?.sandboxId ?? "";
199362
- if (!appName || !sandboxId) {
199363
- const ensured = await ensureActive("shell");
199364
- appName = ensured.appName;
199365
- sandboxId = ensured.sandboxId;
199366
- }
199694
+ stage("Ensuring modal sandbox");
199695
+ const ensured = await ensureActive("shell");
199696
+ const appName = ensured.appName;
199697
+ const sandboxId = ensured.sandboxId;
199367
199698
  client2 = createModalConnectSpritesClient({
199368
199699
  alias: spriteAlias,
199369
199700
  appName,
199370
199701
  sandboxId,
199371
- operationOptions: modalOperationOptions,
199702
+ operationOptions: modalContext.operationOptions,
199372
199703
  ensureActive
199373
199704
  });
199374
199705
  } else {
@@ -199526,7 +199857,7 @@ var init_connect2 = __esm({
199526
199857
  if (!sessionName) return;
199527
199858
  sessions = await readSessionsSafe(sessions);
199528
199859
  sessionId = sessions[sessionName];
199529
- if (sessionId) {
199860
+ if (sessionId && supportsListExecSessions) {
199530
199861
  const available = await client2.listExecSessions(spriteAlias);
199531
199862
  const match2 = available.find((session) => session.id === sessionId);
199532
199863
  if (!match2 || match2.tty === false) {
@@ -199597,7 +199928,7 @@ var init_connect2 = __esm({
199597
199928
  const weztermPane = process.env.WEZTERM_PANE?.trim() || "";
199598
199929
  const weztermSocket = process.env.WEZTERM_UNIX_SOCKET?.trim() || "";
199599
199930
  const weztermSessionId = weztermPane ? `wezterm:${weztermPane}${weztermSocket ? `:${(0, import_node_path17.basename)(weztermSocket)}` : ""}` : "";
199600
- const terminalSessionId = process.env.DEVBOX_TERM_SESSION_ID?.trim() || weztermSessionId || process.env.TERM_SESSION_ID?.trim() || process.env.ITERM_SESSION_ID?.trim() || `dvb-${(0, import_node_crypto8.randomUUID)()}`;
199931
+ const terminalSessionId = process.env.DEVBOX_TERM_SESSION_ID?.trim() || weztermSessionId || process.env.TERM_SESSION_ID?.trim() || process.env.ITERM_SESSION_ID?.trim() || `dvb-${(0, import_node_crypto9.randomUUID)()}`;
199601
199932
  const execCommand2 = (() => {
199602
199933
  const sessionEnv = resolveSessionEnv(terminalSessionId);
199603
199934
  const ttyEnv = isTty ? resolveTtyEnv(terminalSessionId) : null;
@@ -199866,14 +200197,16 @@ ${message}\r
199866
200197
  console.error("Connection lost. Reconnecting... (Ctrl+C to cancel)");
199867
200198
  reconnectNoticeShown = true;
199868
200199
  }
199869
- if (result.opened === false && sessionId && supportsAttachExecSession) {
200200
+ if (result.opened === false && sessionId && supportsAttachExecSession && supportsListExecSessions) {
199870
200201
  try {
199871
200202
  const available = await client2.listExecSessions(spriteAlias);
199872
200203
  const match2 = available.find((session) => session.id === sessionId);
199873
- if ((!match2 || match2.tty === false) && sessionName) {
199874
- delete sessions[sessionName];
200204
+ if (!match2 || match2.tty === false) {
200205
+ if (sessionName) {
200206
+ delete sessions[sessionName];
200207
+ await writeSpriteSessions(client2, spriteAlias, sessions);
200208
+ }
199875
200209
  sessionId = void 0;
199876
- await writeSpriteSessions(client2, spriteAlias, sessions);
199877
200210
  }
199878
200211
  } catch (error2) {
199879
200212
  logger7.warn("session_lookup_failed", { error: String(error2) });
@@ -201209,11 +201542,11 @@ var init_session3 = __esm({
201209
201542
  });
201210
201543
 
201211
201544
  // src/devbox/commands/init/repo.ts
201212
- var import_node_crypto9, import_node_child_process5, import_node_path21, buildSpawnEnv, runCommand2, runCommandRaw, findRepoRoot, readRepoOrigin, readLocalGitConfigValue, writeLocalGitConfigValue, ensureRepoProjectId, resolveGitCommonDir, readHeadState, readNullSeparatedPaths, readWorktreeState, confirmCopyWorktree, readGlobalGitConfigFiles, mapGlobalGitConfigDestinations;
201545
+ var import_node_crypto10, import_node_child_process5, import_node_path21, buildSpawnEnv, runCommand2, runCommandRaw, findRepoRoot, readRepoOrigin, readLocalGitConfigValue, writeLocalGitConfigValue, ensureRepoProjectId, resolveGitCommonDir, readHeadState, readNullSeparatedPaths, readWorktreeState, confirmCopyWorktree, readGlobalGitConfigFiles, mapGlobalGitConfigDestinations;
201213
201546
  var init_repo2 = __esm({
201214
201547
  "src/devbox/commands/init/repo.ts"() {
201215
201548
  "use strict";
201216
- import_node_crypto9 = require("node:crypto");
201549
+ import_node_crypto10 = require("node:crypto");
201217
201550
  import_node_child_process5 = require("node:child_process");
201218
201551
  import_node_path21 = __toESM(require("node:path"), 1);
201219
201552
  init_dist5();
@@ -201300,7 +201633,7 @@ var init_repo2 = __esm({
201300
201633
  const key = "devbox.projectId";
201301
201634
  const existing = await readLocalGitConfigValue(repoRoot, key);
201302
201635
  if (existing) return existing;
201303
- const created = (0, import_node_crypto9.randomUUID)();
201636
+ const created = (0, import_node_crypto10.randomUUID)();
201304
201637
  await writeLocalGitConfigValue(repoRoot, key, created);
201305
201638
  return created;
201306
201639
  };
@@ -201425,11 +201758,11 @@ var init_weztermMux = __esm({
201425
201758
  });
201426
201759
 
201427
201760
  // src/devbox/commands/init/remote.ts
201428
- var import_node_crypto10, DAEMON_DIR, DAEMON_TARBALL, DAEMON_BUNDLE_DIR, DAEMON_ENTRY, DAEMON_WRAPPER, DAEMON_SERVICE_NAME, DAEMON_CONFIG_FILE, DEFAULT_DAEMON_BASE_URL, DEFAULT_HEARTBEAT_MS, BOOTSTRAP_EXEC_TIMEOUT_MS, BOOTSTRAP_EXEC_HANDSHAKE_TIMEOUT_MS, BASHRC_PATH, ZSHRC_PATH, BASIC_ALIASES_MARKER, LEGACY_BASH_TRAP, SAFE_BASH_TRAP, BASH_HISTORY_BLOCK, ZSH_HISTORY_BLOCK, HISTORY_BLOCK_PATTERN, BASH_HISTORY_LINE_PATTERN, ZSH_HISTORY_LINE_PATTERN, logger8, truncateTail, shellQuote4, expandHome2, execWithLog, writeRemoteFile, readRemoteFile, ensureTrailingNewline, upsertHistoryBlock, patchBashrcContent, patchZshrcContent, bootstrapDevbox, buildWeztermMuxConfig, buildWeztermMuxRunner, patchRemoteRcFile, patchBashrc, patchZshrc, stageRemoteSetupArtifacts, resolveDaemonUrl, fetchDaemonBinary, buildDaemonConfig, buildDaemonWrapperScript, isSameArgs, ensureSpriteDaemonService, installWeztermMux, ensureWeztermMuxService, hasWeztermMuxBinary, isWeztermMuxHealthy, installSpriteDaemon;
201761
+ var import_node_crypto11, DAEMON_DIR, DAEMON_TARBALL, DAEMON_BUNDLE_DIR, DAEMON_ENTRY, DAEMON_WRAPPER, DAEMON_SERVICE_NAME, DAEMON_CONFIG_FILE, MODAL_DAEMON_HEALTH_PORT, DEFAULT_DAEMON_BASE_URL, DEFAULT_HEARTBEAT_MS, BOOTSTRAP_EXEC_TIMEOUT_MS, BOOTSTRAP_EXEC_HANDSHAKE_TIMEOUT_MS, BASHRC_PATH, ZSHRC_PATH, BASIC_ALIASES_MARKER, LEGACY_BASH_TRAP, SAFE_BASH_TRAP, BASH_HISTORY_BLOCK, ZSH_HISTORY_BLOCK, HISTORY_BLOCK_PATTERN, BASH_HISTORY_LINE_PATTERN, ZSH_HISTORY_LINE_PATTERN, logger8, truncateTail, shellQuote4, expandHome2, execWithLog, writeRemoteFile, readRemoteFile, ensureTrailingNewline, upsertHistoryBlock, patchBashrcContent, patchZshrcContent, bootstrapDevbox, buildWeztermMuxConfig, buildWeztermMuxRunner, patchRemoteRcFile, patchBashrc, patchZshrc, stageRemoteSetupArtifacts, resolveDaemonUrl, fetchDaemonBinary, buildDaemonConfig, buildDaemonWrapperScript, isSameArgs, ensureSpriteDaemonService, installWeztermMux, ensureWeztermMuxService, hasWeztermMuxBinary, isWeztermMuxHealthy, installSpriteDaemon;
201429
201762
  var init_remote = __esm({
201430
201763
  "src/devbox/commands/init/remote.ts"() {
201431
201764
  "use strict";
201432
- import_node_crypto10 = require("node:crypto");
201765
+ import_node_crypto11 = require("node:crypto");
201433
201766
  init_src();
201434
201767
  init_weztermMux();
201435
201768
  DAEMON_DIR = "/home/sprite/.devbox/daemon";
@@ -201439,6 +201772,7 @@ var init_remote = __esm({
201439
201772
  DAEMON_WRAPPER = `${DAEMON_DIR}/run-daemon.sh`;
201440
201773
  DAEMON_SERVICE_NAME = "devbox-sprite-daemon";
201441
201774
  DAEMON_CONFIG_FILE = `${DAEMON_DIR}/config.json`;
201775
+ MODAL_DAEMON_HEALTH_PORT = 8080;
201442
201776
  DEFAULT_DAEMON_BASE_URL = process.env.SPRITE_DAEMON_BASE_URL?.trim() || "https://deploy-dev.boxes.dev";
201443
201777
  DEFAULT_HEARTBEAT_MS = 3e4;
201444
201778
  BOOTSTRAP_EXEC_TIMEOUT_MS = 9e4;
@@ -201482,7 +201816,7 @@ var init_remote = __esm({
201482
201816
  return value;
201483
201817
  };
201484
201818
  execWithLog = async (client2, spriteAlias, script, stage, options) => {
201485
- const requestId = (0, import_node_crypto10.randomUUID)();
201819
+ const requestId = (0, import_node_crypto11.randomUUID)();
201486
201820
  const startedAt2 = Date.now();
201487
201821
  logger8.info("sprites_request", {
201488
201822
  requestId,
@@ -201516,7 +201850,7 @@ var init_remote = __esm({
201516
201850
  return result;
201517
201851
  };
201518
201852
  writeRemoteFile = async (client2, spriteAlias, path38, content, stage) => {
201519
- const requestId = (0, import_node_crypto10.randomUUID)();
201853
+ const requestId = (0, import_node_crypto11.randomUUID)();
201520
201854
  logger8.info("sprites_request", {
201521
201855
  requestId,
201522
201856
  method: "writeFile",
@@ -201536,7 +201870,7 @@ var init_remote = __esm({
201536
201870
  });
201537
201871
  };
201538
201872
  readRemoteFile = async (client2, spriteAlias, path38, stage) => {
201539
- const requestId = (0, import_node_crypto10.randomUUID)();
201873
+ const requestId = (0, import_node_crypto11.randomUUID)();
201540
201874
  logger8.info("sprites_request", {
201541
201875
  requestId,
201542
201876
  method: "readFile",
@@ -202074,8 +202408,45 @@ ${canonicalBlock}
202074
202408
  };
202075
202409
  ensureSpriteDaemonService = async ({
202076
202410
  client: client2,
202077
- spriteName
202411
+ spriteName,
202412
+ computeProvider
202078
202413
  }) => {
202414
+ if (computeProvider === "modal") {
202415
+ const script = [
202416
+ "set -euo pipefail",
202417
+ `wrapper=${shellQuote4(DAEMON_WRAPPER)}`,
202418
+ `health_port=${String(MODAL_DAEMON_HEALTH_PORT)}`,
202419
+ 'if [ ! -x "$wrapper" ]; then',
202420
+ ' echo "missing sprite-daemon wrapper" >&2',
202421
+ " exit 1",
202422
+ "fi",
202423
+ "ready=0",
202424
+ "for _ in $(seq 1 120); do",
202425
+ ' if (echo >"/dev/tcp/127.0.0.1/${health_port}") >/dev/null 2>&1; then',
202426
+ " ready=1",
202427
+ " break",
202428
+ " fi",
202429
+ " sleep 0.25",
202430
+ "done",
202431
+ 'if [ "$ready" -ne 1 ]; then',
202432
+ ' echo "sprite-daemon websocket health port not ready" >&2',
202433
+ " exit 1",
202434
+ "fi",
202435
+ "echo ok"
202436
+ ].join("\n");
202437
+ const result = await execWithLog(
202438
+ client2,
202439
+ spriteName,
202440
+ script,
202441
+ "ensure-sprite-daemon"
202442
+ );
202443
+ if (result.exitCode !== 0) {
202444
+ throw new Error(
202445
+ result.stderr || result.stdout || "Sprite daemon health check failed."
202446
+ );
202447
+ }
202448
+ return;
202449
+ }
202079
202450
  const expectedCmd = DAEMON_WRAPPER;
202080
202451
  const expectedArgs = [];
202081
202452
  const existing = await client2.getService(spriteName, DAEMON_SERVICE_NAME);
@@ -202420,7 +202791,7 @@ chmod 755 ${WEZTERM_MUX_RUNNER_PATH}`,
202420
202791
  throw new Error(result.stderr || result.stdout || "Daemon install failed.");
202421
202792
  }
202422
202793
  reportPhase(4, "ensure daemon service");
202423
- await ensureSpriteDaemonService({ client: client2, spriteName });
202794
+ await ensureSpriteDaemonService({ client: client2, spriteName, computeProvider });
202424
202795
  reportPhase(5, "completed");
202425
202796
  };
202426
202797
  }
@@ -202684,7 +203055,7 @@ var init_registry2 = __esm({
202684
203055
  });
202685
203056
 
202686
203057
  // src/devbox/commands/mountSsh.ts
202687
- var import_node_child_process7, import_promises19, import_node_os12, import_node_path23, DEVBOX_SSH_DIR, MOUNT_KEY_PATH, MOUNT_PUBLIC_KEY_PATH, KNOWN_HOSTS_PATH, REMOTE_SSH_DIR, REMOTE_AUTH_KEYS, REMOTE_SSHD_CONFIG, SSHD_SERVICE_NAME, REMOTE_SSH_USER_PATTERN, shellEscape, runCommand4, ensureDevboxSshDir, ensureKnownHostsFile, ensureLocalMountKey, readLocalMountPublicKey, resolveRemoteSshUser, buildSshdConfig, ensureRemoteMountAccess, ensureSshdService;
203058
+ var import_node_child_process7, import_promises19, import_node_os12, import_node_path23, DEVBOX_SSH_DIR, MOUNT_KEY_PATH, MOUNT_PUBLIC_KEY_PATH, KNOWN_HOSTS_PATH, REMOTE_MOUNT_ROOT, REMOTE_SSH_DIR, REMOTE_AUTH_KEYS, REMOTE_SSHD_CONFIG, SSHD_SERVICE_NAME, REMOTE_SSH_USER_PATTERN, shellEscape, runCommand4, ensureDevboxSshDir, ensureKnownHostsFile, ensureLocalMountKey, readLocalMountPublicKey, ensureRemoteMountRoot, resolveRemoteSshUser, buildSshdConfig, ensureRemoteMountAccess, ensureSshdService, getRemoteMountRoot;
202688
203059
  var init_mountSsh = __esm({
202689
203060
  "src/devbox/commands/mountSsh.ts"() {
202690
203061
  "use strict";
@@ -202697,7 +203068,8 @@ var init_mountSsh = __esm({
202697
203068
  MOUNT_KEY_PATH = import_node_path23.default.join(DEVBOX_SSH_DIR, "mount_ed25519");
202698
203069
  MOUNT_PUBLIC_KEY_PATH = `${MOUNT_KEY_PATH}.pub`;
202699
203070
  KNOWN_HOSTS_PATH = import_node_path23.default.join(DEVBOX_SSH_DIR, "known_hosts");
202700
- REMOTE_SSH_DIR = "/home/sprite/.devbox/ssh";
203071
+ REMOTE_MOUNT_ROOT = "/home/sprite";
203072
+ REMOTE_SSH_DIR = `${REMOTE_MOUNT_ROOT}/.devbox/ssh`;
202701
203073
  REMOTE_AUTH_KEYS = `${REMOTE_SSH_DIR}/authorized_keys`;
202702
203074
  REMOTE_SSHD_CONFIG = `${REMOTE_SSH_DIR}/sshd_config`;
202703
203075
  SSHD_SERVICE_NAME = "devbox-sshd";
@@ -202757,6 +203129,25 @@ var init_mountSsh = __esm({
202757
203129
  }
202758
203130
  return trimmed;
202759
203131
  };
203132
+ ensureRemoteMountRoot = async (client2, spriteName) => {
203133
+ const result = await client2.exec(spriteName, [
203134
+ "/bin/bash",
203135
+ "-lc",
203136
+ `test -d ${shellEscape(REMOTE_MOUNT_ROOT)}`
203137
+ ]);
203138
+ if (result.exitCode === 0) {
203139
+ return;
203140
+ }
203141
+ const stderr = result.stderr.trim();
203142
+ const stdout = result.stdout.trim();
203143
+ const combined = [stderr, stdout].filter(Boolean).join("\n");
203144
+ const details = combined ? `
203145
+
203146
+ ${combined}` : "";
203147
+ throw new Error(
203148
+ `Remote mount root "${REMOTE_MOUNT_ROOT}" is missing or inaccessible. Run \`dvb init --resume\` for this devbox before mounting.${details}`
203149
+ );
203150
+ };
202760
203151
  resolveRemoteSshUser = async (client2, spriteName) => {
202761
203152
  const detectScript = [
202762
203153
  "set -euo pipefail",
@@ -202833,9 +203224,9 @@ ${combined}` : "";
202833
203224
  " sudo -n DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server",
202834
203225
  " fi",
202835
203226
  "fi",
202836
- "sudo -n mkdir -p /home/sprite/.devbox/ssh",
202837
- `sudo -n chown ${shellEscape(sshUser)}:${shellEscape(sshUser)} /home/sprite/.devbox/ssh`,
202838
- "sudo -n chmod 700 /home/sprite/.devbox/ssh",
203227
+ `sudo -n mkdir -p ${shellEscape(REMOTE_SSH_DIR)}`,
203228
+ `sudo -n chown ${shellEscape(sshUser)}:${shellEscape(sshUser)} ${shellEscape(REMOTE_SSH_DIR)}`,
203229
+ `sudo -n chmod 700 ${shellEscape(REMOTE_SSH_DIR)}`,
202839
203230
  ...sshUser === "root" ? [] : [
202840
203231
  `account_status=$(sudo -n passwd -S ${shellEscape(sshUser)} 2>/dev/null | awk '{print $2}' || true)`,
202841
203232
  'if [ "$account_status" = "L" ]; then',
@@ -202906,6 +203297,7 @@ ${combined}` : "";
202906
203297
  });
202907
203298
  }
202908
203299
  };
203300
+ getRemoteMountRoot = () => REMOTE_MOUNT_ROOT;
202909
203301
  }
202910
203302
  });
202911
203303
 
@@ -204626,11 +205018,11 @@ ${usageText}`;
204626
205018
  });
204627
205019
 
204628
205020
  // src/devbox/commands/init/codex/artifacts.ts
204629
- var import_node_crypto11, import_node_fs11, import_promises23, import_node_path27, import_node_os14, macCopyfileDisabledEnv, SETUP_ARTIFACT_PART_SIZE_BYTES, SETUP_ARTIFACT_PARTS_DIRNAME, SETUP_ARTIFACT_PARTS_DESCRIPTOR_FILENAME, isWithinRepo, normalizeExternalPath, expandHomePath, buildArtifactEntry, buildEntries, copyArtifact, sha256File, readSetupArtifactsPartsDescriptor, createSetupArtifacts;
205021
+ var import_node_crypto12, import_node_fs11, import_promises23, import_node_path27, import_node_os14, macCopyfileDisabledEnv, SETUP_ARTIFACT_PART_SIZE_BYTES, SETUP_ARTIFACT_PARTS_DIRNAME, SETUP_ARTIFACT_PARTS_DESCRIPTOR_FILENAME, isWithinRepo, normalizeExternalPath, expandHomePath, buildArtifactEntry, buildEntries, copyArtifact, sha256File, readSetupArtifactsPartsDescriptor, createSetupArtifacts;
204630
205022
  var init_artifacts = __esm({
204631
205023
  "src/devbox/commands/init/codex/artifacts.ts"() {
204632
205024
  "use strict";
204633
- import_node_crypto11 = require("node:crypto");
205025
+ import_node_crypto12 = require("node:crypto");
204634
205026
  import_node_fs11 = require("node:fs");
204635
205027
  import_promises23 = __toESM(require("node:fs/promises"), 1);
204636
205028
  import_node_path27 = __toESM(require("node:path"), 1);
@@ -204740,7 +205132,7 @@ var init_artifacts = __esm({
204740
205132
  await import_promises23.default.cp(entry.sourcePath, destPath, { recursive: false });
204741
205133
  };
204742
205134
  sha256File = async (filePath) => await new Promise((resolve2, reject) => {
204743
- const hash = (0, import_node_crypto11.createHash)("sha256");
205135
+ const hash = (0, import_node_crypto12.createHash)("sha256");
204744
205136
  const stream = (0, import_node_fs11.createReadStream)(filePath);
204745
205137
  stream.on("data", (chunk) => hash.update(chunk));
204746
205138
  stream.on("error", reject);
@@ -205143,12 +205535,12 @@ var init_progress = __esm({
205143
205535
  });
205144
205536
 
205145
205537
  // src/devbox/commands/init/codex/index.ts
205146
- var import_node_path28, import_node_crypto12, import_promises24, import_node_os15, resolveLocalCodexRoot, readLocalCodexAuthCache, syncLocalCodexAuthCacheToSprite, uploadSetupPlan, runRemoteCodexSetup;
205538
+ var import_node_path28, import_node_crypto13, import_promises24, import_node_os15, resolveLocalCodexRoot, readLocalCodexAuthCache, syncLocalCodexAuthCacheToSprite, uploadSetupPlan, runRemoteCodexSetup;
205147
205539
  var init_codex = __esm({
205148
205540
  "src/devbox/commands/init/codex/index.ts"() {
205149
205541
  "use strict";
205150
205542
  import_node_path28 = __toESM(require("node:path"), 1);
205151
- import_node_crypto12 = require("node:crypto");
205543
+ import_node_crypto13 = require("node:crypto");
205152
205544
  import_promises24 = __toESM(require("node:fs/promises"), 1);
205153
205545
  import_node_os15 = require("node:os");
205154
205546
  init_dist5();
@@ -205389,7 +205781,7 @@ var init_codex = __esm({
205389
205781
  }
205390
205782
  if (splitArtifacts && remoteArtifactsBundlePath) {
205391
205783
  status.stage("Assembling artifacts on remote");
205392
- const assembledTmpPath = `${remoteArtifactsBundlePath}.tmp-assemble-${(0, import_node_crypto12.randomUUID)()}`;
205784
+ const assembledTmpPath = `${remoteArtifactsBundlePath}.tmp-assemble-${(0, import_node_crypto13.randomUUID)()}`;
205393
205785
  const assembleScript = [
205394
205786
  "set -euo pipefail",
205395
205787
  `bundle=${shellQuote4(remoteArtifactsBundlePath)}`,
@@ -205591,7 +205983,7 @@ codex login`
205591
205983
  entrypoints
205592
205984
  });
205593
205985
  const codexLastMessagePath = "/home/sprite/.devbox/codex-setup-output.txt";
205594
- const proxyRoot = proxyOptions ? `/home/sprite/.devbox/tmp/codex-proxy-${(0, import_node_crypto12.randomUUID)()}` : null;
205986
+ const proxyRoot = proxyOptions ? `/home/sprite/.devbox/tmp/codex-proxy-${(0, import_node_crypto13.randomUUID)()}` : null;
205595
205987
  const proxyTokenPath = proxyRoot ? `${proxyRoot}/devbox-token` : null;
205596
205988
  const proxyCodexHome = proxyRoot ? `${proxyRoot}/codex-home` : null;
205597
205989
  const proxyConfigPath = proxyCodexHome ? `${proxyCodexHome}/config.toml` : null;
@@ -206620,7 +207012,6 @@ var init_setupPlanFlow = __esm({
206620
207012
  }
206621
207013
  outsideRepoPaths.sort();
206622
207014
  directoryPaths.sort();
206623
- const hasRisk = outsideRepoPaths.length > 0 || directoryPaths.length > 0;
206624
207015
  const warningLines = [];
206625
207016
  if (outsideRepoPaths.length > 0) {
206626
207017
  warningLines.push("Outside repo:");
@@ -206637,8 +207028,7 @@ var init_setupPlanFlow = __esm({
206637
207028
  }
206638
207029
  return {
206639
207030
  summary: lines.join("\n"),
206640
- warning: warningLines.length > 0 ? warningLines.join("\n") : null,
206641
- hasRisk
207031
+ warning: warningLines.length > 0 ? warningLines.join("\n") : null
206642
207032
  };
206643
207033
  };
206644
207034
  let draftSetup = setupPlan;
@@ -206653,7 +207043,7 @@ var init_setupPlanFlow = __esm({
206653
207043
  initialSelection: draftSetup?.services ?? null
206654
207044
  });
206655
207045
  const nextPlan = { ...nextSetup, services: nextServices };
206656
- const { summary, warning, hasRisk } = await buildApprovalSummary(nextPlan);
207046
+ const { summary, warning } = await buildApprovalSummary(nextPlan);
206657
207047
  kt2(summary, "Selected setup requirements");
206658
207048
  if (warning) {
206659
207049
  kt2(warning, "Special attention");
@@ -206674,21 +207064,6 @@ var init_setupPlanFlow = __esm({
206674
207064
  draftSetup = nextPlan;
206675
207065
  continue;
206676
207066
  }
206677
- if (hasRisk) {
206678
- const confirmed = await Mt2({
206679
- message: "You selected items outside the repo and/or directories. Continue?",
206680
- active: "Continue",
206681
- inactive: "Edit selections",
206682
- initialValue: true
206683
- });
206684
- if (Ct(confirmed)) {
206685
- throwInitCanceled2();
206686
- }
206687
- if (!confirmed) {
206688
- draftSetup = nextPlan;
206689
- continue;
206690
- }
206691
- }
206692
207067
  approvedPlan = nextPlan;
206693
207068
  break;
206694
207069
  }
@@ -207220,11 +207595,11 @@ var init_provisionFlow = __esm({
207220
207595
  });
207221
207596
 
207222
207597
  // src/devbox/commands/init/ssh.ts
207223
- var import_node_crypto13, import_node_child_process10, logger9, SSH_IDENTITY_FILE, SSH_ED25519_PUBLIC_KEY_PATTERN, stripGitSuffix2, buildSshUrl, buildSettingsUrl, parseScpLike, parseGitRemote, execRemote, extractEd25519PublicKey, readRemoteOrigin, setRemoteOrigin, ensureSshKey, ensureSshConfig, verifySshAuth, openBrowser4, runClipboardCommand, copyToClipboard;
207598
+ var import_node_crypto14, import_node_child_process10, logger9, SSH_IDENTITY_FILE, SSH_ED25519_PUBLIC_KEY_PATTERN, stripGitSuffix2, buildSshUrl, buildSettingsUrl, parseScpLike, parseGitRemote, execRemote, extractEd25519PublicKey, readRemoteOrigin, setRemoteOrigin, ensureSshKey, ensureSshConfig, verifySshAuth, openBrowser4, runClipboardCommand, copyToClipboard;
207224
207599
  var init_ssh = __esm({
207225
207600
  "src/devbox/commands/init/ssh.ts"() {
207226
207601
  "use strict";
207227
- import_node_crypto13 = require("node:crypto");
207602
+ import_node_crypto14 = require("node:crypto");
207228
207603
  import_node_child_process10 = require("node:child_process");
207229
207604
  init_src();
207230
207605
  init_remote();
@@ -207306,7 +207681,7 @@ var init_ssh = __esm({
207306
207681
  return null;
207307
207682
  };
207308
207683
  execRemote = async (client2, spriteAlias, script, stage) => {
207309
- const requestId = (0, import_node_crypto13.randomUUID)();
207684
+ const requestId = (0, import_node_crypto14.randomUUID)();
207310
207685
  logger9.info("sprites_request", {
207311
207686
  requestId,
207312
207687
  method: "exec",
@@ -207844,13 +208219,15 @@ var init_finalizeFlow = __esm({
207844
208219
  promptBeforeOpenBrowser = async ({
207845
208220
  url,
207846
208221
  title,
208222
+ promptMessage,
207847
208223
  consequence,
207848
208224
  throwInitCanceled: throwInitCanceled2
207849
208225
  }) => {
207850
208226
  if (!process.stdin.isTTY) return false;
207851
208227
  showCopyableUrl(url, title);
208228
+ const message = typeof promptMessage === "string" && promptMessage.trim().length > 0 ? promptMessage : `Open ${title} in your browser?`;
207852
208229
  const choice = await qt({
207853
- message: `Open ${title} in your browser?`,
208230
+ message,
207854
208231
  options: [
207855
208232
  { value: "open", label: "Open in browser" },
207856
208233
  { value: "skip", label: "Skip" }
@@ -208176,9 +208553,11 @@ var init_finalizeFlow = __esm({
208176
208553
  } else {
208177
208554
  R2.warn("Could not copy the SSH key automatically.");
208178
208555
  }
208556
+ const openBrowserPromptMessage = copied ? `Open ${remoteInfo.host} SSH key page in your browser? (SSH key copied to clipboard; paste it into the key box, then click "Add SSH key".)` : `Open ${remoteInfo.host} SSH key page in your browser?`;
208179
208557
  const shouldOpen = await promptBeforeOpenBrowser({
208180
208558
  url: remoteInfo.settingsUrl,
208181
208559
  title: `${remoteInfo.host} SSH key page`,
208560
+ promptMessage: openBrowserPromptMessage,
208182
208561
  consequence: [
208183
208562
  "Skipping browser open.",
208184
208563
  "You must add the SSH key before git pull/push will work via SSH."
@@ -209913,7 +210292,8 @@ var init_init = __esm({
209913
210292
  title: "Ensuring daemon service",
209914
210293
  fn: async () => await ensureSpriteDaemonService({
209915
210294
  client: client2,
209916
- spriteName: alias
210295
+ spriteName: alias,
210296
+ computeProvider
209917
210297
  })
209918
210298
  });
209919
210299
  await updateInitState({ steps: { daemonServiceEnsured: true } });
@@ -210485,7 +210865,7 @@ var init_logout = __esm({
210485
210865
  });
210486
210866
 
210487
210867
  // src/devbox/commands/mount.ts
210488
- var import_node_child_process11, import_promises29, import_node_os19, import_node_path35, parseMountArgs, resolveMountDir, commandExists, ensureLocalDependencies, resolveSpriteAlias, runCommand5, forwardSshPort, stopSshPort, unmount, runMount, runUnmount;
210868
+ var import_node_child_process11, import_promises29, import_node_os19, import_node_path35, parseMountArgs, resolveMountDir, commandExists, ensureLocalDependencies, resolveSpritesMountRuntimeClient, resolveModalMountRuntimeClient, resolveMountRuntimeClient, resolveSpriteAlias, runCommand5, forwardSshPort, stopSshPort, resolveMountProviderTarget, unmount, runMount, runUnmount;
210489
210869
  var init_mount = __esm({
210490
210870
  "src/devbox/commands/mount.ts"() {
210491
210871
  "use strict";
@@ -210499,7 +210879,10 @@ var init_mount = __esm({
210499
210879
  init_logger3();
210500
210880
  init_boxSelect();
210501
210881
  init_commandProvider();
210882
+ init_modalRuntime();
210502
210883
  init_mountSsh();
210884
+ init_modalCommandContext();
210885
+ init_modalLifecycle();
210503
210886
  parseMountArgs = (args) => {
210504
210887
  const parsed = {};
210505
210888
  for (const arg of args) {
@@ -210530,6 +210913,86 @@ var init_mount = __esm({
210530
210913
  throw new Error("Missing ssh client.");
210531
210914
  }
210532
210915
  };
210916
+ resolveSpritesMountRuntimeClient = async () => {
210917
+ const config4 = await loadConfig(
210918
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
210919
+ );
210920
+ const store = await createSecretStore(
210921
+ config4?.tokenStore,
210922
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
210923
+ );
210924
+ const apiBaseUrl = resolveSpritesApiUrl(config4);
210925
+ const { token } = await ensureSpritesToken(store, void 0, {
210926
+ apiBaseUrl
210927
+ });
210928
+ return createSpritesClient({ apiBaseUrl, token });
210929
+ };
210930
+ resolveModalMountRuntimeClient = async (options, dependencies = {}) => {
210931
+ const resolveModalContext = dependencies.resolveModalContext ?? resolveModalCommandContext;
210932
+ const findSandbox = dependencies.findSandbox ?? findModalSandbox;
210933
+ const createRuntimeClient = dependencies.createRuntimeClient ?? createModalInitRuntimeClient;
210934
+ const modalContext = await resolveModalContext({
210935
+ alias: options.alias,
210936
+ cwd: options.cwd
210937
+ });
210938
+ const sandbox = await findSandbox(
210939
+ {
210940
+ alias: options.alias,
210941
+ includeFinished: true
210942
+ },
210943
+ modalContext.operationOptions
210944
+ );
210945
+ let appName = sandbox?.appName ?? "";
210946
+ let sandboxId = sandbox?.sandboxId ?? "";
210947
+ if (!sandbox || sandbox.status !== "running") {
210948
+ try {
210949
+ const ensured = await modalContext.ensureActive("proxy");
210950
+ appName = ensured.appName;
210951
+ sandboxId = ensured.sandboxId;
210952
+ } catch (error2) {
210953
+ const reason = error2 instanceof Error ? error2.message : String(error2);
210954
+ if (!sandbox) {
210955
+ throw new Error(
210956
+ `No running modal sandbox found named "${options.targetBox}" and it could not be resumed for mount.
210957
+
210958
+ ${reason}`
210959
+ );
210960
+ }
210961
+ throw new Error(
210962
+ `Modal sandbox "${options.targetBox}" is ${sandbox.status} and could not be resumed for mount.
210963
+
210964
+ ${reason}`
210965
+ );
210966
+ }
210967
+ }
210968
+ return createRuntimeClient({
210969
+ alias: options.alias,
210970
+ appName,
210971
+ sandboxId,
210972
+ credentialMode: modalContext.operationOptions.credentialMode,
210973
+ credentials: modalContext.operationOptions.credentials,
210974
+ ...modalContext.operationOptions.cwd ? { cwd: modalContext.operationOptions.cwd } : {},
210975
+ ensureActive: async (intent) => {
210976
+ const ensured = await modalContext.ensureActive(intent);
210977
+ return {
210978
+ appName: ensured.appName,
210979
+ sandboxId: ensured.sandboxId
210980
+ };
210981
+ }
210982
+ });
210983
+ };
210984
+ resolveMountRuntimeClient = async (options, dependencies = {}) => {
210985
+ if (options.provider === "modal") {
210986
+ const resolveModalRuntimeClient = dependencies.resolveModalRuntimeClient ?? (async (modalOptions) => await resolveModalMountRuntimeClient(modalOptions));
210987
+ return await resolveModalRuntimeClient({
210988
+ alias: options.alias,
210989
+ targetBox: options.targetBox,
210990
+ cwd: options.cwd
210991
+ });
210992
+ }
210993
+ const resolveSpritesRuntimeClient = dependencies.resolveSpritesRuntimeClient ?? resolveSpritesMountRuntimeClient;
210994
+ return await resolveSpritesRuntimeClient();
210995
+ };
210533
210996
  resolveSpriteAlias = async (_socketPath, box) => box;
210534
210997
  runCommand5 = (command, args, options = {}) => new Promise((resolve2, reject) => {
210535
210998
  const child = (0, import_node_child_process11.spawn)(command, args, {
@@ -210568,28 +211031,8 @@ var init_mount = __esm({
210568
211031
  throw new Error(`dvbd error: ${response.status}`);
210569
211032
  }
210570
211033
  };
210571
- unmount = async (mountDir) => {
210572
- const command = process.platform === "darwin" ? "diskutil" : "umount";
210573
- const args = process.platform === "darwin" ? ["unmount", mountDir] : [mountDir];
210574
- const exitCode = await runCommand5(command, args);
210575
- if (exitCode !== 0) {
210576
- throw new Error(`Failed to unmount ${mountDir}`);
210577
- }
210578
- };
210579
- runMount = async (args) => {
210580
- const parsed = parseMountArgs(args);
210581
- let targetBox = parsed.box;
210582
- if (!targetBox) {
210583
- const selected = await selectDevbox(
210584
- "Use `dvb mount <box>` to target a specific box."
210585
- );
210586
- if (!selected) return;
210587
- targetBox = selected.box;
210588
- }
210589
- const socketInfo = resolveSocketInfo();
210590
- await ensureDaemonRunning(socketInfo.socketPath);
210591
- await requireDaemonFeatures(socketInfo.socketPath, ["ports.forward"]);
210592
- let spriteAlias = await resolveSpriteAlias(socketInfo.socketPath, targetBox);
211034
+ resolveMountProviderTarget = async (socketPath, targetBox) => {
211035
+ const spriteAlias = await resolveSpriteAlias(socketPath, targetBox);
210593
211036
  let providerLookupBoxes = null;
210594
211037
  try {
210595
211038
  providerLookupBoxes = await listDevboxes();
@@ -210599,14 +211042,14 @@ var init_mount = __esm({
210599
211042
  error: String(error2)
210600
211043
  });
210601
211044
  }
210602
- const providerTarget = await resolveCommandComputeProvider({
211045
+ return await resolveCommandComputeProvider({
210603
211046
  box: spriteAlias,
210604
211047
  boxes: providerLookupBoxes,
210605
211048
  homeDir: process.env.HOME ?? import_node_os19.default.homedir(),
210606
211049
  persistAssumedComputeProvider: async ({ alias, computeProvider }) => {
210607
211050
  try {
210608
211051
  const response = await requestJson3(
210609
- socketInfo.socketPath,
211052
+ socketPath,
210610
211053
  "POST",
210611
211054
  "/registry/upsert",
210612
211055
  DAEMON_TIMEOUT_MS.registry,
@@ -210632,26 +211075,49 @@ var init_mount = __esm({
210632
211075
  }
210633
211076
  }
210634
211077
  });
211078
+ };
211079
+ unmount = async (mountDir) => {
211080
+ const command = process.platform === "darwin" ? "diskutil" : "umount";
211081
+ const args = process.platform === "darwin" ? ["unmount", mountDir] : [mountDir];
211082
+ const exitCode = await runCommand5(command, args);
211083
+ if (exitCode !== 0) {
211084
+ throw new Error(`Failed to unmount ${mountDir}`);
211085
+ }
211086
+ };
211087
+ runMount = async (args) => {
211088
+ const parsed = parseMountArgs(args);
211089
+ let targetBox = parsed.box;
211090
+ if (!targetBox) {
211091
+ const selected = await selectDevbox(
211092
+ "Use `dvb mount <box>` to target a specific box."
211093
+ );
211094
+ if (!selected) return;
211095
+ targetBox = selected.box;
211096
+ }
211097
+ const socketInfo = resolveSocketInfo();
211098
+ await ensureDaemonRunning(socketInfo.socketPath);
211099
+ await requireDaemonFeatures(socketInfo.socketPath, ["ports.forward"]);
211100
+ const providerTarget = await resolveMountProviderTarget(
211101
+ socketInfo.socketPath,
211102
+ targetBox
211103
+ );
210635
211104
  assertCommandProviderCapability({
210636
211105
  provider: providerTarget.computeProvider,
210637
211106
  command: "mount",
210638
211107
  capability: "files.read"
210639
211108
  });
210640
- spriteAlias = providerTarget.alias;
211109
+ const spriteAlias = providerTarget.alias;
210641
211110
  ensureLocalDependencies();
210642
- const config4 = await loadConfig(
210643
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
210644
- );
210645
- const store = await createSecretStore(
210646
- config4?.tokenStore,
210647
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
210648
- );
210649
- const apiBaseUrl = resolveSpritesApiUrl(config4);
210650
- const { token } = await ensureSpritesToken(store, void 0, { apiBaseUrl });
210651
- const client2 = createSpritesClient({ apiBaseUrl, token });
211111
+ const client2 = await resolveMountRuntimeClient({
211112
+ provider: providerTarget.computeProvider,
211113
+ alias: spriteAlias,
211114
+ targetBox,
211115
+ cwd: process.cwd()
211116
+ });
210652
211117
  const { privateKeyPath } = await ensureLocalMountKey();
210653
211118
  const publicKey = await readLocalMountPublicKey();
210654
211119
  const knownHostsPath = await ensureKnownHostsFile();
211120
+ await ensureRemoteMountRoot(client2, spriteAlias);
210655
211121
  const remoteMountAccess = await ensureRemoteMountAccess(
210656
211122
  client2,
210657
211123
  spriteAlias,
@@ -210672,12 +211138,24 @@ var init_mount = __esm({
210672
211138
  "StrictHostKeyChecking=accept-new",
210673
211139
  "-p",
210674
211140
  String(localPort),
210675
- `${remoteMountAccess.sshUser}@localhost:/home/sprite`,
211141
+ `${remoteMountAccess.sshUser}@localhost:${getRemoteMountRoot()}`,
210676
211142
  mountDir
210677
211143
  ];
210678
- const exitCode = await runCommand5("sshfs", sshfsArgs);
210679
- if (exitCode !== 0) {
210680
- throw new Error("sshfs failed to mount.");
211144
+ try {
211145
+ const exitCode = await runCommand5("sshfs", sshfsArgs);
211146
+ if (exitCode !== 0) {
211147
+ throw new Error("sshfs failed to mount.");
211148
+ }
211149
+ } catch (error2) {
211150
+ try {
211151
+ await stopSshPort(socketInfo.socketPath, spriteAlias);
211152
+ } catch (stopError) {
211153
+ logger7.warn("mount_forward_cleanup_failed", {
211154
+ box: spriteAlias,
211155
+ error: String(stopError)
211156
+ });
211157
+ }
211158
+ throw error2;
210681
211159
  }
210682
211160
  console.log(`Mounted ${spriteAlias} at ${mountDir}`);
210683
211161
  };
@@ -210694,10 +211172,11 @@ var init_mount = __esm({
210694
211172
  const socketInfo = resolveSocketInfo();
210695
211173
  await ensureDaemonRunning(socketInfo.socketPath);
210696
211174
  await requireDaemonFeatures(socketInfo.socketPath, ["ports.forward"]);
210697
- const spriteAlias = await resolveSpriteAlias(
211175
+ const providerTarget = await resolveMountProviderTarget(
210698
211176
  socketInfo.socketPath,
210699
211177
  targetBox
210700
211178
  );
211179
+ const spriteAlias = providerTarget.alias;
210701
211180
  const mountDir = resolveMountDir(spriteAlias);
210702
211181
  await unmount(mountDir);
210703
211182
  await stopSshPort(socketInfo.socketPath, spriteAlias);
@@ -211303,16 +211782,20 @@ var init_uninstall = __esm({
211303
211782
  });
211304
211783
 
211305
211784
  // src/devbox/commands/sessions.ts
211306
- var renameUsage, killUsage, listUsage, parseSessionsArgs, parseSessionTarget, parseKillTarget, runRename, runKill, runSessions;
211785
+ var import_node_os21, renameUsage, killUsage, listUsage, parseSessionsArgs, parseSessionTarget, parseKillTarget, loadBoxesSnapshot, resolveSessionsClient, runRename, runKill, runSessions;
211307
211786
  var init_sessions2 = __esm({
211308
211787
  "src/devbox/commands/sessions.ts"() {
211309
211788
  "use strict";
211789
+ import_node_os21 = __toESM(require("node:os"), 1);
211310
211790
  init_src();
211311
211791
  init_daemonClient();
211312
211792
  init_auth();
211313
211793
  init_colors();
211314
211794
  init_listFormatting();
211315
211795
  init_boxSelect();
211796
+ init_commandProvider();
211797
+ init_providerClient();
211798
+ init_modalLifecycle();
211316
211799
  init_sessionUtils();
211317
211800
  init_completions();
211318
211801
  renameUsage = "Usage: dvb sessions rename <session> -n <name> or dvb sessions rename <box>/<session> -n <name>";
@@ -211412,24 +211895,89 @@ var init_sessions2 = __esm({
211412
211895
  }
211413
211896
  return { box, session };
211414
211897
  };
211415
- runRename = async (target2, name) => {
211416
- const trimmed = name.trim();
211417
- if (!trimmed) {
211418
- throw new Error("Session name cannot be empty.");
211419
- }
211420
- const parsedTarget = parseSessionTarget(target2);
211421
- let targetBox = parsedTarget.box;
211422
- if (!targetBox) {
211423
- const selected = await selectDevbox(
211424
- "To rename a session on a specific box, use `dvb sessions rename <box>/<session> -n <name>`."
211898
+ loadBoxesSnapshot = async (socketPath) => {
211899
+ try {
211900
+ const response = await requestJson3(
211901
+ socketPath,
211902
+ "GET",
211903
+ "/boxes",
211904
+ DAEMON_TIMEOUT_MS.registry
211425
211905
  );
211426
- if (!selected) return;
211427
- targetBox = selected.box;
211906
+ if (response.status !== 200) {
211907
+ return null;
211908
+ }
211909
+ return response.body.boxes;
211910
+ } catch {
211911
+ return null;
211428
211912
  }
211913
+ };
211914
+ resolveSessionsClient = async (targetBox) => {
211429
211915
  const socketInfo = resolveSocketInfo();
211430
211916
  await ensureDaemonRunning(socketInfo.socketPath);
211431
211917
  await requireDaemonFeatures(socketInfo.socketPath, ["registry"]);
211432
- const spriteAlias = targetBox;
211918
+ const boxes = await loadBoxesSnapshot(socketInfo.socketPath);
211919
+ const providerTarget = await resolveCommandComputeProvider({
211920
+ box: targetBox,
211921
+ ...boxes ? { boxes } : {},
211922
+ homeDir: process.env.HOME ?? import_node_os21.default.homedir()
211923
+ });
211924
+ const spriteAlias = providerTarget.alias;
211925
+ if (providerTarget.computeProvider === "modal") {
211926
+ const config5 = await loadConfig(
211927
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
211928
+ );
211929
+ const store2 = await createSecretStore(
211930
+ config5?.tokenStore,
211931
+ process.env.HOME ? { homeDir: process.env.HOME } : void 0
211932
+ );
211933
+ const modalCredentialContext = createProviderCredentialContext({
211934
+ mode: "auto",
211935
+ controlPlaneToken: await store2.getControlPlaneToken()
211936
+ });
211937
+ let modalOperationOptions = await resolveModalCommandOperationOptions({
211938
+ credentials: modalCredentialContext,
211939
+ cwd: process.cwd()
211940
+ });
211941
+ if (modalOperationOptions.credentialMode === "shared" && (!modalOperationOptions.credentials.modalTokenId || !modalOperationOptions.credentials.modalTokenSecret)) {
211942
+ const controlPlaneToken = await ensureControlPlaneToken(store2);
211943
+ if (controlPlaneToken) {
211944
+ modalOperationOptions = await resolveModalCommandOperationOptions({
211945
+ credentials: createProviderCredentialContext({
211946
+ mode: "auto",
211947
+ controlPlaneToken
211948
+ }),
211949
+ cwd: process.cwd()
211950
+ });
211951
+ }
211952
+ }
211953
+ const sandbox = await findModalSandbox(
211954
+ {
211955
+ alias: spriteAlias,
211956
+ includeFinished: true
211957
+ },
211958
+ modalOperationOptions
211959
+ );
211960
+ if (!sandbox) {
211961
+ throw new Error(
211962
+ `No modal sandbox found named "${targetBox}". Run "dvb init --compute modal" to create one, or "dvb list" to see existing devboxes.`
211963
+ );
211964
+ }
211965
+ if (sandbox.status !== "running") {
211966
+ throw new Error(
211967
+ `Modal sandbox "${targetBox}" is ${sandbox.status}. Run "dvb init --resume" to reprovision it.`
211968
+ );
211969
+ }
211970
+ return {
211971
+ spriteAlias,
211972
+ computeProvider: "modal",
211973
+ client: createModalConnectSpritesClient({
211974
+ alias: spriteAlias,
211975
+ appName: sandbox.appName,
211976
+ sandboxId: sandbox.sandboxId,
211977
+ operationOptions: modalOperationOptions
211978
+ })
211979
+ };
211980
+ }
211433
211981
  const config4 = await loadConfig(
211434
211982
  process.env.HOME ? { homeDir: process.env.HOME } : void 0
211435
211983
  );
@@ -211439,7 +211987,27 @@ var init_sessions2 = __esm({
211439
211987
  );
211440
211988
  const apiBaseUrl = resolveSpritesApiUrl(config4);
211441
211989
  const { token } = await ensureSpritesToken(store, void 0, { apiBaseUrl });
211442
- const client2 = createSpritesClient({ apiBaseUrl, token });
211990
+ return {
211991
+ spriteAlias,
211992
+ computeProvider: "sprites",
211993
+ client: createSpritesClient({ apiBaseUrl, token })
211994
+ };
211995
+ };
211996
+ runRename = async (target2, name) => {
211997
+ const trimmed = name.trim();
211998
+ if (!trimmed) {
211999
+ throw new Error("Session name cannot be empty.");
212000
+ }
212001
+ const parsedTarget = parseSessionTarget(target2);
212002
+ let targetBox = parsedTarget.box;
212003
+ if (!targetBox) {
212004
+ const selected = await selectDevbox(
212005
+ "To rename a session on a specific box, use `dvb sessions rename <box>/<session> -n <name>`."
212006
+ );
212007
+ if (!selected) return;
212008
+ targetBox = selected.box;
212009
+ }
212010
+ const { spriteAlias, client: client2 } = await resolveSessionsClient(targetBox);
211443
212011
  const sessions = await readSpriteSessions(client2, spriteAlias);
211444
212012
  const sessionId = sessions[parsedTarget.session];
211445
212013
  if (!sessionId) {
@@ -211472,20 +212040,7 @@ var init_sessions2 = __esm({
211472
212040
  if (!selected) return;
211473
212041
  targetBox = selected.box;
211474
212042
  }
211475
- const socketInfo = resolveSocketInfo();
211476
- await ensureDaemonRunning(socketInfo.socketPath);
211477
- await requireDaemonFeatures(socketInfo.socketPath, ["registry"]);
211478
- const spriteAlias = targetBox;
211479
- const config4 = await loadConfig(
211480
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
211481
- );
211482
- const store = await createSecretStore(
211483
- config4?.tokenStore,
211484
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
211485
- );
211486
- const apiBaseUrl = resolveSpritesApiUrl(config4);
211487
- const { token } = await ensureSpritesToken(store, void 0, { apiBaseUrl });
211488
- const client2 = createSpritesClient({ apiBaseUrl, token });
212043
+ const { spriteAlias, client: client2 } = await resolveSessionsClient(targetBox);
211489
212044
  const sessionRef = parsedTarget.session;
211490
212045
  const sessions = await readSpriteSessions(client2, spriteAlias);
211491
212046
  let sessionId = sessions[sessionRef];
@@ -211560,24 +212115,31 @@ var init_sessions2 = __esm({
211560
212115
  if (!selected) return;
211561
212116
  targetArg = selected.box;
211562
212117
  }
212118
+ const { spriteAlias, client: client2 } = await resolveSessionsClient(targetArg);
211563
212119
  const socketInfo = resolveSocketInfo();
211564
212120
  await ensureDaemonRunning(socketInfo.socketPath);
211565
- await requireDaemonFeatures(socketInfo.socketPath, ["registry", "ports"]);
211566
- const spriteAlias = targetArg;
211567
- const config4 = await loadConfig(
211568
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
211569
- );
211570
- const store = await createSecretStore(
211571
- config4?.tokenStore,
211572
- process.env.HOME ? { homeDir: process.env.HOME } : void 0
211573
- );
211574
- const apiBaseUrl = resolveSpritesApiUrl(config4);
211575
- const { token } = await ensureSpritesToken(store, void 0, { apiBaseUrl });
211576
- const client2 = createSpritesClient({ apiBaseUrl, token });
211577
- const [sessions, sessionMap, portsResponse] = await Promise.all([
212121
+ const readPortsSnapshot = async () => {
212122
+ try {
212123
+ await requireDaemonFeatures(socketInfo.socketPath, ["ports"]);
212124
+ const response = await requestJson3(socketInfo.socketPath, "GET", "/ports", DAEMON_TIMEOUT_MS.quick);
212125
+ if (response.status < 200 || response.status >= 300) {
212126
+ return {
212127
+ forwards: [],
212128
+ detected: []
212129
+ };
212130
+ }
212131
+ return response.body;
212132
+ } catch {
212133
+ return {
212134
+ forwards: [],
212135
+ detected: []
212136
+ };
212137
+ }
212138
+ };
212139
+ const [sessions, sessionMap, portsSnapshot] = await Promise.all([
211578
212140
  client2.listExecSessions(spriteAlias),
211579
212141
  readSpriteSessions(client2, spriteAlias),
211580
- requestJson3(socketInfo.socketPath, "GET", "/ports", DAEMON_TIMEOUT_MS.quick)
212142
+ readPortsSnapshot()
211581
212143
  ]);
211582
212144
  const idToName = /* @__PURE__ */ new Map();
211583
212145
  for (const [name, id] of Object.entries(sessionMap)) {
@@ -211598,10 +212160,10 @@ var init_sessions2 = __esm({
211598
212160
  return view;
211599
212161
  });
211600
212162
  const ports = {
211601
- forwards: portsResponse.body.forwards.filter(
212163
+ forwards: portsSnapshot.forwards.filter(
211602
212164
  (entry) => entry.box === spriteAlias
211603
212165
  ),
211604
- detected: portsResponse.body.detected.filter(
212166
+ detected: portsSnapshot.detected.filter(
211605
212167
  (entry) => entry.box === spriteAlias
211606
212168
  )
211607
212169
  };
@@ -213462,11 +214024,11 @@ var init_qr = __esm({
213462
214024
  });
213463
214025
 
213464
214026
  // src/devbox/commands/setup.ts
213465
- var import_node_crypto14, trim, normalizeOrgSlug, extractOrgFromSpriteToken, parseCodexAuthMode, parseSpriteAuthMode, resolveSpriteAuthMode, normalizeSiteUrl, resolveSiteUrl, MOBILE_DOWNLOAD_LINK, parseSetupArgs, splitQrLines, printMobileDownloadQr, printFirstSetupCompleteMessage, normalizeUrlForCompare, resolveCliName3, formatSpritesApiError, probeSpritesAccess, runSetup;
214027
+ var import_node_crypto15, trim, normalizeOrgSlug, extractOrgFromSpriteToken, parseCodexAuthMode, parseSpriteAuthMode, resolveSpriteAuthMode, normalizeSiteUrl, resolveSiteUrl, MOBILE_DOWNLOAD_LINK, parseSetupArgs, splitQrLines, printMobileDownloadQr, printFirstSetupCompleteMessage, normalizeUrlForCompare, resolveCliName3, formatSpritesApiError, probeSpritesAccess, runSetup;
213466
214028
  var init_setup = __esm({
213467
214029
  "src/devbox/commands/setup.ts"() {
213468
214030
  "use strict";
213469
- import_node_crypto14 = require("node:crypto");
214031
+ import_node_crypto15 = require("node:crypto");
213470
214032
  init_src();
213471
214033
  init_src();
213472
214034
  init_auth();
@@ -213663,7 +214225,7 @@ var init_setup = __esm({
213663
214225
  return lines.join("\n");
213664
214226
  };
213665
214227
  probeSpritesAccess = async (apiBaseUrl, token) => {
213666
- const requestId = (0, import_node_crypto14.randomUUID)();
214228
+ const requestId = (0, import_node_crypto15.randomUUID)();
213667
214229
  const url = new URL("/v1/sprites", apiBaseUrl);
213668
214230
  url.searchParams.set("max_results", "1");
213669
214231
  logger7.info("sprites_request", {
@@ -214260,14 +214822,14 @@ var init_whoami = __esm({
214260
214822
  });
214261
214823
 
214262
214824
  // src/devbox/commands/wezterm.ts
214263
- var import_node_crypto15, import_node_child_process12, import_promises32, import_node_os21, import_node_path38, import_promises33, logger10, WEZTERM_APP_PATH, WEZTERM_BIN_PATH, WEZTERM_BIN_DIR, WEZTERM_INSTALL_URL, WEZTERM_PATH_EXPORT, WEZTERM_HEALTH_POLL_INTERVAL_MS, WEZTERM_HEALTH_POLL_TIMEOUT_MS, WEZTERM_PROXY_BASE_ENV, WEZTERM_PROXY_LOG_NAME, WEZTERM_USAGE, parseWeztermArgs, resolveSpriteAlias3, initWeztermClient, waitForWeztermMuxHealthy, ensureWeztermMuxReady, runWeztermProxy, runCommand6, promptYesNo2, fileExists, hasWeztermOnPath, resolveShellProfilePath, ensureWeztermOnPath, ensureWeztermInstalled, expandPath, resolveDefaultConfigPath, escapeRegExp2, resolveCliName4, resolveDvbCommand, formatLuaArgs, resolveWeztermProxyEnv, buildProxyCommand, buildDomainBlock, canAppendToConfig, countReturns, applyReturnTableTransform, insertBlock, runWeztermSetup, startWeztermDomain, runWezterm;
214825
+ var import_node_crypto16, import_node_child_process12, import_promises32, import_node_os22, import_node_path38, import_promises33, logger10, WEZTERM_APP_PATH, WEZTERM_BIN_PATH, WEZTERM_BIN_DIR, WEZTERM_INSTALL_URL, WEZTERM_PATH_EXPORT, WEZTERM_HEALTH_POLL_INTERVAL_MS, WEZTERM_HEALTH_POLL_TIMEOUT_MS, WEZTERM_PROXY_BASE_ENV, WEZTERM_PROXY_LOG_NAME, WEZTERM_USAGE, parseWeztermArgs, resolveSpriteAlias3, initWeztermClient, waitForWeztermMuxHealthy, ensureWeztermMuxReady, runWeztermProxy, runCommand6, promptYesNo2, fileExists, hasWeztermOnPath, resolveShellProfilePath, ensureWeztermOnPath, ensureWeztermInstalled, expandPath, resolveDefaultConfigPath, escapeRegExp2, resolveCliName4, resolveDvbCommand, formatLuaArgs, resolveWeztermProxyEnv, buildProxyCommand, buildDomainBlock, canAppendToConfig, countReturns, applyReturnTableTransform, insertBlock, runWeztermSetup, startWeztermDomain, runWezterm;
214264
214826
  var init_wezterm = __esm({
214265
214827
  "src/devbox/commands/wezterm.ts"() {
214266
214828
  "use strict";
214267
- import_node_crypto15 = require("node:crypto");
214829
+ import_node_crypto16 = require("node:crypto");
214268
214830
  import_node_child_process12 = require("node:child_process");
214269
214831
  import_promises32 = __toESM(require("node:fs/promises"), 1);
214270
- import_node_os21 = __toESM(require("node:os"), 1);
214832
+ import_node_os22 = __toESM(require("node:os"), 1);
214271
214833
  import_node_path38 = __toESM(require("node:path"), 1);
214272
214834
  import_promises33 = __toESM(require("node:readline/promises"), 1);
214273
214835
  init_src();
@@ -214454,7 +215016,7 @@ var init_wezterm = __esm({
214454
215016
  runWeztermProxy = async (box, port, options) => {
214455
215017
  const writeProxyLog = async (message) => {
214456
215018
  if (process.env.DEVBOX_WEZTERM_PROXY !== "1") return;
214457
- const homeDir = import_node_os21.default.homedir();
215019
+ const homeDir = import_node_os22.default.homedir();
214458
215020
  if (!homeDir) return;
214459
215021
  try {
214460
215022
  const logDir = import_node_path38.default.join(resolveDevboxDir(homeDir), "wezterm");
@@ -214475,7 +215037,7 @@ var init_wezterm = __esm({
214475
215037
  await writeProxyLog(
214476
215038
  `proxy_ready box=${spriteAlias} setup=${skipSetup ? "skip" : "full"}`
214477
215039
  );
214478
- const requestId = (0, import_node_crypto15.randomUUID)();
215040
+ const requestId = (0, import_node_crypto16.randomUUID)();
214479
215041
  const proxyPath = `/v1/sprites/${spriteAlias}/proxy`;
214480
215042
  logger10.info("sprites_request", {
214481
215043
  requestId,
@@ -215374,7 +215936,7 @@ var init_cli = __esm({
215374
215936
 
215375
215937
  // src/bin/dvb.ts
215376
215938
  var import_node_fs14 = __toESM(require("node:fs"), 1);
215377
- var import_node_os22 = __toESM(require("node:os"), 1);
215939
+ var import_node_os23 = __toESM(require("node:os"), 1);
215378
215940
  var import_node_path40 = __toESM(require("node:path"), 1);
215379
215941
  init_src();
215380
215942
  var MIN_NODE_MAJOR = 24;
@@ -215456,7 +216018,7 @@ run().catch(async (error2) => {
215456
216018
  await flushDevboxTelemetry();
215457
216019
  const message = formatErrorMessage(error2);
215458
216020
  if (process.env.DEVBOX_WEZTERM_PROXY === "1") {
215459
- const homeDir = import_node_os22.default.homedir();
216021
+ const homeDir = import_node_os23.default.homedir();
215460
216022
  if (homeDir) {
215461
216023
  try {
215462
216024
  const logDir = import_node_path40.default.join(resolveDevboxDir(homeDir), "wezterm");
@@ -215556,4 +216118,4 @@ smol-toml/dist/index.js:
215556
216118
  */
215557
216119
  //# sourceMappingURL=dvb.cjs.map
215558
216120
 
215559
- //# debugId=5b27d1b2-cb5a-5370-b4ca-61330f7946e5
216121
+ //# debugId=4d4f5269-c2cd-5397-a6d4-993b4d24cfdc