@boxes-dev/dvb 0.2.43 → 0.2.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/dvb.cjs CHANGED
@@ -404,11 +404,11 @@ var init_repo = __esm({
404
404
  try {
405
405
  const url = new URL(trimmed);
406
406
  const host = url.hostname.toLowerCase();
407
- const path25 = stripGitSuffix(url.pathname);
408
- if (!host || !path25) {
407
+ const path26 = stripGitSuffix(url.pathname);
408
+ if (!host || !path26) {
409
409
  throw new Error(`Unrecognized git URL: ${input}`);
410
410
  }
411
- return `${host}/${path25}`;
411
+ return `${host}/${path26}`;
412
412
  } catch {
413
413
  }
414
414
  if (trimmed.includes(":")) {
@@ -436,11 +436,11 @@ var init_sprites = __esm({
436
436
  method;
437
437
  path;
438
438
  body;
439
- constructor(status, method, path25, body) {
440
- super(`Sprites API error ${status} ${method} ${path25}: ${body}`);
439
+ constructor(status, method, path26, body) {
440
+ super(`Sprites API error ${status} ${method} ${path26}: ${body}`);
441
441
  this.status = status;
442
442
  this.method = method;
443
- this.path = path25;
443
+ this.path = path26;
444
444
  this.body = body;
445
445
  }
446
446
  };
@@ -485,15 +485,15 @@ var init_sprites = __esm({
485
485
  }
486
486
  return { message: String(event) };
487
487
  };
488
- toWsUrl = (apiBaseUrl, path25) => {
488
+ toWsUrl = (apiBaseUrl, path26) => {
489
489
  const base = new URL(apiBaseUrl);
490
490
  const protocol = base.protocol === "https:" ? "wss:" : "ws:";
491
- return new URL(path25, `${protocol}//${base.host}`);
491
+ return new URL(path26, `${protocol}//${base.host}`);
492
492
  };
493
493
  shellQuote = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
494
- requestJson = async (apiBaseUrl, token, method, path25, body) => {
494
+ requestJson = async (apiBaseUrl, token, method, path26, body) => {
495
495
  const requestId = (0, import_node_crypto.randomUUID)();
496
- const url = new URL(path25, apiBaseUrl);
496
+ const url = new URL(path26, apiBaseUrl);
497
497
  const headers = {
498
498
  authorization: `Bearer ${token}`,
499
499
  "x-request-id": requestId
@@ -505,18 +505,18 @@ var init_sprites = __esm({
505
505
  if (body) {
506
506
  init.body = JSON.stringify(body);
507
507
  }
508
- logger.info("sprites_request", { requestId, method, path: path25 });
508
+ logger.info("sprites_request", { requestId, method, path: path26 });
509
509
  const response = await fetch(url, init);
510
510
  const text = await response.text();
511
511
  logger.info("sprites_response", {
512
512
  requestId,
513
513
  method,
514
- path: path25,
514
+ path: path26,
515
515
  status: response.status
516
516
  });
517
517
  if (!response.ok) {
518
518
  const snippet = text.trim().slice(0, 200);
519
- throw new SpritesApiError(response.status, method, path25, snippet);
519
+ throw new SpritesApiError(response.status, method, path26, snippet);
520
520
  }
521
521
  if (!text) return null;
522
522
  try {
@@ -536,8 +536,8 @@ var init_sprites = __esm({
536
536
  if (options?.prefix) {
537
537
  params.set("prefix", options.prefix);
538
538
  }
539
- const path25 = `/v1/sprites${params.size ? `?${params.toString()}` : ""}`;
540
- const payload = await requestJson(apiBaseUrl, token, "GET", path25);
539
+ const path26 = `/v1/sprites${params.size ? `?${params.toString()}` : ""}`;
540
+ const payload = await requestJson(apiBaseUrl, token, "GET", path26);
541
541
  const record = payload && typeof payload === "object" ? payload : null;
542
542
  const rawSprites = Array.isArray(record?.sprites) ? record?.sprites : Array.isArray(payload) ? payload : [];
543
543
  const sprites = rawSprites.filter(
@@ -563,9 +563,9 @@ var init_sprites = __esm({
563
563
  }
564
564
  return response;
565
565
  };
566
- requestNdjson = async (apiBaseUrl, token, method, path25, body) => {
566
+ requestNdjson = async (apiBaseUrl, token, method, path26, body) => {
567
567
  const requestId = (0, import_node_crypto.randomUUID)();
568
- const url = new URL(path25, apiBaseUrl);
568
+ const url = new URL(path26, apiBaseUrl);
569
569
  const headers = {
570
570
  authorization: `Bearer ${token}`,
571
571
  "x-request-id": requestId
@@ -577,18 +577,18 @@ var init_sprites = __esm({
577
577
  if (body) {
578
578
  init.body = JSON.stringify(body);
579
579
  }
580
- logger.info("sprites_request", { requestId, method, path: path25 });
580
+ logger.info("sprites_request", { requestId, method, path: path26 });
581
581
  const response = await fetch(url, init);
582
582
  logger.info("sprites_response", {
583
583
  requestId,
584
584
  method,
585
- path: path25,
585
+ path: path26,
586
586
  status: response.status
587
587
  });
588
588
  const text = await response.text();
589
589
  if (!response.ok) {
590
590
  const snippet = text.trim().slice(0, 200);
591
- throw new SpritesApiError(response.status, method, path25, snippet);
591
+ throw new SpritesApiError(response.status, method, path26, snippet);
592
592
  }
593
593
  const lines = text.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0);
594
594
  const events = [];
@@ -618,13 +618,13 @@ var init_sprites = __esm({
618
618
  };
619
619
  writeFile = async (apiBaseUrl, token, name, remotePath, data) => {
620
620
  const requestId = (0, import_node_crypto.randomUUID)();
621
- const path25 = `/v1/sprites/${name}/fs/write`;
622
- const url = new URL(path25, apiBaseUrl);
621
+ const path26 = `/v1/sprites/${name}/fs/write`;
622
+ const url = new URL(path26, apiBaseUrl);
623
623
  url.searchParams.set("path", remotePath);
624
624
  url.searchParams.set("mkdir", "true");
625
625
  logger.info("sprites_fs_write", {
626
626
  requestId,
627
- path: path25,
627
+ path: path26,
628
628
  name,
629
629
  remotePath,
630
630
  size: data.length
@@ -640,7 +640,7 @@ var init_sprites = __esm({
640
640
  });
641
641
  logger.info("sprites_fs_write_response", {
642
642
  requestId,
643
- path: path25,
643
+ path: path26,
644
644
  status: response.status
645
645
  });
646
646
  if (!response.ok) {
@@ -677,15 +677,15 @@ var init_sprites = __esm({
677
677
  };
678
678
  readFile = async (apiBaseUrl, token, name, options) => {
679
679
  const requestId = (0, import_node_crypto.randomUUID)();
680
- const path25 = `/v1/sprites/${name}/fs/read`;
681
- const url = new URL(path25, apiBaseUrl);
680
+ const path26 = `/v1/sprites/${name}/fs/read`;
681
+ const url = new URL(path26, apiBaseUrl);
682
682
  url.searchParams.set("path", options.path);
683
683
  if (options.workingDir) {
684
684
  url.searchParams.set("workingDir", options.workingDir);
685
685
  }
686
686
  logger.info("sprites_fs_read", {
687
687
  requestId,
688
- path: path25,
688
+ path: path26,
689
689
  name,
690
690
  remotePath: options.path,
691
691
  workingDir: options.workingDir
@@ -699,12 +699,12 @@ var init_sprites = __esm({
699
699
  });
700
700
  logger.info("sprites_fs_read_response", {
701
701
  requestId,
702
- path: path25,
702
+ path: path26,
703
703
  status: response.status
704
704
  });
705
705
  if (!response.ok) {
706
706
  const snippet = (await response.text()).trim().slice(0, 200);
707
- throw new SpritesApiError(response.status, "GET", path25, snippet);
707
+ throw new SpritesApiError(response.status, "GET", path26, snippet);
708
708
  }
709
709
  const buffer = await response.arrayBuffer();
710
710
  return new Uint8Array(buffer);
@@ -931,9 +931,9 @@ var init_sprites = __esm({
931
931
  await internalServicesRequest(apiBaseUrl, token, name, command);
932
932
  return [];
933
933
  };
934
- execCommand = async (apiBaseUrl, token, name, cmd, requestId) => {
935
- const path25 = `/v1/sprites/${name}/exec`;
936
- const url = toWsUrl(apiBaseUrl, path25);
934
+ execCommand = async (apiBaseUrl, token, name, cmd, requestId, options) => {
935
+ const path26 = `/v1/sprites/${name}/exec`;
936
+ const url = toWsUrl(apiBaseUrl, path26);
937
937
  cmd.forEach((part) => url.searchParams.append("cmd", part));
938
938
  url.searchParams.set("tty", "false");
939
939
  url.searchParams.set("stdin", "false");
@@ -942,11 +942,28 @@ var init_sprites = __esm({
942
942
  const stderr = [];
943
943
  let exitCode = null;
944
944
  let resolved = false;
945
+ const timeoutMs = options?.timeoutMs;
946
+ const handshakeTimeoutMs = options?.handshakeTimeoutMs ?? (typeof timeoutMs === "number" ? Math.min(timeoutMs, 6e4) : void 0);
947
+ const timeoutHandle = typeof timeoutMs === "number" && timeoutMs > 0 ? setTimeout(() => {
948
+ if (resolved) return;
949
+ resolved = true;
950
+ logger.warn("sprites_exec_timeout", {
951
+ requestId,
952
+ path: path26,
953
+ timeoutMs
954
+ });
955
+ try {
956
+ ws.terminate();
957
+ } catch {
958
+ }
959
+ reject(new Error(`Exec websocket timed out after ${timeoutMs}ms`));
960
+ }, timeoutMs) : null;
945
961
  const ws = new import_ws.default(url.toString(), {
946
962
  headers: {
947
963
  Authorization: `Bearer ${token}`,
948
964
  "x-request-id": requestId
949
- }
965
+ },
966
+ ...typeof handshakeTimeoutMs === "number" && handshakeTimeoutMs > 0 ? { handshakeTimeout: handshakeTimeoutMs } : {}
950
967
  });
951
968
  const readResponseSnippet = async (response, limit = 800) => new Promise((resolveBody) => {
952
969
  let body = "";
@@ -966,12 +983,14 @@ var init_sprites = __esm({
966
983
  const status = response.statusCode ?? 0;
967
984
  logger.warn("sprites_exec_unexpected_response", {
968
985
  requestId,
969
- path: path25,
986
+ path: path26,
970
987
  status,
971
988
  headers: response.headers,
972
989
  bodySnippet: snippet ? snippet.slice(0, 800) : void 0
973
990
  });
974
991
  if (!resolved) {
992
+ if (timeoutHandle) clearTimeout(timeoutHandle);
993
+ resolved = true;
975
994
  const suffix = snippet ? ` (${snippet.slice(0, 800)})` : "";
976
995
  reject(new Error(`Exec websocket error: Unexpected server response: ${status}${suffix}`));
977
996
  }
@@ -980,7 +999,8 @@ var init_sprites = __esm({
980
999
  const finish = (code2) => {
981
1000
  if (resolved) return;
982
1001
  resolved = true;
983
- logger.info("sprites_exec_response", { requestId, path: path25, status: code2 });
1002
+ if (timeoutHandle) clearTimeout(timeoutHandle);
1003
+ logger.info("sprites_exec_response", { requestId, path: path26, status: code2 });
984
1004
  resolve({
985
1005
  exitCode: code2,
986
1006
  stdout: Buffer.concat(stdout).toString("utf8"),
@@ -1030,13 +1050,15 @@ var init_sprites = __esm({
1030
1050
  const errorMessage = errorInfo.details && errorInfo.details !== errorInfo.message ? `${errorInfo.message} (${errorInfo.details})` : errorInfo.message;
1031
1051
  logger.warn("sprites_exec_error", {
1032
1052
  requestId,
1033
- path: path25,
1053
+ path: path26,
1034
1054
  errorMessage,
1035
1055
  errorName: errorInfo.name,
1036
1056
  errorCode: errorInfo.code,
1037
1057
  errorStack: errorInfo.stack
1038
1058
  });
1039
1059
  if (!resolved) {
1060
+ if (timeoutHandle) clearTimeout(timeoutHandle);
1061
+ resolved = true;
1040
1062
  reject(new Error(`Exec websocket error: ${errorMessage}`));
1041
1063
  }
1042
1064
  };
@@ -1091,7 +1113,7 @@ var init_sprites = __esm({
1091
1113
  await writeFile(apiBaseUrl, token, name, remotePath, data);
1092
1114
  },
1093
1115
  readFile: async (name, options) => readFile(apiBaseUrl, token, name, options),
1094
- exec: async (name, cmd) => {
1116
+ exec: async (name, cmd, options) => {
1095
1117
  const requestId = (0, import_node_crypto.randomUUID)();
1096
1118
  logger.info("sprites_exec", {
1097
1119
  requestId,
@@ -1099,7 +1121,7 @@ var init_sprites = __esm({
1099
1121
  cmd,
1100
1122
  path: `/v1/sprites/${name}/exec`
1101
1123
  });
1102
- return execCommand(apiBaseUrl, token, name, cmd, requestId);
1124
+ return execCommand(apiBaseUrl, token, name, cmd, requestId, options);
1103
1125
  },
1104
1126
  listExecSessions: async (name) => listExecSessions(apiBaseUrl, token, name),
1105
1127
  listServices: async (name) => USE_INTERNAL_SERVICE_API ? listServicesInternal(apiBaseUrl, token, name) : listServices(apiBaseUrl, token, name),
@@ -3335,12 +3357,12 @@ function createApi(pathParts = []) {
3335
3357
  `API path is expected to be of the form \`api.moduleName.functionName\`. Found: \`${found}\``
3336
3358
  );
3337
3359
  }
3338
- const path25 = pathParts.slice(0, -1).join("/");
3360
+ const path26 = pathParts.slice(0, -1).join("/");
3339
3361
  const exportName = pathParts[pathParts.length - 1];
3340
3362
  if (exportName === "default") {
3341
- return path25;
3363
+ return path26;
3342
3364
  } else {
3343
- return path25 + ":" + exportName;
3365
+ return path26 + ":" + exportName;
3344
3366
  }
3345
3367
  } else if (prop === Symbol.toStringTag) {
3346
3368
  return "FunctionReference";
@@ -4726,27 +4748,27 @@ var init_authentication_manager = __esm({
4726
4748
  );
4727
4749
  return;
4728
4750
  }
4729
- let delay = Math.min(
4751
+ let delay2 = Math.min(
4730
4752
  MAXIMUM_REFRESH_DELAY,
4731
4753
  (tokenValiditySeconds - this.refreshTokenLeewaySeconds) * 1e3
4732
4754
  );
4733
- if (delay <= 0) {
4755
+ if (delay2 <= 0) {
4734
4756
  this.logger.warn(
4735
4757
  `Refetching auth token immediately, configured leeway ${this.refreshTokenLeewaySeconds}s is larger than the token's lifetime ${tokenValiditySeconds}s`
4736
4758
  );
4737
- delay = 0;
4759
+ delay2 = 0;
4738
4760
  }
4739
4761
  const refetchTokenTimeoutId = setTimeout(() => {
4740
4762
  this._logVerbose("running scheduled token refetch");
4741
4763
  void this.refetchToken();
4742
- }, delay);
4764
+ }, delay2);
4743
4765
  this.setAuthState({
4744
4766
  state: "waitingForScheduledRefetch",
4745
4767
  refetchTokenTimeoutId,
4746
4768
  config: this.authState.config
4747
4769
  });
4748
4770
  this._logVerbose(
4749
- `scheduled preemptive auth token refetching in ${delay}ms`
4771
+ `scheduled preemptive auth token refetching in ${delay2}ms`
4750
4772
  );
4751
4773
  }
4752
4774
  // Protects against simultaneous calls to `setConfig`
@@ -6549,8 +6571,8 @@ var init_simple_client_node = __esm({
6549
6571
  });
6550
6572
  require_node_gyp_build = __commonJS2({
6551
6573
  "../common/temp/node_modules/.pnpm/node-gyp-build@4.8.4/node_modules/node-gyp-build/node-gyp-build.js"(exports2, module2) {
6552
- var fs25 = __require("fs");
6553
- var path25 = __require("path");
6574
+ var fs26 = __require("fs");
6575
+ var path26 = __require("path");
6554
6576
  var os11 = __require("os");
6555
6577
  var runtimeRequire = typeof __webpack_require__ === "function" ? __non_webpack_require__ : __require;
6556
6578
  var vars = process.config && process.config.variables || {};
@@ -6567,21 +6589,21 @@ var init_simple_client_node = __esm({
6567
6589
  return runtimeRequire(load2.resolve(dir));
6568
6590
  }
6569
6591
  load2.resolve = load2.path = function(dir) {
6570
- dir = path25.resolve(dir || ".");
6592
+ dir = path26.resolve(dir || ".");
6571
6593
  try {
6572
- var name = runtimeRequire(path25.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
6594
+ var name = runtimeRequire(path26.join(dir, "package.json")).name.toUpperCase().replace(/-/g, "_");
6573
6595
  if (process.env[name + "_PREBUILD"]) dir = process.env[name + "_PREBUILD"];
6574
6596
  } catch (err) {
6575
6597
  }
6576
6598
  if (!prebuildsOnly) {
6577
- var release = getFirst(path25.join(dir, "build/Release"), matchBuild);
6599
+ var release = getFirst(path26.join(dir, "build/Release"), matchBuild);
6578
6600
  if (release) return release;
6579
- var debug = getFirst(path25.join(dir, "build/Debug"), matchBuild);
6601
+ var debug = getFirst(path26.join(dir, "build/Debug"), matchBuild);
6580
6602
  if (debug) return debug;
6581
6603
  }
6582
6604
  var prebuild = resolve(dir);
6583
6605
  if (prebuild) return prebuild;
6584
- var nearby = resolve(path25.dirname(process.execPath));
6606
+ var nearby = resolve(path26.dirname(process.execPath));
6585
6607
  if (nearby) return nearby;
6586
6608
  var target = [
6587
6609
  "platform=" + platform,
@@ -6598,26 +6620,26 @@ var init_simple_client_node = __esm({
6598
6620
  ].filter(Boolean).join(" ");
6599
6621
  throw new Error("No native build was found for " + target + "\n loaded from: " + dir + "\n");
6600
6622
  function resolve(dir2) {
6601
- var tuples = readdirSync(path25.join(dir2, "prebuilds")).map(parseTuple);
6623
+ var tuples = readdirSync(path26.join(dir2, "prebuilds")).map(parseTuple);
6602
6624
  var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
6603
6625
  if (!tuple) return;
6604
- var prebuilds = path25.join(dir2, "prebuilds", tuple.name);
6626
+ var prebuilds = path26.join(dir2, "prebuilds", tuple.name);
6605
6627
  var parsed = readdirSync(prebuilds).map(parseTags);
6606
6628
  var candidates = parsed.filter(matchTags(runtime, abi));
6607
6629
  var winner = candidates.sort(compareTags(runtime))[0];
6608
- if (winner) return path25.join(prebuilds, winner.file);
6630
+ if (winner) return path26.join(prebuilds, winner.file);
6609
6631
  }
6610
6632
  };
6611
6633
  function readdirSync(dir) {
6612
6634
  try {
6613
- return fs25.readdirSync(dir);
6635
+ return fs26.readdirSync(dir);
6614
6636
  } catch (err) {
6615
6637
  return [];
6616
6638
  }
6617
6639
  }
6618
6640
  function getFirst(dir, filter) {
6619
6641
  var files = readdirSync(dir).filter(filter);
6620
- return files[0] && path25.join(dir, files[0]);
6642
+ return files[0] && path26.join(dir, files[0]);
6621
6643
  }
6622
6644
  function matchBuild(name) {
6623
6645
  return /\.node$/.test(name);
@@ -6704,7 +6726,7 @@ var init_simple_client_node = __esm({
6704
6726
  return typeof window !== "undefined" && window.process && window.process.type === "renderer";
6705
6727
  }
6706
6728
  function isAlpine(platform2) {
6707
- return platform2 === "linux" && fs25.existsSync("/etc/alpine-release");
6729
+ return platform2 === "linux" && fs26.existsSync("/etc/alpine-release");
6708
6730
  }
6709
6731
  load2.parseTags = parseTags;
6710
6732
  load2.matchTags = matchTags;
@@ -10686,7 +10708,7 @@ var init_server = __esm({
10686
10708
  });
10687
10709
 
10688
10710
  // ../daemon/src/spritesRegistry.ts
10689
- var import_node_crypto2, import_node_fs, import_promises4, registryGet, registryReplace, registryUpsert, registryUsage, registryRemove, logger4, TOKEN_REFRESH_BUFFER_MS, clientCache, migrationPromise, migrationCompleted, trimEnv, resolveConvexUrl, resolveControlPlaneUrl, requireConvexConfig, decodeJwtPayload, parseTokenExpiresAt, shouldRefreshToken, isUnauthorizedError, clearControlPlaneSession, handleUnauthorized, refreshSession, loadControlPlaneToken, getClient, spritePortsList, logRequest, logResponse, parseTimestamp, pickEarlier, pickLater, mergeBoxes, mergeProjects, mergeRegistry, getRegistryFromConvex, replaceRegistry, migrateLocalRegistry, backfillInitStatus, fetchRegistry, upsertRegistry, recordRegistryUsage, removeRegistryEntry, subscribeSpritePorts;
10711
+ var import_node_crypto2, import_node_fs, import_promises4, registryGet, registryReplace, registryUpsert, registryUsage, registryRemove, logger4, TOKEN_REFRESH_BUFFER_MS, clientCache, migrationPromise, migrationCompleted, trimEnv, normalizeConvexDeployment, stripDevPrefix, resolveFromDeployment, resolveFromUrl, resolveConvexUrl, resolveControlPlaneUrl, requireConvexConfig, decodeJwtPayload, parseTokenExpiresAt, shouldRefreshToken, isUnauthorizedError, clearControlPlaneSession, handleUnauthorized, refreshSession, loadControlPlaneToken, requireControlPlaneToken, getClient, spritePortsList, logRequest, logResponse, parseTimestamp, pickEarlier, pickLater, mergeBoxes, mergeProjects, mergeRegistry, getRegistryFromConvex, replaceRegistry, migrateLocalRegistry, backfillInitStatus, fetchRegistry, upsertRegistry, recordRegistryUsage, removeRegistryEntry, subscribeSpritePorts;
10690
10712
  var init_spritesRegistry = __esm({
10691
10713
  "../daemon/src/spritesRegistry.ts"() {
10692
10714
  "use strict";
@@ -10708,13 +10730,55 @@ var init_spritesRegistry = __esm({
10708
10730
  migrationPromise = null;
10709
10731
  migrationCompleted = false;
10710
10732
  trimEnv = (value) => value?.trim() ?? "";
10733
+ normalizeConvexDeployment = (value) => {
10734
+ const normalized = trimEnv(value).replace(/\r/g, "");
10735
+ if (!normalized) return "";
10736
+ if (normalized.includes(":")) {
10737
+ const [prefix, rest] = normalized.split(":", 2);
10738
+ return `${prefix}:${trimEnv(rest ?? "")}`;
10739
+ }
10740
+ return normalized;
10741
+ };
10742
+ stripDevPrefix = (value) => {
10743
+ if (value.startsWith("dev:")) {
10744
+ return trimEnv(value.slice(4));
10745
+ }
10746
+ return value;
10747
+ };
10748
+ resolveFromDeployment = (deploymentRaw, suffix) => {
10749
+ const deployment = stripDevPrefix(normalizeConvexDeployment(deploymentRaw));
10750
+ if (!deployment) return "";
10751
+ if (deployment.includes("://")) {
10752
+ return deployment;
10753
+ }
10754
+ if (deployment.includes(".")) {
10755
+ const host = suffix === "cloud" ? deployment.replace(".convex.site", ".convex.cloud") : deployment.replace(".convex.cloud", ".convex.site");
10756
+ return `https://${host}`;
10757
+ }
10758
+ return `https://${deployment}.convex.${suffix}`;
10759
+ };
10760
+ resolveFromUrl = (raw, suffix) => {
10761
+ const value = trimEnv(raw).replace(/\r/g, "");
10762
+ if (!value) return "";
10763
+ try {
10764
+ const url = new URL(value);
10765
+ const host = suffix === "cloud" ? url.host.replace(".convex.site", ".convex.cloud") : url.host.replace(".convex.cloud", ".convex.site");
10766
+ return `${url.protocol}//${host}`;
10767
+ } catch {
10768
+ return "";
10769
+ }
10770
+ };
10711
10771
  resolveConvexUrl = () => {
10712
10772
  const url = trimEnv(process.env.DEVBOX_CONVEX_URL) || trimEnv(process.env.VITE_CONVEX_URL);
10713
- return url.length > 0 ? url : null;
10773
+ if (url.length > 0) return url;
10774
+ const derived = resolveFromDeployment(process.env.CONVEX_DEPLOYMENT ?? "", "cloud") || resolveFromUrl(process.env.CONVEX_SITE_URL ?? "", "cloud");
10775
+ return derived ? derived : null;
10714
10776
  };
10715
10777
  resolveControlPlaneUrl = () => {
10716
10778
  const url = trimEnv(process.env.DEVBOX_CONTROL_PLANE_URL) || trimEnv(process.env.CONVEX_SITE_URL);
10717
- return url.length > 0 ? url : null;
10779
+ if (url.length > 0) return url;
10780
+ const derived = resolveFromDeployment(process.env.CONVEX_DEPLOYMENT ?? "", "site") || resolveFromUrl(process.env.VITE_CONVEX_URL ?? "", "site");
10781
+ return derived ? derived : null;
10718
10782
  };
10719
10783
  requireConvexConfig = () => {
10720
10784
  if (!resolveControlPlaneUrl()) {
@@ -10850,26 +10914,35 @@ var init_spritesRegistry = __esm({
10850
10914
  if (!token) {
10851
10915
  const refreshToken = await store.getControlPlaneRefreshToken();
10852
10916
  if (refreshToken) {
10853
- const refreshed = await refreshSession(refreshToken);
10854
- token = refreshed.token;
10855
- await store.setControlPlaneToken(token);
10856
- if (refreshed.refreshToken) {
10857
- await store.setControlPlaneRefreshToken(refreshed.refreshToken);
10858
- }
10859
- const nextExpiresAt = parseTokenExpiresAt(token);
10860
- if (nextExpiresAt) {
10861
- await store.setControlPlaneTokenExpiresAt(nextExpiresAt);
10862
- } else {
10863
- await store.clearControlPlaneTokenExpiresAt();
10917
+ try {
10918
+ const refreshed = await refreshSession(refreshToken);
10919
+ token = refreshed.token;
10920
+ await store.setControlPlaneToken(token);
10921
+ if (refreshed.refreshToken) {
10922
+ await store.setControlPlaneRefreshToken(refreshed.refreshToken);
10923
+ }
10924
+ const nextExpiresAt = parseTokenExpiresAt(token);
10925
+ if (nextExpiresAt) {
10926
+ await store.setControlPlaneTokenExpiresAt(nextExpiresAt);
10927
+ } else {
10928
+ await store.clearControlPlaneTokenExpiresAt();
10929
+ }
10930
+ } catch (error) {
10931
+ logger4.warn("control_plane_refresh_failed", { error: String(error) });
10864
10932
  }
10865
10933
  }
10866
10934
  }
10935
+ return token ?? null;
10936
+ };
10937
+ requireControlPlaneToken = async () => {
10938
+ const token = await loadControlPlaneToken();
10867
10939
  if (!token) {
10868
10940
  throw new Error("Control plane auth missing. Run `dvb setup` to sign in.");
10869
10941
  }
10870
10942
  return token;
10871
10943
  };
10872
10944
  getClient = async () => {
10945
+ await requireControlPlaneToken();
10873
10946
  const convexUrl = requireConvexConfig();
10874
10947
  if (clientCache && clientCache.url === convexUrl) {
10875
10948
  return clientCache.client;
@@ -11677,7 +11750,7 @@ __export(src_exports, {
11677
11750
  runDaemon: () => runDaemon,
11678
11751
  startDaemon: () => startDaemon
11679
11752
  });
11680
- var import_node_http, import_promises5, import_node_fs2, import_node_crypto4, import_node_net2, import_node_path5, logger6, startedAt, DAEMON_API_VERSION, DAEMON_FEATURES, allowShutdown, buildBoxSummaries, readBody, readRequestPath, writeJson, handleRequestError, isSocketAlive, ensureRuntimeDir, startDaemon, runDaemon;
11753
+ var import_node_http, import_promises5, import_node_fs2, import_node_crypto4, import_node_net2, import_node_path5, logger6, startedAt, DAEMON_API_VERSION, DAEMON_FEATURES, allowShutdown, buildBoxSummaries, readBody, readRequestPath, writeJson, handleRequestError, isSocketAlive, waitForSocketAlive, ensureRuntimeDir, startDaemon, runDaemon;
11681
11754
  var init_src2 = __esm({
11682
11755
  "../daemon/src/index.ts"() {
11683
11756
  import_node_http = require("node:http");
@@ -11790,6 +11863,15 @@ var init_src2 = __esm({
11790
11863
  socket.once("error", () => done(false));
11791
11864
  socket.setTimeout(250, () => done(false));
11792
11865
  });
11866
+ waitForSocketAlive = async (socketPath, timeoutMs) => {
11867
+ const deadline = Date.now() + timeoutMs;
11868
+ while (Date.now() < deadline) {
11869
+ if (!(0, import_node_fs2.existsSync)(socketPath)) return false;
11870
+ if (await isSocketAlive(socketPath)) return true;
11871
+ await new Promise((resolve) => setTimeout(resolve, 50));
11872
+ }
11873
+ return false;
11874
+ };
11793
11875
  ensureRuntimeDir = async (runtimeDir) => {
11794
11876
  await import_promises5.default.mkdir(runtimeDir, { recursive: true, mode: 448 });
11795
11877
  try {
@@ -11805,7 +11887,7 @@ var init_src2 = __esm({
11805
11887
  const { socketPath, runtimeDir } = socketInfo;
11806
11888
  await ensureRuntimeDir(runtimeDir);
11807
11889
  if ((0, import_node_fs2.existsSync)(socketPath)) {
11808
- const alive = await isSocketAlive(socketPath);
11890
+ const alive = await waitForSocketAlive(socketPath, 1e3);
11809
11891
  if (alive) {
11810
11892
  throw new Error(`dvbd already running at ${socketPath}`);
11811
11893
  }
@@ -11813,31 +11895,18 @@ var init_src2 = __esm({
11813
11895
  }
11814
11896
  const portManager = new PortManager();
11815
11897
  portManager.start();
11816
- void fetchRegistry().then((registry) => {
11817
- for (const canonical of Object.keys(registry.boxes)) {
11818
- portManager.noteBox(canonical);
11819
- }
11820
- for (const canonical of Object.values(registry.aliases)) {
11821
- portManager.noteBox(canonical);
11822
- }
11823
- for (const project of Object.values(registry.projects)) {
11824
- portManager.noteBox(project.canonical);
11825
- }
11826
- }).catch((error) => {
11827
- logger6.warn("ports_registry_load_failed", { error: String(error) });
11828
- });
11829
11898
  const server = (0, import_node_http.createServer)((req, res) => {
11830
11899
  const requestId = req.headers["x-request-id"] ?? (0, import_node_crypto4.randomUUID)();
11831
- const path25 = readRequestPath(req);
11900
+ const path26 = readRequestPath(req);
11832
11901
  res.on("finish", () => {
11833
11902
  logger6.info("daemon_request", {
11834
11903
  requestId,
11835
11904
  method: req.method,
11836
- path: path25,
11905
+ path: path26,
11837
11906
  status: res.statusCode
11838
11907
  });
11839
11908
  });
11840
- if (path25 === "/health") {
11909
+ if (path26 === "/health") {
11841
11910
  writeJson(res, 200, {
11842
11911
  ok: true,
11843
11912
  pid: process.pid,
@@ -11846,7 +11915,7 @@ var init_src2 = __esm({
11846
11915
  });
11847
11916
  return;
11848
11917
  }
11849
- if (path25 === "/version") {
11918
+ if (path26 === "/version") {
11850
11919
  writeJson(res, 200, {
11851
11920
  name: "dvbd",
11852
11921
  version: "0.0.0",
@@ -11855,7 +11924,7 @@ var init_src2 = __esm({
11855
11924
  });
11856
11925
  return;
11857
11926
  }
11858
- if (path25 === "/boxes") {
11927
+ if (path26 === "/boxes") {
11859
11928
  void buildBoxSummaries().then((boxes) => {
11860
11929
  writeJson(res, 200, { boxes });
11861
11930
  }).catch((error) => {
@@ -11863,7 +11932,7 @@ var init_src2 = __esm({
11863
11932
  });
11864
11933
  return;
11865
11934
  }
11866
- if (path25 === "/registry/project" && req.method === "GET") {
11935
+ if (path26 === "/registry/project" && req.method === "GET") {
11867
11936
  const url = new URL(req.url ?? "", "http://localhost");
11868
11937
  const fingerprint = url.searchParams.get("fingerprint") ?? "";
11869
11938
  void fetchRegistry().then((registry) => {
@@ -11874,7 +11943,7 @@ var init_src2 = __esm({
11874
11943
  });
11875
11944
  return;
11876
11945
  }
11877
- if (path25 === "/registry/alias" && req.method === "GET") {
11946
+ if (path26 === "/registry/alias" && req.method === "GET") {
11878
11947
  const url = new URL(req.url ?? "", "http://localhost");
11879
11948
  const alias = url.searchParams.get("alias") ?? "";
11880
11949
  void fetchRegistry().then((registry) => {
@@ -11885,7 +11954,7 @@ var init_src2 = __esm({
11885
11954
  });
11886
11955
  return;
11887
11956
  }
11888
- if (path25 === "/registry/upsert" && req.method === "POST") {
11957
+ if (path26 === "/registry/upsert" && req.method === "POST") {
11889
11958
  void readBody(req).then(async (payload) => {
11890
11959
  const project = payload?.project;
11891
11960
  const box = payload?.box;
@@ -11910,7 +11979,7 @@ var init_src2 = __esm({
11910
11979
  });
11911
11980
  return;
11912
11981
  }
11913
- if (path25 === "/registry/usage" && req.method === "POST") {
11982
+ if (path26 === "/registry/usage" && req.method === "POST") {
11914
11983
  void readBody(req).then(async (payload) => {
11915
11984
  const canonical = typeof payload?.canonical === "string" ? payload.canonical : "";
11916
11985
  if (!canonical) {
@@ -11925,7 +11994,7 @@ var init_src2 = __esm({
11925
11994
  });
11926
11995
  return;
11927
11996
  }
11928
- if (path25 === "/registry/remove" && req.method === "POST") {
11997
+ if (path26 === "/registry/remove" && req.method === "POST") {
11929
11998
  void readBody(req).then(async (payload) => {
11930
11999
  const canonical = typeof payload?.canonical === "string" ? payload.canonical : "";
11931
12000
  if (!canonical) {
@@ -11940,12 +12009,12 @@ var init_src2 = __esm({
11940
12009
  });
11941
12010
  return;
11942
12011
  }
11943
- if (path25 === "/ports" && req.method === "GET") {
12012
+ if (path26 === "/ports" && req.method === "GET") {
11944
12013
  const snapshot = portManager.listPorts();
11945
12014
  writeJson(res, 200, snapshot);
11946
12015
  return;
11947
12016
  }
11948
- if (path25 === "/ports/clear" && req.method === "POST") {
12017
+ if (path26 === "/ports/clear" && req.method === "POST") {
11949
12018
  void readBody(req).then((payload) => {
11950
12019
  const box = typeof payload?.box === "string" ? payload.box : void 0;
11951
12020
  if (!box) {
@@ -11959,7 +12028,7 @@ var init_src2 = __esm({
11959
12028
  });
11960
12029
  return;
11961
12030
  }
11962
- if (path25 === "/ports/reload" && req.method === "POST") {
12031
+ if (path26 === "/ports/reload" && req.method === "POST") {
11963
12032
  void readBody(req).then(async (payload) => {
11964
12033
  const box = typeof payload?.box === "string" ? payload.box : void 0;
11965
12034
  if (!box) {
@@ -11973,7 +12042,7 @@ var init_src2 = __esm({
11973
12042
  });
11974
12043
  return;
11975
12044
  }
11976
- if (path25 === "/ports/policy" && req.method === "POST") {
12045
+ if (path26 === "/ports/policy" && req.method === "POST") {
11977
12046
  void readBody(req).then((payload) => {
11978
12047
  const box = typeof payload?.box === "string" ? payload.box : void 0;
11979
12048
  const policy = payload?.policy === "auto" || payload?.policy === "disabled" ? payload.policy : null;
@@ -11990,7 +12059,7 @@ var init_src2 = __esm({
11990
12059
  });
11991
12060
  return;
11992
12061
  }
11993
- if (path25 === "/ports/forward" && req.method === "POST") {
12062
+ if (path26 === "/ports/forward" && req.method === "POST") {
11994
12063
  void readBody(req).then(async (payload) => {
11995
12064
  const box = typeof payload?.box === "string" ? payload.box : void 0;
11996
12065
  const port = typeof payload?.port === "number" ? payload.port : void 0;
@@ -12010,7 +12079,7 @@ var init_src2 = __esm({
12010
12079
  });
12011
12080
  return;
12012
12081
  }
12013
- if (path25 === "/ports/stop" && req.method === "POST") {
12082
+ if (path26 === "/ports/stop" && req.method === "POST") {
12014
12083
  void readBody(req).then((payload) => {
12015
12084
  const box = typeof payload?.box === "string" ? payload.box : void 0;
12016
12085
  const port = typeof payload?.port === "number" ? payload.port : void 0;
@@ -12025,7 +12094,7 @@ var init_src2 = __esm({
12025
12094
  });
12026
12095
  return;
12027
12096
  }
12028
- if (path25 === "/shutdown" && req.method === "POST" && allowShutdown()) {
12097
+ if (path26 === "/shutdown" && req.method === "POST" && allowShutdown()) {
12029
12098
  writeJson(res, 202, { ok: true });
12030
12099
  void close();
12031
12100
  return;
@@ -12098,7 +12167,7 @@ var init_logger2 = __esm({
12098
12167
  });
12099
12168
 
12100
12169
  // src/devbox/controlPlane.ts
12101
- var import_node_http2, import_node_crypto5, import_node_child_process, resolveControlPlaneUrl2, resolveConvexUrl2, openBrowser, requestJson2, startCallbackServer, getControlPlaneUrl, getConvexUrl, signInWithBrowser, spriteTokenGet, spriteTokenSet, spriteDaemonReleaseGet, spriteDaemonTokenIssue, spriteDaemonSessionSummariesList, spriteDaemonSessionsList, withConvexClient, fetchSpriteToken, storeSpriteToken, fetchSpriteDaemonRelease, issueSpriteDaemonToken, listSpriteDaemonSessionSummaries, listSpriteDaemonSessions, signOutControlPlane, refreshControlPlaneSession;
12170
+ var import_node_http2, import_node_crypto5, import_node_child_process, trim, normalizeConvexDeployment2, stripDevPrefix2, resolveFromDeployment2, resolveFromUrl2, resolveControlPlaneUrl2, resolveConvexUrl2, openBrowser, requestJson2, startCallbackServer, getControlPlaneUrl, getConvexUrl, signInWithBrowser, spriteTokenGet, spriteTokenSet, spriteDaemonReleaseGet, spriteDaemonTokenIssue, spriteDaemonSessionSummariesList, spriteDaemonSessionsList, withConvexClient, fetchSpriteToken, storeSpriteToken, fetchSpriteDaemonRelease, issueSpriteDaemonToken, listSpriteDaemonSessionSummaries, listSpriteDaemonSessions, signOutControlPlane, refreshControlPlaneSession;
12102
12171
  var init_controlPlane = __esm({
12103
12172
  "src/devbox/controlPlane.ts"() {
12104
12173
  "use strict";
@@ -12108,11 +12177,52 @@ var init_controlPlane = __esm({
12108
12177
  init_index_node();
12109
12178
  init_server();
12110
12179
  init_logger2();
12180
+ trim = (value) => value.trim().replace(/\r/g, "");
12181
+ normalizeConvexDeployment2 = (value) => {
12182
+ const normalized = trim(value);
12183
+ if (!normalized) return "";
12184
+ if (normalized.includes(":")) {
12185
+ const [prefix, rest] = normalized.split(":", 2);
12186
+ return `${prefix}:${trim(rest ?? "")}`;
12187
+ }
12188
+ return normalized;
12189
+ };
12190
+ stripDevPrefix2 = (value) => {
12191
+ if (value.startsWith("dev:")) {
12192
+ return trim(value.slice(4));
12193
+ }
12194
+ return value;
12195
+ };
12196
+ resolveFromDeployment2 = (deploymentRaw, suffix) => {
12197
+ const deployment = stripDevPrefix2(normalizeConvexDeployment2(deploymentRaw));
12198
+ if (!deployment) return "";
12199
+ if (deployment.includes("://")) {
12200
+ return deployment;
12201
+ }
12202
+ if (deployment.includes(".")) {
12203
+ const host = suffix === "cloud" ? deployment.replace(".convex.site", ".convex.cloud") : deployment.replace(".convex.cloud", ".convex.site");
12204
+ return `https://${host}`;
12205
+ }
12206
+ return `https://${deployment}.convex.${suffix}`;
12207
+ };
12208
+ resolveFromUrl2 = (raw, suffix) => {
12209
+ const value = trim(raw);
12210
+ if (!value) return "";
12211
+ try {
12212
+ const url = new URL(value);
12213
+ const host = suffix === "cloud" ? url.host.replace(".convex.site", ".convex.cloud") : url.host.replace(".convex.cloud", ".convex.site");
12214
+ return `${url.protocol}//${host}`;
12215
+ } catch {
12216
+ return "";
12217
+ }
12218
+ };
12111
12219
  resolveControlPlaneUrl2 = () => {
12112
12220
  const envOverride = process.env.DEVBOX_CONTROL_PLANE_URL ?? process.env.CONVEX_SITE_URL;
12113
12221
  if (envOverride && envOverride.trim().length > 0) {
12114
12222
  return envOverride.trim();
12115
12223
  }
12224
+ const derived = resolveFromDeployment2(process.env.CONVEX_DEPLOYMENT ?? "", "site") || resolveFromUrl2(process.env.VITE_CONVEX_URL ?? "", "site");
12225
+ if (derived) return derived;
12116
12226
  if (false) return null;
12117
12227
  const trimmed = "https://api.boxes.dev".trim();
12118
12228
  return trimmed.length > 0 ? trimmed : null;
@@ -12122,6 +12232,8 @@ var init_controlPlane = __esm({
12122
12232
  if (envOverride && envOverride.trim().length > 0) {
12123
12233
  return envOverride.trim();
12124
12234
  }
12235
+ const derived = resolveFromDeployment2(process.env.CONVEX_DEPLOYMENT ?? "", "cloud") || resolveFromUrl2(process.env.CONVEX_SITE_URL ?? "", "cloud");
12236
+ if (derived) return derived;
12125
12237
  if (false) return null;
12126
12238
  const trimmed = "https://convex.boxes.dev".trim();
12127
12239
  return trimmed.length > 0 ? trimmed : null;
@@ -12151,9 +12263,9 @@ var init_controlPlane = __esm({
12151
12263
  console.log(url);
12152
12264
  }
12153
12265
  };
12154
- requestJson2 = async (baseUrl, method, path25, body, token) => {
12266
+ requestJson2 = async (baseUrl, method, path26, body, token) => {
12155
12267
  const requestId = (0, import_node_crypto5.randomUUID)();
12156
- const url = new URL(path25, baseUrl);
12268
+ const url = new URL(path26, baseUrl);
12157
12269
  const headers = {
12158
12270
  "x-request-id": requestId
12159
12271
  };
@@ -12426,7 +12538,7 @@ var init_controlPlane = __esm({
12426
12538
  });
12427
12539
 
12428
12540
  // src/devbox/daemonClient.ts
12429
- var import_node_http3, import_node_path6, import_node_child_process2, import_node_crypto6, import_promises6, DAEMON_TIMEOUT_MS, DaemonConnectionError, isConnectionError, requestJson3, requireDaemonFeatures, resolveDaemonCommand, spawnDaemon, waitForHealth, listAlternateSocketPaths, pruneDuplicateDaemons, ensureDaemonRunning, waitForSocketGone, stopDaemon;
12541
+ var import_node_http3, import_node_path6, import_node_child_process2, import_node_crypto6, import_node_fs3, import_promises6, DAEMON_TIMEOUT_MS, DaemonConnectionError, isConnectionError, requestJson3, requireDaemonFeatures, resolveDaemonCommand, spawnDaemon, waitForHealth, listAlternateSocketPaths, pruneDuplicateDaemons, ensureDaemonRunning, waitForSocketGone, stopDaemon;
12430
12542
  var init_daemonClient = __esm({
12431
12543
  "src/devbox/daemonClient.ts"() {
12432
12544
  "use strict";
@@ -12434,6 +12546,7 @@ var init_daemonClient = __esm({
12434
12546
  import_node_path6 = __toESM(require("node:path"), 1);
12435
12547
  import_node_child_process2 = require("node:child_process");
12436
12548
  import_node_crypto6 = require("node:crypto");
12549
+ import_node_fs3 = __toESM(require("node:fs"), 1);
12437
12550
  import_promises6 = require("node:fs/promises");
12438
12551
  init_src();
12439
12552
  init_controlPlane();
@@ -12584,11 +12697,20 @@ var init_daemonClient = __esm({
12584
12697
  const command = resolveDaemonCommand();
12585
12698
  const controlPlaneUrl = getControlPlaneUrl();
12586
12699
  const convexUrl = getConvexUrl();
12700
+ const runtimeDir = import_node_path6.default.dirname(socketPath);
12701
+ const logPath = import_node_path6.default.join(runtimeDir, "dvbd.log");
12702
+ let logFd = null;
12703
+ try {
12704
+ logFd = import_node_fs3.default.openSync(logPath, "a");
12705
+ } catch {
12706
+ logFd = null;
12707
+ }
12587
12708
  logger7.info("daemon_spawn", {
12588
12709
  socketPath,
12589
12710
  command: command.command,
12590
12711
  args: command.args,
12591
- source: command.source
12712
+ source: command.source,
12713
+ ...logFd !== null ? { logPath } : {}
12592
12714
  });
12593
12715
  const child = (0, import_node_child_process2.spawn)(command.command, command.args, {
12594
12716
  env: {
@@ -12597,9 +12719,15 @@ var init_daemonClient = __esm({
12597
12719
  ...controlPlaneUrl ? { DEVBOX_CONTROL_PLANE_URL: controlPlaneUrl } : {},
12598
12720
  ...convexUrl ? { DEVBOX_CONVEX_URL: convexUrl } : {}
12599
12721
  },
12600
- stdio: "ignore",
12722
+ stdio: logFd !== null ? ["ignore", logFd, logFd] : "ignore",
12601
12723
  detached: true
12602
12724
  });
12725
+ if (logFd !== null) {
12726
+ try {
12727
+ import_node_fs3.default.closeSync(logFd);
12728
+ } catch {
12729
+ }
12730
+ }
12603
12731
  child.unref();
12604
12732
  };
12605
12733
  waitForHealth = async (socketPath, timeoutMs) => {
@@ -12879,11 +13007,11 @@ ${tokenInstructions()}`
12879
13007
  );
12880
13008
  }
12881
13009
  let controlPlaneToken = await store.getControlPlaneToken();
12882
- const requireControlPlaneToken = options?.requireControlPlaneToken !== false;
12883
- if (!controlPlaneToken && requireControlPlaneToken) {
13010
+ const requireControlPlaneToken2 = options?.requireControlPlaneToken !== false;
13011
+ if (!controlPlaneToken && requireControlPlaneToken2) {
12884
13012
  controlPlaneToken = await ensureControlPlaneToken(store, stage);
12885
13013
  }
12886
- if (controlPlaneToken && requireControlPlaneToken) {
13014
+ if (controlPlaneToken && requireControlPlaneToken2) {
12887
13015
  const expiresAt = await store.getControlPlaneTokenExpiresAt();
12888
13016
  if (shouldRefreshToken2(expiresAt)) {
12889
13017
  try {
@@ -19635,8 +19763,8 @@ var init_connect = __esm({
19635
19763
  pendingPortLogs.set(event.port, token2);
19636
19764
  const delays = [30, 60, 120, 200];
19637
19765
  void (async () => {
19638
- for (const delay of delays) {
19639
- await new Promise((resolve) => setTimeout(resolve, delay));
19766
+ for (const delay2 of delays) {
19767
+ await new Promise((resolve) => setTimeout(resolve, delay2));
19640
19768
  if (pendingPortLogs.get(event.port) !== token2) {
19641
19769
  return;
19642
19770
  }
@@ -22164,16 +22292,25 @@ var init_registry2 = __esm({
22164
22292
  });
22165
22293
 
22166
22294
  // src/devbox/commands/init/scripts.ts
22167
- var import_promises19, import_node_path14, resolveScriptsDir, loadInitScript;
22295
+ var import_node_fs4, import_promises19, import_node_path14, resolveScriptsDir, loadInitScript;
22168
22296
  var init_scripts = __esm({
22169
22297
  "src/devbox/commands/init/scripts.ts"() {
22170
22298
  "use strict";
22299
+ import_node_fs4 = __toESM(require("node:fs"), 1);
22171
22300
  import_promises19 = __toESM(require("node:fs/promises"), 1);
22172
22301
  import_node_path14 = __toESM(require("node:path"), 1);
22173
22302
  resolveScriptsDir = () => {
22174
- const binPath = process.argv[1];
22175
- if (binPath) {
22176
- return import_node_path14.default.resolve(import_node_path14.default.dirname(binPath), "..", "scripts");
22303
+ const argv1 = typeof process.argv[1] === "string" ? process.argv[1] : "";
22304
+ if (argv1) {
22305
+ try {
22306
+ const real = import_node_fs4.default.realpathSync(argv1);
22307
+ return import_node_path14.default.resolve(import_node_path14.default.dirname(real), "..", "scripts");
22308
+ } catch {
22309
+ }
22310
+ try {
22311
+ return import_node_path14.default.resolve(import_node_path14.default.dirname(argv1), "..", "scripts");
22312
+ } catch {
22313
+ }
22177
22314
  }
22178
22315
  return import_node_path14.default.resolve(process.cwd(), "scripts");
22179
22316
  };
@@ -22202,7 +22339,7 @@ var init_weztermMux = __esm({
22202
22339
  });
22203
22340
 
22204
22341
  // src/devbox/commands/init/remote.ts
22205
- 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, logger8, truncateTail, shellQuote3, expandHome2, execWithLog, writeRemoteFile, bootstrapDevbox, buildWeztermMuxConfig, buildWeztermMuxRunner, patchBashrc, writeRemoteCodexConfig, stageRemoteSetupArtifacts, resolveDaemonUrl, fetchDaemonBinary, buildDaemonConfig, isSameArgs, ensureSpriteDaemonService, installWeztermMux, ensureWeztermMuxService, hasWeztermMuxBinary, isWeztermMuxHealthy, installSpriteDaemon;
22342
+ 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_RETRY_DELAY_MS, logger8, truncateTail, shellQuote3, expandHome2, execWithLog, isExecTimeoutError, delay, writeRemoteFile, bootstrapDevbox, buildWeztermMuxConfig, buildWeztermMuxRunner, patchBashrc, writeRemoteCodexConfig, stageRemoteSetupArtifacts, resolveDaemonUrl, fetchDaemonBinary, buildDaemonConfig, isSameArgs, ensureSpriteDaemonService, installWeztermMux, ensureWeztermMuxService, hasWeztermMuxBinary, isWeztermMuxHealthy, installSpriteDaemon;
22206
22343
  var init_remote = __esm({
22207
22344
  "src/devbox/commands/init/remote.ts"() {
22208
22345
  "use strict";
@@ -22220,6 +22357,8 @@ var init_remote = __esm({
22220
22357
  DAEMON_CONFIG_FILE = `${DAEMON_DIR}/config.json`;
22221
22358
  DEFAULT_DAEMON_BASE_URL = process.env.SPRITE_DAEMON_BASE_URL?.trim() || "https://deploy-dev.boxes.dev";
22222
22359
  DEFAULT_HEARTBEAT_MS = 3e4;
22360
+ BOOTSTRAP_EXEC_TIMEOUT_MS = 9e4;
22361
+ BOOTSTRAP_EXEC_RETRY_DELAY_MS = 1e4;
22223
22362
  logger8 = createLogger("devbox-init");
22224
22363
  truncateTail = (value, maxChars) => {
22225
22364
  if (value.length <= maxChars) return value;
@@ -22233,7 +22372,7 @@ var init_remote = __esm({
22233
22372
  }
22234
22373
  return value;
22235
22374
  };
22236
- execWithLog = async (client, canonical, script, stage) => {
22375
+ execWithLog = async (client, canonical, script, stage, options) => {
22237
22376
  const requestId = (0, import_node_crypto10.randomUUID)();
22238
22377
  const startedAt2 = Date.now();
22239
22378
  logger8.info("sprites_request", {
@@ -22243,7 +22382,11 @@ var init_remote = __esm({
22243
22382
  box: canonical,
22244
22383
  stage
22245
22384
  });
22246
- const result = await client.exec(canonical, ["/bin/bash", "-lc", script]);
22385
+ const result = await client.exec(
22386
+ canonical,
22387
+ ["/bin/bash", "-lc", script],
22388
+ options
22389
+ );
22247
22390
  const durationMs = Date.now() - startedAt2;
22248
22391
  logger8.info("sprites_response", {
22249
22392
  requestId,
@@ -22263,21 +22406,23 @@ var init_remote = __esm({
22263
22406
  });
22264
22407
  return result;
22265
22408
  };
22266
- writeRemoteFile = async (client, canonical, path25, content, stage) => {
22409
+ isExecTimeoutError = (error) => error instanceof Error && typeof error.message === "string" && error.message.startsWith("Exec websocket timed out after ");
22410
+ delay = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
22411
+ writeRemoteFile = async (client, canonical, path26, content, stage) => {
22267
22412
  const requestId = (0, import_node_crypto10.randomUUID)();
22268
22413
  logger8.info("sprites_request", {
22269
22414
  requestId,
22270
22415
  method: "writeFile",
22271
- path: path25,
22416
+ path: path26,
22272
22417
  box: canonical,
22273
22418
  stage
22274
22419
  });
22275
22420
  const buffer = typeof content === "string" ? Buffer.from(content, "utf8") : content;
22276
- await client.writeFile(canonical, path25, buffer);
22421
+ await client.writeFile(canonical, path26, buffer);
22277
22422
  logger8.info("sprites_response", {
22278
22423
  requestId,
22279
22424
  method: "writeFile",
22280
- path: path25,
22425
+ path: path26,
22281
22426
  status: "ok",
22282
22427
  box: canonical,
22283
22428
  stage
@@ -22294,12 +22439,28 @@ var init_remote = __esm({
22294
22439
  " sudo -n chown -R sprite:sprite /home/sprite/.devbox || true",
22295
22440
  "fi"
22296
22441
  ].join("\n");
22297
- const permsResult = await execWithLog(
22442
+ let permsResult = await execWithLog(
22298
22443
  client,
22299
22444
  canonical,
22300
22445
  permissionsScript,
22301
- "bootstrap-permissions"
22302
- );
22446
+ "bootstrap-permissions",
22447
+ { timeoutMs: BOOTSTRAP_EXEC_TIMEOUT_MS }
22448
+ ).catch(async (error) => {
22449
+ if (!isExecTimeoutError(error)) throw error;
22450
+ logger8.warn("sprites_exec_retry_after_timeout", {
22451
+ stage: "bootstrap-permissions",
22452
+ timeoutMs: BOOTSTRAP_EXEC_TIMEOUT_MS,
22453
+ delayMs: BOOTSTRAP_EXEC_RETRY_DELAY_MS
22454
+ });
22455
+ await delay(BOOTSTRAP_EXEC_RETRY_DELAY_MS);
22456
+ return await execWithLog(
22457
+ client,
22458
+ canonical,
22459
+ permissionsScript,
22460
+ "bootstrap-permissions",
22461
+ { timeoutMs: BOOTSTRAP_EXEC_TIMEOUT_MS }
22462
+ );
22463
+ });
22303
22464
  if (permsResult.exitCode !== 0) {
22304
22465
  const details = permsResult.stderr || permsResult.stdout || "";
22305
22466
  throw new Error(
@@ -22319,7 +22480,8 @@ var init_remote = __esm({
22319
22480
  client,
22320
22481
  canonical,
22321
22482
  ipv4PreferenceScript,
22322
- "bootstrap-ipv4-preference"
22483
+ "bootstrap-ipv4-preference",
22484
+ { timeoutMs: BOOTSTRAP_EXEC_TIMEOUT_MS }
22323
22485
  );
22324
22486
  if (ipv4Result.exitCode !== 0) {
22325
22487
  const details = ipv4Result.stderr || ipv4Result.stdout || "";
@@ -22964,30 +23126,34 @@ chmod 755 ${WEZTERM_MUX_RUNNER_PATH}`,
22964
23126
  DAEMON_CONFIG_FILE,
22965
23127
  Buffer.from(buildDaemonConfig(convexUrl, heartbeatToken))
22966
23128
  );
22967
- const result = await client.exec(spriteName, [
22968
- "/bin/bash",
22969
- "--noprofile",
22970
- "--norc",
22971
- "-e",
22972
- "-u",
22973
- "-o",
22974
- "pipefail",
22975
- "-c",
23129
+ const result = await client.exec(
23130
+ spriteName,
22976
23131
  [
22977
- `mkdir -p ${DAEMON_DIR}`,
22978
- `rm -rf ${DAEMON_BUNDLE_DIR}`,
22979
- `mkdir -p ${DAEMON_BUNDLE_DIR}`,
22980
- `tar -xzf ${DAEMON_TARBALL} -C ${DAEMON_BUNDLE_DIR}`,
22981
- `chmod 755 ${DAEMON_ENTRY} || true`,
22982
- `chmod 755 ${DAEMON_BUNDLE_DIR}/bin/* || true`,
23132
+ "/bin/bash",
23133
+ "--noprofile",
23134
+ "--norc",
23135
+ "-e",
23136
+ "-u",
23137
+ "-o",
23138
+ "pipefail",
23139
+ "-c",
22983
23140
  [
22984
- `${DAEMON_ENTRY} daemonctl install --json --timeout-ms 20000`,
22985
- `--tarball ${DAEMON_TARBALL}`,
22986
- `--release-sha ${release.sha256}`,
22987
- `--config-path ${DAEMON_CONFIG_FILE}`
22988
- ].join(" ")
22989
- ].join("\n")
22990
- ]);
23141
+ `mkdir -p ${DAEMON_DIR}`,
23142
+ `rm -rf ${DAEMON_BUNDLE_DIR}`,
23143
+ `mkdir -p ${DAEMON_BUNDLE_DIR}`,
23144
+ `tar -xzf ${DAEMON_TARBALL} -C ${DAEMON_BUNDLE_DIR}`,
23145
+ `chmod 755 ${DAEMON_ENTRY} || true`,
23146
+ `chmod 755 ${DAEMON_BUNDLE_DIR}/bin/* || true`,
23147
+ [
23148
+ `${DAEMON_ENTRY} daemonctl install --json --timeout-ms 20000`,
23149
+ `--tarball ${DAEMON_TARBALL}`,
23150
+ `--release-sha ${release.sha256}`,
23151
+ `--config-path ${DAEMON_CONFIG_FILE}`
23152
+ ].join(" ")
23153
+ ].join("\n")
23154
+ ],
23155
+ { timeoutMs: 12e4 }
23156
+ );
22991
23157
  if (result.exitCode !== 0) {
22992
23158
  throw new Error(result.stderr || result.stdout || "Daemon install failed.");
22993
23159
  }
@@ -23293,7 +23459,7 @@ var init_ssh = __esm({
23293
23459
  }
23294
23460
  return trimmed.replace(/^\/+/, "");
23295
23461
  };
23296
- buildSshUrl = (host, path25) => `git@${host}:${stripGitSuffix2(path25)}.git`;
23462
+ buildSshUrl = (host, path26) => `git@${host}:${stripGitSuffix2(path26)}.git`;
23297
23463
  buildSettingsUrl = (host) => {
23298
23464
  const lower = host.toLowerCase();
23299
23465
  if (lower.includes("gitlab")) {
@@ -23306,12 +23472,12 @@ var init_ssh = __esm({
23306
23472
  const withoutUser = trimmed.startsWith("git@") ? trimmed.slice("git@".length) : trimmed;
23307
23473
  const [host, pathPart] = withoutUser.split(":");
23308
23474
  if (!host || !pathPart) return null;
23309
- const path25 = stripGitSuffix2(pathPart);
23475
+ const path26 = stripGitSuffix2(pathPart);
23310
23476
  return {
23311
23477
  host: host.toLowerCase(),
23312
- path: path25,
23478
+ path: path26,
23313
23479
  protocol: "ssh",
23314
- sshUrl: buildSshUrl(host, path25),
23480
+ sshUrl: buildSshUrl(host, path26),
23315
23481
  settingsUrl: buildSettingsUrl(host)
23316
23482
  };
23317
23483
  };
@@ -23328,13 +23494,13 @@ var init_ssh = __esm({
23328
23494
  try {
23329
23495
  const url = new URL(trimmed);
23330
23496
  const host = url.hostname;
23331
- const path25 = stripGitSuffix2(url.pathname);
23332
- if (!host || !path25) return null;
23497
+ const path26 = stripGitSuffix2(url.pathname);
23498
+ if (!host || !path26) return null;
23333
23499
  return {
23334
23500
  host: host.toLowerCase(),
23335
- path: path25,
23501
+ path: path26,
23336
23502
  protocol: "ssh",
23337
- sshUrl: buildSshUrl(host, path25),
23503
+ sshUrl: buildSshUrl(host, path26),
23338
23504
  settingsUrl: buildSettingsUrl(host)
23339
23505
  };
23340
23506
  } catch {
@@ -23345,13 +23511,13 @@ var init_ssh = __esm({
23345
23511
  try {
23346
23512
  const url = new URL(trimmed);
23347
23513
  const host = url.hostname;
23348
- const path25 = stripGitSuffix2(url.pathname);
23349
- if (!host || !path25) return null;
23514
+ const path26 = stripGitSuffix2(url.pathname);
23515
+ if (!host || !path26) return null;
23350
23516
  return {
23351
23517
  host: host.toLowerCase(),
23352
- path: path25,
23518
+ path: path26,
23353
23519
  protocol: "https",
23354
- sshUrl: buildSshUrl(host, path25),
23520
+ sshUrl: buildSshUrl(host, path26),
23355
23521
  settingsUrl: buildSettingsUrl(host)
23356
23522
  };
23357
23523
  } catch {
@@ -24309,21 +24475,25 @@ fi`
24309
24475
  });
24310
24476
 
24311
24477
  // src/devbox/commands/init/codex/plan.ts
24312
- var import_node_path18, import_promises24, resolveSchemaPath, writeSetupEnvSecretsSchema, writeSetupExternalSchema, writeSetupExtraArtifactsSchema, writeServicesSchema, isObject4, isServicesSelection, isSetupPlan, isSetupEnvSecretsPlan, isSetupExternalPlan, isSetupExtraArtifactsPlan, isServicesPlan, readSetupPlan, readSetupEnvSecretsPlan, readSetupExternalPlan, readSetupExtraArtifactsPlan, readServicesPlan, writeSetupPlan, mergeSetupScans;
24478
+ var import_node_path18, import_node_fs5, import_promises24, resolveSchemaPath, writeSetupEnvSecretsSchema, writeSetupExternalSchema, writeSetupExtraArtifactsSchema, writeServicesSchema, isObject4, isServicesSelection, isSetupPlan, isSetupEnvSecretsPlan, isSetupExternalPlan, isSetupExtraArtifactsPlan, isServicesPlan, readSetupPlan, readSetupEnvSecretsPlan, readSetupExternalPlan, readSetupExtraArtifactsPlan, readServicesPlan, writeSetupPlan, mergeSetupScans;
24313
24479
  var init_plan = __esm({
24314
24480
  "src/devbox/commands/init/codex/plan.ts"() {
24315
24481
  "use strict";
24316
24482
  import_node_path18 = __toESM(require("node:path"), 1);
24483
+ import_node_fs5 = __toESM(require("node:fs"), 1);
24317
24484
  import_promises24 = __toESM(require("node:fs/promises"), 1);
24318
24485
  resolveSchemaPath = (fileName) => {
24319
- const binPath = process.argv[1];
24320
- if (binPath) {
24321
- return import_node_path18.default.resolve(
24322
- import_node_path18.default.dirname(binPath),
24323
- "..",
24324
- "codex",
24325
- fileName
24326
- );
24486
+ const argv1 = typeof process.argv[1] === "string" ? process.argv[1] : "";
24487
+ if (argv1) {
24488
+ try {
24489
+ const real = import_node_fs5.default.realpathSync(argv1);
24490
+ return import_node_path18.default.resolve(import_node_path18.default.dirname(real), "..", "codex", fileName);
24491
+ } catch {
24492
+ }
24493
+ try {
24494
+ return import_node_path18.default.resolve(import_node_path18.default.dirname(argv1), "..", "codex", fileName);
24495
+ } catch {
24496
+ }
24327
24497
  }
24328
24498
  return import_node_path18.default.resolve(process.cwd(), "codex", fileName);
24329
24499
  };
@@ -24613,12 +24783,12 @@ ${bottom}
24613
24783
  });
24614
24784
 
24615
24785
  // src/devbox/commands/init/codex/local.ts
24616
- var import_node_child_process9, import_node_fs3, import_promises25, import_node_path19, stripAnsi3, extractBoldText2, runCodexExec, runLocalSetupEnvSecretsScan, runLocalSetupExternalScan, runLocalSetupExtraArtifactsScan, runLocalServicesScan, toPosixPath, toRepoRelativePath, countSecretVars, buildEnvFileHint, buildExternalDependencyLabel, promptForPlanApproval, promptForServicesApproval;
24786
+ var import_node_child_process9, import_node_fs6, import_promises25, import_node_path19, stripAnsi3, extractBoldText2, runCodexExec, runLocalSetupEnvSecretsScan, runLocalSetupExternalScan, runLocalSetupExtraArtifactsScan, runLocalServicesScan, toPosixPath, toRepoRelativePath, countSecretVars, buildEnvFileHint, buildExternalDependencyLabel, promptForPlanApproval, promptForServicesApproval;
24617
24787
  var init_local = __esm({
24618
24788
  "src/devbox/commands/init/codex/local.ts"() {
24619
24789
  "use strict";
24620
24790
  import_node_child_process9 = require("node:child_process");
24621
- import_node_fs3 = require("node:fs");
24791
+ import_node_fs6 = require("node:fs");
24622
24792
  import_promises25 = __toESM(require("node:fs/promises"), 1);
24623
24793
  import_node_path19 = __toESM(require("node:path"), 1);
24624
24794
  init_dist2();
@@ -24637,11 +24807,11 @@ var init_local = __esm({
24637
24807
  try {
24638
24808
  if (stdoutLogPath) {
24639
24809
  await import_promises25.default.mkdir(import_node_path19.default.dirname(stdoutLogPath), { recursive: true });
24640
- stdoutStream = (0, import_node_fs3.createWriteStream)(stdoutLogPath, { flags: "a" });
24810
+ stdoutStream = (0, import_node_fs6.createWriteStream)(stdoutLogPath, { flags: "a" });
24641
24811
  }
24642
24812
  if (stderrLogPath) {
24643
24813
  await import_promises25.default.mkdir(import_node_path19.default.dirname(stderrLogPath), { recursive: true });
24644
- stderrStream = (0, import_node_fs3.createWriteStream)(stderrLogPath, { flags: "a" });
24814
+ stderrStream = (0, import_node_fs6.createWriteStream)(stderrLogPath, { flags: "a" });
24645
24815
  }
24646
24816
  } catch {
24647
24817
  stdoutStream = null;
@@ -30485,11 +30655,11 @@ var init_services = __esm({
30485
30655
  };
30486
30656
  loadConfigFromSprite = async (client, canonical) => {
30487
30657
  const workdir = await resolveProjectWorkdir(client, canonical);
30488
- const path25 = workdir ? `${workdir.replace(/\/$/, "")}/devbox.toml` : null;
30658
+ const path26 = workdir ? `${workdir.replace(/\/$/, "")}/devbox.toml` : null;
30489
30659
  if (!workdir) {
30490
30660
  return {
30491
30661
  workdir: null,
30492
- path: path25,
30662
+ path: path26,
30493
30663
  content: null,
30494
30664
  services: {},
30495
30665
  missing: true,
@@ -30504,7 +30674,7 @@ var init_services = __esm({
30504
30674
  const content = Buffer.from(bytes).toString("utf8");
30505
30675
  return {
30506
30676
  workdir,
30507
- path: path25,
30677
+ path: path26,
30508
30678
  content,
30509
30679
  services: parseServicesToml(content),
30510
30680
  missing: false
@@ -30513,7 +30683,7 @@ var init_services = __esm({
30513
30683
  if (error instanceof SpritesApiError && error.status === 404) {
30514
30684
  return {
30515
30685
  workdir,
30516
- path: path25,
30686
+ path: path26,
30517
30687
  content: null,
30518
30688
  services: {},
30519
30689
  missing: true
@@ -30521,7 +30691,7 @@ var init_services = __esm({
30521
30691
  }
30522
30692
  return {
30523
30693
  workdir,
30524
- path: path25,
30694
+ path: path26,
30525
30695
  content: null,
30526
30696
  services: {},
30527
30697
  missing: false,
@@ -30993,8 +31163,144 @@ var init_setup = __esm({
30993
31163
  }
30994
31164
  });
30995
31165
 
31166
+ // src/devbox/commands/version.ts
31167
+ var import_node_module, import_node_path24, parseVersionArgs, readPackageVersion, tryReadDaemonInfo, runVersion;
31168
+ var init_version = __esm({
31169
+ "src/devbox/commands/version.ts"() {
31170
+ "use strict";
31171
+ import_node_module = require("node:module");
31172
+ import_node_path24 = __toESM(require("node:path"), 1);
31173
+ init_src();
31174
+ init_src();
31175
+ init_controlPlane();
31176
+ init_daemonClient();
31177
+ parseVersionArgs = (args) => {
31178
+ const parsed = { json: false };
31179
+ for (const arg of args) {
31180
+ if (!arg) continue;
31181
+ if (arg === "--json") {
31182
+ parsed.json = true;
31183
+ continue;
31184
+ }
31185
+ if (arg === "--help" || arg === "-h") {
31186
+ throw new Error("help_requested");
31187
+ }
31188
+ if (arg.startsWith("-")) {
31189
+ throw new Error(`Unknown version flag: ${arg}`);
31190
+ }
31191
+ throw new Error(`Unexpected argument: ${arg}`);
31192
+ }
31193
+ return parsed;
31194
+ };
31195
+ readPackageVersion = () => {
31196
+ const fromArgv = typeof process.argv[1] === "string" ? process.argv[1] : "";
31197
+ const from = fromArgv ? import_node_path24.default.resolve(fromArgv) : import_node_path24.default.join(process.cwd(), "dvb");
31198
+ const require3 = (0, import_node_module.createRequire)(from);
31199
+ try {
31200
+ const pkg = require3("@boxes-dev/dvb/package.json");
31201
+ return typeof pkg.version === "string" ? pkg.version : "unknown";
31202
+ } catch {
31203
+ return "unknown";
31204
+ }
31205
+ };
31206
+ tryReadDaemonInfo = async (socketPath) => {
31207
+ try {
31208
+ const health = await requestJson3(
31209
+ socketPath,
31210
+ "GET",
31211
+ "/health",
31212
+ DAEMON_TIMEOUT_MS.health
31213
+ );
31214
+ if (health.status !== 200 || !health.body.ok) return null;
31215
+ const version2 = await requestJson3(
31216
+ socketPath,
31217
+ "GET",
31218
+ "/version",
31219
+ DAEMON_TIMEOUT_MS.quick
31220
+ );
31221
+ return {
31222
+ health: health.body,
31223
+ version: version2.status === 200 ? version2.body : null
31224
+ };
31225
+ } catch {
31226
+ return null;
31227
+ }
31228
+ };
31229
+ runVersion = async (args) => {
31230
+ const parsed = parseVersionArgs(args);
31231
+ const dvbVersion = readPackageVersion();
31232
+ const nodeVersion = process.versions.node;
31233
+ const controlPlaneUrl = getControlPlaneUrl();
31234
+ const convexUrl = getConvexUrl();
31235
+ const homeDir = process.env.HOME?.trim();
31236
+ const config = await loadConfig(homeDir ? { homeDir } : void 0);
31237
+ const store = await createSecretStore(
31238
+ config?.tokenStore,
31239
+ homeDir ? { homeDir } : void 0
31240
+ );
31241
+ const spritesTokenPresent = Boolean(await store.getToken());
31242
+ const controlPlaneTokenPresent = Boolean(await store.getControlPlaneToken());
31243
+ const controlPlaneRefreshTokenPresent = Boolean(
31244
+ await store.getControlPlaneRefreshToken()
31245
+ );
31246
+ const socketInfo = resolveSocketInfo();
31247
+ const daemon = await tryReadDaemonInfo(socketInfo.socketPath);
31248
+ if (parsed.json) {
31249
+ console.log(
31250
+ JSON.stringify(
31251
+ {
31252
+ dvb: { version: dvbVersion },
31253
+ node: { version: nodeVersion },
31254
+ auth: {
31255
+ spritesToken: spritesTokenPresent,
31256
+ controlPlaneToken: controlPlaneTokenPresent,
31257
+ controlPlaneRefreshToken: controlPlaneRefreshTokenPresent
31258
+ },
31259
+ config: {
31260
+ controlPlaneUrl,
31261
+ convexUrl,
31262
+ socketPath: socketInfo.socketPath
31263
+ },
31264
+ dvbd: daemon ? {
31265
+ pid: daemon.health.pid,
31266
+ startedAt: daemon.health.startedAt,
31267
+ apiVersion: daemon.version?.apiVersion ?? null,
31268
+ features: daemon.version?.features ?? null
31269
+ } : null
31270
+ },
31271
+ null,
31272
+ 2
31273
+ )
31274
+ );
31275
+ return;
31276
+ }
31277
+ console.log(`dvb ${dvbVersion}`);
31278
+ console.log(`node ${nodeVersion}`);
31279
+ console.log(`control plane: ${controlPlaneUrl ?? "(not set/embedded)"}`);
31280
+ console.log(`convex: ${convexUrl ?? "(not set/embedded)"}`);
31281
+ console.log(
31282
+ `auth: sprites=${spritesTokenPresent ? "ok" : "missing"} control_plane=${controlPlaneTokenPresent ? "ok" : "missing"}`
31283
+ );
31284
+ console.log(`socket: ${socketInfo.socketPath}`);
31285
+ if (daemon) {
31286
+ const apiVersion = daemon.version?.apiVersion;
31287
+ const features = Array.isArray(daemon.version?.features) ? daemon.version?.features.join(", ") : "";
31288
+ console.log(`dvbd: running (pid ${daemon.health.pid})`);
31289
+ if (typeof apiVersion === "number") {
31290
+ console.log(`dvbd api: ${apiVersion}`);
31291
+ }
31292
+ if (features) {
31293
+ console.log(`dvbd features: ${features}`);
31294
+ }
31295
+ } else {
31296
+ console.log("dvbd: not running");
31297
+ }
31298
+ };
31299
+ }
31300
+ });
31301
+
30996
31302
  // src/devbox/commands/wezterm.ts
30997
- var import_node_crypto13, import_node_child_process11, import_promises31, import_node_os10, import_node_path24, import_promises32, 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, resolveCanonical3, initWeztermClient, waitForWeztermMuxHealthy, ensureWeztermMuxReady, runWeztermProxy, runCommand6, promptYesNo2, fileExists, hasWeztermOnPath, resolveShellProfilePath, ensureWeztermOnPath, ensureWeztermInstalled, expandPath, resolveDefaultConfigPath, escapeRegExp, resolveCliName2, resolveDvbCommand, formatLuaArgs, resolveWeztermProxyEnv, buildProxyCommand, buildDomainBlock, canAppendToConfig, countReturns, applyReturnTableTransform, insertBlock, runWeztermSetup, startWeztermDomain, runWezterm;
31303
+ var import_node_crypto13, import_node_child_process11, import_promises31, import_node_os10, import_node_path25, import_promises32, 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, resolveCanonical3, initWeztermClient, waitForWeztermMuxHealthy, ensureWeztermMuxReady, runWeztermProxy, runCommand6, promptYesNo2, fileExists, hasWeztermOnPath, resolveShellProfilePath, ensureWeztermOnPath, ensureWeztermInstalled, expandPath, resolveDefaultConfigPath, escapeRegExp, resolveCliName2, resolveDvbCommand, formatLuaArgs, resolveWeztermProxyEnv, buildProxyCommand, buildDomainBlock, canAppendToConfig, countReturns, applyReturnTableTransform, insertBlock, runWeztermSetup, startWeztermDomain, runWezterm;
30998
31304
  var init_wezterm = __esm({
30999
31305
  "src/devbox/commands/wezterm.ts"() {
31000
31306
  "use strict";
@@ -31002,7 +31308,7 @@ var init_wezterm = __esm({
31002
31308
  import_node_child_process11 = require("node:child_process");
31003
31309
  import_promises31 = __toESM(require("node:fs/promises"), 1);
31004
31310
  import_node_os10 = __toESM(require("node:os"), 1);
31005
- import_node_path24 = __toESM(require("node:path"), 1);
31311
+ import_node_path25 = __toESM(require("node:path"), 1);
31006
31312
  import_promises32 = __toESM(require("node:readline/promises"), 1);
31007
31313
  init_src();
31008
31314
  init_daemonClient();
@@ -31194,11 +31500,11 @@ var init_wezterm = __esm({
31194
31500
  const homeDir = import_node_os10.default.homedir();
31195
31501
  if (!homeDir) return;
31196
31502
  try {
31197
- const logDir = import_node_path24.default.join(resolveDevboxDir(homeDir), "wezterm");
31503
+ const logDir = import_node_path25.default.join(resolveDevboxDir(homeDir), "wezterm");
31198
31504
  await import_promises31.default.mkdir(logDir, { recursive: true });
31199
31505
  const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${message}
31200
31506
  `;
31201
- await import_promises31.default.appendFile(import_node_path24.default.join(logDir, WEZTERM_PROXY_LOG_NAME), line, "utf8");
31507
+ await import_promises31.default.appendFile(import_node_path25.default.join(logDir, WEZTERM_PROXY_LOG_NAME), line, "utf8");
31202
31508
  } catch {
31203
31509
  }
31204
31510
  };
@@ -31441,16 +31747,16 @@ var init_wezterm = __esm({
31441
31747
  }
31442
31748
  const shell = process.env.SHELL ?? "";
31443
31749
  if (shell.includes("zsh")) {
31444
- return import_node_path24.default.join(homeDir, ".zshrc");
31750
+ return import_node_path25.default.join(homeDir, ".zshrc");
31445
31751
  }
31446
31752
  if (shell.includes("bash")) {
31447
- const profile = import_node_path24.default.join(homeDir, ".bash_profile");
31753
+ const profile = import_node_path25.default.join(homeDir, ".bash_profile");
31448
31754
  if (await fileExists(profile)) {
31449
31755
  return profile;
31450
31756
  }
31451
- return import_node_path24.default.join(homeDir, ".bashrc");
31757
+ return import_node_path25.default.join(homeDir, ".bashrc");
31452
31758
  }
31453
- return import_node_path24.default.join(homeDir, ".profile");
31759
+ return import_node_path25.default.join(homeDir, ".profile");
31454
31760
  };
31455
31761
  ensureWeztermOnPath = async () => {
31456
31762
  if (await hasWeztermOnPath()) {
@@ -31507,7 +31813,7 @@ ${content ? "\n" : ""}${WEZTERM_PATH_EXPORT}
31507
31813
  expandPath = (value) => {
31508
31814
  if (value.startsWith("~/")) {
31509
31815
  const homeDir = process.env.HOME ?? "";
31510
- return homeDir ? import_node_path24.default.join(homeDir, value.slice(2)) : value;
31816
+ return homeDir ? import_node_path25.default.join(homeDir, value.slice(2)) : value;
31511
31817
  }
31512
31818
  return value;
31513
31819
  };
@@ -31517,8 +31823,8 @@ ${content ? "\n" : ""}${WEZTERM_PATH_EXPORT}
31517
31823
  throw new Error("HOME is not set; pass --path to wezterm setup.");
31518
31824
  }
31519
31825
  const candidates = [
31520
- import_node_path24.default.join(homeDir, ".wezterm.lua"),
31521
- import_node_path24.default.join(homeDir, ".config", "wezterm", "wezterm.lua")
31826
+ import_node_path25.default.join(homeDir, ".wezterm.lua"),
31827
+ import_node_path25.default.join(homeDir, ".config", "wezterm", "wezterm.lua")
31522
31828
  ];
31523
31829
  for (const candidate of candidates) {
31524
31830
  try {
@@ -31539,7 +31845,7 @@ ${content ? "\n" : ""}${WEZTERM_PATH_EXPORT}
31539
31845
  resolveDvbCommand = async () => {
31540
31846
  const scriptPath = process.argv[1];
31541
31847
  if (scriptPath) {
31542
- const candidate = import_node_path24.default.isAbsolute(scriptPath) ? scriptPath : import_node_path24.default.resolve(process.cwd(), scriptPath);
31848
+ const candidate = import_node_path25.default.isAbsolute(scriptPath) ? scriptPath : import_node_path25.default.resolve(process.cwd(), scriptPath);
31543
31849
  try {
31544
31850
  await import_promises31.default.access(candidate);
31545
31851
  return [process.execPath, candidate];
@@ -31679,7 +31985,7 @@ ${block}`;
31679
31985
  }
31680
31986
  }
31681
31987
  if (updated) {
31682
- await import_promises31.default.mkdir(import_node_path24.default.dirname(configPath), { recursive: true });
31988
+ await import_promises31.default.mkdir(import_node_path25.default.dirname(configPath), { recursive: true });
31683
31989
  await import_promises31.default.writeFile(configPath, nextContent, "utf8");
31684
31990
  console.log(`Updated WezTerm config: ${configPath}`);
31685
31991
  } else {
@@ -31780,10 +32086,12 @@ var init_cli = __esm({
31780
32086
  init_sessions2();
31781
32087
  init_services();
31782
32088
  init_setup();
32089
+ init_version();
31783
32090
  init_wezterm();
31784
32091
  init_completions();
31785
32092
  printUsage = () => {
31786
32093
  console.log("Usage:");
32094
+ console.log(" dvb --version");
31787
32095
  console.log(" dvb setup [--token <token>] [--org <slug>]");
31788
32096
  console.log(" [--api-base-url <url>] [--no-verify] [--json]");
31789
32097
  console.log(" dvb logout [--json]");
@@ -31836,6 +32144,7 @@ var init_cli = __esm({
31836
32144
  console.log(
31837
32145
  " dvb wezterm [<box>] [--port <port>] [--domain <name>] [--path <path>]"
31838
32146
  );
32147
+ console.log(" dvb version [--json]");
31839
32148
  };
31840
32149
  main2 = async () => {
31841
32150
  const args = process.argv.slice(2);
@@ -31843,9 +32152,25 @@ var init_cli = __esm({
31843
32152
  printUsage();
31844
32153
  return;
31845
32154
  }
32155
+ if (args[0] === "--version") {
32156
+ await runVersion([]);
32157
+ return;
32158
+ }
31846
32159
  if (args[0] !== "complete" && args[0] !== "completions") {
31847
32160
  await maybeAutoUpdateCompletions();
31848
32161
  }
32162
+ if (args[0] === "version") {
32163
+ try {
32164
+ await runVersion(args.slice(1));
32165
+ } catch (error) {
32166
+ if (error instanceof Error && error.message === "help_requested") {
32167
+ printUsage();
32168
+ return;
32169
+ }
32170
+ throw error;
32171
+ }
32172
+ return;
32173
+ }
31849
32174
  if (args[0] === "setup") {
31850
32175
  await runSetup(args.slice(1));
31851
32176
  return;
@@ -31929,9 +32254,9 @@ var init_cli = __esm({
31929
32254
  });
31930
32255
 
31931
32256
  // src/bin/dvb.ts
31932
- var import_node_fs4 = __toESM(require("node:fs"), 1);
32257
+ var import_node_fs7 = __toESM(require("node:fs"), 1);
31933
32258
  var import_node_os11 = __toESM(require("node:os"), 1);
31934
- var import_node_path25 = __toESM(require("node:path"), 1);
32259
+ var import_node_path26 = __toESM(require("node:path"), 1);
31935
32260
  init_src();
31936
32261
  var MIN_NODE_MAJOR = 24;
31937
32262
  var assertNodeVersion = () => {
@@ -31986,10 +32311,10 @@ run().catch((error) => {
31986
32311
  const homeDir = import_node_os11.default.homedir();
31987
32312
  if (homeDir) {
31988
32313
  try {
31989
- const logDir = import_node_path25.default.join(resolveDevboxDir(homeDir), "wezterm");
31990
- import_node_fs4.default.mkdirSync(logDir, { recursive: true });
31991
- import_node_fs4.default.appendFileSync(
31992
- import_node_path25.default.join(logDir, "proxy.log"),
32314
+ const logDir = import_node_path26.default.join(resolveDevboxDir(homeDir), "wezterm");
32315
+ import_node_fs7.default.mkdirSync(logDir, { recursive: true });
32316
+ import_node_fs7.default.appendFileSync(
32317
+ import_node_path26.default.join(logDir, "proxy.log"),
31993
32318
  `${(/* @__PURE__ */ new Date()).toISOString()} ${message}
31994
32319
  `
31995
32320
  );