@boxes-dev/dvb-runtime 1.0.958 → 1.0.959

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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
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]="8cb3e81f-1a45-5309-aca4-748b6f610d13")}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]="622a15c0-7c29-5be9-a35c-b1a193a6b0f0")}catch(e){}}();
4
4
  import { createRequire as __dvbCreateRequire } from "node:module";
5
5
  import { dirname as __dvbDirname } from "node:path";
6
6
  import { fileURLToPath as __dvbFileURLToPath } from "node:url";
@@ -101145,8 +101145,8 @@ var init_otel = __esm({
101145
101145
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
101146
101146
  };
101147
101147
  readBuildMetadata = () => {
101148
- const rawPackageVersion = "1.0.958";
101149
- const rawGitSha = "1436ae0e44cbd7325937bad75a389dc22a69ba80";
101148
+ const rawPackageVersion = "1.0.959";
101149
+ const rawGitSha = "c5992d38486ffdbc188773dfe7556175ffb24abc";
101150
101150
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
101151
101151
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
101152
101152
  return { packageVersion, gitSha };
@@ -133552,9 +133552,9 @@ var init_sentry = __esm({
133552
133552
  uncaughtExceptionMonitorInstalled = false;
133553
133553
  currentDevboxSentryUser = null;
133554
133554
  readBuildMetadata2 = () => {
133555
- const rawPackageVersion = "1.0.958";
133556
- const rawGitSha = "1436ae0e44cbd7325937bad75a389dc22a69ba80";
133557
- const rawSentryRelease = "boxes-dev-dvb@1.0.958+1436ae0e44cbd7325937bad75a389dc22a69ba80";
133555
+ const rawPackageVersion = "1.0.959";
133556
+ const rawGitSha = "c5992d38486ffdbc188773dfe7556175ffb24abc";
133557
+ const rawSentryRelease = "boxes-dev-dvb@1.0.959+c5992d38486ffdbc188773dfe7556175ffb24abc";
133558
133558
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
133559
133559
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
133560
133560
  const sentryRelease = typeof rawSentryRelease === "string" ? rawSentryRelease : void 0;
@@ -138235,8 +138235,8 @@ var init_desktopSetupReview = __esm({
138235
138235
  const summary = uniqueNonEmpty(sourceParts).join(" \xB7 ");
138236
138236
  return summary || databaseSourceKindLabel(entry.source.kind);
138237
138237
  };
138238
- createItem = ({ detailLines = [], included = true, section, source, sourceIndex, subtitle = null, title, warning: warning3 = null }) => ({
138239
- id: itemId({ section, source, sourceIndex }),
138238
+ createItem = ({ detailLines = [], id: id2 = null, included = true, section, source, sourceIndex, subtitle = null, title, warning: warning3 = null }) => ({
138239
+ id: id2 ?? itemId({ section, source, sourceIndex }),
138240
138240
  section,
138241
138241
  source,
138242
138242
  sourceIndex,
@@ -138300,6 +138300,8 @@ var init_desktopSetupReview = __esm({
138300
138300
  }));
138301
138301
  case "databases":
138302
138302
  return plan.databaseCopies.map((entry, index) => createItem({
138303
+ id: `databases:database_copy:${encodeURIComponent(entry.id)}`,
138304
+ included: entry.canAutomate,
138303
138305
  section,
138304
138306
  source: "database_copy",
138305
138307
  sourceIndex: index,
@@ -138717,7 +138719,7 @@ var init_packageVersion = __esm({
138717
138719
  return path17.join(process.cwd(), "dvb");
138718
138720
  };
138719
138721
  readEmbeddedPackageVersion = () => {
138720
- const raw = "1.0.958";
138722
+ const raw = "1.0.959";
138721
138723
  return trimVersion(raw);
138722
138724
  };
138723
138725
  readNearestPackageMetadata = (basePath) => {
@@ -204404,7 +204406,7 @@ var formatThreadBackendLabel, formatThreadBackendConnectingLabel, formatThreadBa
204404
204406
  var init_threadBackendLabels = __esm({
204405
204407
  "../../../../shared/threadRuntime/threadBackendLabels.ts"() {
204406
204408
  "use strict";
204407
- formatThreadBackendLabel = (backend) => backend === "codex" ? "Codex" : backend === "claude_code" ? "Claude Code CLI" : "Claude Code";
204409
+ formatThreadBackendLabel = (backend) => backend === "codex" ? "Codex" : "Claude";
204408
204410
  formatThreadBackendConnectingLabel = (backend) => `Connecting ${formatThreadBackendLabel(backend)}`;
204409
204411
  formatThreadBackendDefaultTitle = (backend) => `${formatThreadBackendLabel(backend)} thread`;
204410
204412
  }
@@ -231930,7 +231932,7 @@ var init_actionPresentation = __esm({
231930
231932
  switch (outcome.kind) {
231931
231933
  case "detached":
231932
231934
  return {
231933
- message: backend === "claude_code" ? "Claude is still running. Press Enter to reattach its terminal." : "Claude is still open in terminal. Press Enter to reattach.",
231935
+ message: "Claude is still open in terminal. Press Enter to reattach.",
231934
231936
  tone: "neutral"
231935
231937
  };
231936
231938
  case "terminal_exit":
@@ -286497,10 +286499,6 @@ var init_controller = __esm({
286497
286499
  }
286498
286500
  let target = null;
286499
286501
  if (selected.kind === "thread") {
286500
- if (selected.target.backend === "claude_code") {
286501
- this.setPreviewUnavailableForClaudeCode();
286502
- return;
286503
- }
286504
286502
  target = {
286505
286503
  selectedKey: selected.key,
286506
286504
  primaryInstanceId: selected.target.primaryInstanceId,
@@ -286519,10 +286517,6 @@ var init_controller = __esm({
286519
286517
  );
286520
286518
  return;
286521
286519
  }
286522
- if (anchor.backend === "claude_code") {
286523
- this.setPreviewUnavailableForClaudeCode();
286524
- return;
286525
- }
286526
286520
  target = {
286527
286521
  selectedKey: selected.key,
286528
286522
  primaryInstanceId: anchor.primaryInstanceId,
@@ -286610,11 +286604,6 @@ var init_controller = __esm({
286610
286604
  confirmPreviewRendered(args) {
286611
286605
  this.peekController.confirmRendered(args);
286612
286606
  }
286613
- setPreviewUnavailableForClaudeCode() {
286614
- this.setPreviewControlStatus(
286615
- "Preview isn\u2019t available for Claude Code threads. Press Enter to open this thread."
286616
- );
286617
- }
286618
286607
  setPreviewControlStatus(message) {
286619
286608
  this.selectedActionStatusContext = null;
286620
286609
  this.snapshot = {
@@ -286899,7 +286888,7 @@ var init_controller = __esm({
286899
286888
  selected,
286900
286889
  suspendAction ?? (async (callback) => await callback())
286901
286890
  );
286902
- } else if (selected.kind === "thread" && (selected.actions.enter.backend === "claude" || selected.actions.enter.backend === "claude_code")) {
286891
+ } else if (selected.kind === "thread" && selected.actions.enter.backend === "claude") {
286903
286892
  await this.activateClaudeThread(
286904
286893
  selected,
286905
286894
  suspendAction ?? (async (callback) => await callback()),
@@ -287342,7 +287331,7 @@ var init_controller = __esm({
287342
287331
  }
287343
287332
  async activateClaudeThread(selected, suspendAction, confirmation) {
287344
287333
  const action = selected.actions.enter;
287345
- if (action.kind !== "native_thread" || action.backend !== "claude" && action.backend !== "claude_code" || !this.actionDependencies.openClaude) {
287334
+ if (action.kind !== "native_thread" || action.backend !== "claude" || !this.actionDependencies.openClaude) {
287346
287335
  return;
287347
287336
  }
287348
287337
  const claudeBackend = action.backend;
@@ -287352,7 +287341,7 @@ var init_controller = __esm({
287352
287341
  ...this.snapshot,
287353
287342
  claudeConfirmation: null,
287354
287343
  selectedActionPending: true,
287355
- selectedActionPendingLabel: claudeBackend === "claude_code" ? "Opening terminal\u2026" : confirmation !== null && confirmationWarning === "desktop_turn_active" ? "Interrupting Claude in the desktop app\u2026" : "Opening Claude in terminal\u2026",
287344
+ selectedActionPendingLabel: confirmation !== null && confirmationWarning === "desktop_turn_active" ? "Interrupting Claude in the desktop app\u2026" : "Opening Claude in terminal\u2026",
287356
287345
  selectedActionStatusMessage: null,
287357
287346
  selectedActionStatusTone: "neutral"
287358
287347
  };
@@ -292629,7 +292618,7 @@ var init_workspaceProtocol = __esm({
292629
292618
  };
292630
292619
  }
292631
292620
  if (kind === "claude") {
292632
- if (record3.backend !== "claude" && record3.backend !== "claude_code") {
292621
+ if (record3.backend !== "claude") {
292633
292622
  throw new Error("Invalid workspace Claude backend.");
292634
292623
  }
292635
292624
  return {
@@ -292802,7 +292791,7 @@ var init_workspaceActionClient = __esm({
292802
292791
  case "codex_empty":
292803
292792
  return "Codex";
292804
292793
  case "claude":
292805
- return action.backend === "claude_code" ? "Claude Code" : "Claude";
292794
+ return "Claude";
292806
292795
  case "claude_empty":
292807
292796
  return "Claude";
292808
292797
  case "shell":
@@ -300614,7 +300603,7 @@ var init_scanOutputs = __esm({
300614
300603
  return false;
300615
300604
  }
300616
300605
  const resolved = source.resolvedNonSecret;
300617
- return typeof value.id === "string" && typeof value.engine === "string" && typeof value.displayLabel === "string" && typeof value.canAutomate === "boolean" && typeof value.confidence === "string" && Array.isArray(value.evidence) && typeof source.kind === "string" && Array.isArray(source.refs) && source.refs.every(isDatabaseSourceRef) && isObject8(resolved) && (resolved.host === null || typeof resolved.host === "string") && (resolved.port === null || typeof resolved.port === "number") && (resolved.database === null || typeof resolved.database === "string") && (resolved.username === null || typeof resolved.username === "string") && (resolved.schema === null || typeof resolved.schema === "string") && (resolved.sslMode === null || typeof resolved.sslMode === "string") && typeof source.locality === "string" && typeof target.mode === "string" && (target.ref === null || typeof target.ref === "string") && typeof restoreHint.commandFamily === "string" && typeof restoreHint.expectedFormat === "string" && (value.skipReason === null || typeof value.skipReason === "string");
300606
+ return typeof value.id === "string" && value.id.trim().length > 0 && typeof value.engine === "string" && typeof value.displayLabel === "string" && typeof value.canAutomate === "boolean" && typeof value.confidence === "string" && Array.isArray(value.evidence) && typeof source.kind === "string" && Array.isArray(source.refs) && source.refs.every(isDatabaseSourceRef) && isObject8(resolved) && (resolved.host === null || typeof resolved.host === "string") && (resolved.port === null || typeof resolved.port === "number") && (resolved.database === null || typeof resolved.database === "string") && (resolved.username === null || typeof resolved.username === "string") && (resolved.schema === null || typeof resolved.schema === "string") && (resolved.sslMode === null || typeof resolved.sslMode === "string") && typeof source.locality === "string" && typeof target.mode === "string" && (target.ref === null || typeof target.ref === "string") && typeof restoreHint.commandFamily === "string" && typeof restoreHint.expectedFormat === "string" && (value.skipReason === null || typeof value.skipReason === "string");
300618
300607
  };
300619
300608
  isManagedConfigPath = (value, rootName) => {
300620
300609
  const normalized = value.replaceAll("\\", "/").replace(/\/+$/u, "").trim();
@@ -300665,6 +300654,11 @@ var init_scanOutputs = __esm({
300665
300654
  if (!databaseCandidates.every(isDatabaseCopyCandidate)) {
300666
300655
  throw new Error("Invalid database candidate scan output.");
300667
300656
  }
300657
+ if (new Set(databaseCandidates.map((candidate) => candidate.id)).size !== databaseCandidates.length) {
300658
+ throw new Error(
300659
+ "Invalid database candidate scan output: ids must be unique."
300660
+ );
300661
+ }
300668
300662
  return {
300669
300663
  schemaVersion: parsed.schemaVersion,
300670
300664
  scanFullyCompleted: parsed.scanFullyCompleted,
@@ -303585,7 +303579,7 @@ import os25 from "node:os";
303585
303579
  import path51 from "node:path";
303586
303580
  import process25 from "node:process";
303587
303581
  import { pipeline } from "node:stream/promises";
303588
- var SNAPSHOT_VERSION, X25519_SPKI_DER_PREFIX, DATABASE_DUMP_TIMEOUT_MS, REPO_SSH_VERIFY_TIMEOUT_MS, DATABASE_DUMP_TOOL_MISSING_ERROR_CODE, DATABASE_DUMP_CLIENT_VERSION_MISMATCH_ERROR_CODE, DATABASE_DUMP_FAILED_ERROR_CODE, MULTIPART_UPLOAD_URL_REFRESH_SKEW_MS, nowIso7, trim10, toErrorMessage, toRedactedError, normalizeAgentConfigSelection2, createAgentConfigSnapshot, normalizeAgentThreadHistorySelection, normalizeAgentThreadImportWarning, normalizeAgentThreadImportScope, createAgentThreadHistorySnapshot, assertGitSigningReadyForBundle, shellQuote5, ensureDir7, pathExists4, readJsonFile2, writeJsonFile4, writeRepoMarker, runCommand7, runCommandToFile, formatMissingDatabaseDumpToolMessage, createMissingDatabaseDumpToolError, createPostgresDumpVersionMismatchError, createDatabaseDumpExecutionError, executeDatabaseDumpCommand, runDatabaseDumpCommand, spawnCommand, isRepoInitArtifactPath2, readDirtyWorktreeState, readProjectDirtyWorktreeState, hasGitHead, readGitHeadInfo, copyPathIntoRoot, isPathInside, copyLocalPath2, createUserFacingEnvFileError, deriveEnvStagingId, snapshotEnvStagingFile, deleteEnvStagingFile, pruneEnvStagingFilesExcept, copyStagedEditableSetupFile, createRepoPayloadOwnership, createProjectPayloadOwnership, relativeFromStagingRoot2, resolveRepoPayloadRoot, addCopiedInventoryLeaf2, copyPathWithInventory2, copyPathWithRepoPayloadExclusions, directorySize3, createInitialScanState, createApprovals, createUploadState, setUploadProgressState, createBundleOptions, createLfsWithoutRepoSshWarning, buildLocalPrepWarnings, createForkStartupScriptSetup, createDestroyedLocalPrepSnapshot, mergeSetupPlanForRescan, SETUP_REVIEW_SECTION_SCAN_CATEGORY, reviewStatusForScanStatus, buildReviewSectionStatusesFromScanState, buildReviewState, normalizeSetupReviewRescanRequest, getSetupReviewSectionsForScanCategories, normalizeSetupReviewRetryFailedScansRequest, assertRetryableInterruptedScanCategories, DESKTOP_INIT_SCAN_FOCUS_SET, createDesktopInitRequestValidationError, isDesktopInitRequestValidationError, normalizeDesktopInitScanFocus, normalizeLocalPrepScanCategories, hasStartedOrSkippedInitialScan, resolveLockedScanFocus, isInitialScanCategoryResolved, areInitialScanCategoriesResolved, getRunnableInitialScanCategories, getSkippableInitialScanCategories, applyRescanStateToReview, markScanCategories, normalizeDirtyWorktreeForSnapshot, normalizeScanStateForSnapshot, createSnapshotFromState, createLocalPrepState, buildSkippedRepoSshSetup, getRepoSshBundleDecisionKey, parseGitRemoteHost2, acquireLocalLock, releaseLocalLock, captureShellEnvironment, safeName2, resolveSetupArtifactSource, findOwningProjectLayoutRepo, gitCommandSucceeds, isIgnoredUntrackedRepoFile, resolveEnvFileArtifactSource, isEligibleAgentEnvFileSource, buildReviewEnvFileEntry, enrichSetupPlanEnvFiles, DESKTOP_SHELL_RC_IMPORTS, resolveShellRcSourcePath, deriveShellRcStagingId, resolvesToShellRcSource, enrichSetupPlanShellRcFiles, wrapSetupArtifactCopyError, copySetupArtifacts, collectRepoScopedSetupArtifactPaths, copyGitMetadata, copyGlobalGitConfig, ensureDevboxAccessPublicKey, writeDirtyPayloads, GIT_CHECK_ATTR_PATH_CHUNK_SIZE, forEachTrackedLfsManagedPath, createLfsWorktreePayloads, createRepoPayloads, createProjectRootPayloads, createAggregateRepoPayloadState, addRepoPayloadState, buildSkippedRepoSshSetupForLayoutRepo, shouldConvertHttpsRepoOriginToSsh, buildRepoSshSetupForLayoutRepo, getPreOwnedRepoPathsForLayoutRepo, createProjectRepoPayloads, stripEnvValueQuotes, readRawEnvFileValues, resolveLocalReferencePath, parseEnvFileRef, readDatabaseEnvFileValue, getDatabaseValueForRole, isSupportedDatabaseUrlProtocol, parseDatabaseUrlForDump, appendEnvValue, normalizeDatabasePort, resolveDatabaseConnectionFields, resolveDatabaseDumpCommand, safeDatabaseDumpBaseName, formatDatabaseDumpFailureMessage, createDatabaseDumpFailureError, preflightDatabaseDumpCandidates, createDatabasePayloads, stripLocalEnvFileReviewMetadata, stripLocalExternalConfigReviewMetadata, buildRemoteSetupPlan, createInnerBundleStaging, stageRepoSshSetup, createTarGz, sha256File2, encryptBundle, buildX25519PublicKey, createKeyEnvelope, createPrivatePublicX25519Pair, MULTIPART_UPLOAD_RECOVERY_ROUND_COUNT, MULTIPART_UPLOAD_RECOVERY_BASE_DELAY_MS, REMOTE_DESTROY_POLL_INTERVAL_MS, REMOTE_DESTROY_TIMEOUT_MS, sleep5, sanitizeMultipartUploadPartsForState, createMultipartUploadState, shouldRefreshMultipartUploadUrlsBeforeUpload, normalizeRepo, normalizeOptionalProjectInstanceTypeKey, normalizeSelectedProjectRepoRelPaths, buildDesktopProjectLayoutRepo, readGitConfigValues, unsetGitConfigIfExactlyMatches, removeEmptyDirectoryIfPresent, shouldCleanupProjectLayoutClaims, cleanupProjectLayoutClaims, resolveSelectedProjectRepoRelPaths, claimDesktopProjectLayout, buildLocalScanProjectLayoutContext, normalizeSelectedAgents, normalizeBackendJobReference, getRemoteDestroyFailureMessage, waitForRemoteDestroyCompletion, normalizeApprovedEnvFile, normalizeApprovedPlan, shouldPreserveVerifiedRepoSshSetup, normalizeManagedGithubAccessRepository, normalizeManagedGithubAccess, buildManagedGithubAccessForProjectLayout, createDesktopLocalPrepService;
303582
+ var SNAPSHOT_VERSION, X25519_SPKI_DER_PREFIX, DATABASE_DUMP_TIMEOUT_MS, DATABASE_APPROVAL_PREFLIGHT_TIMEOUT_MS, DATABASE_APPROVAL_PREFLIGHT_CONCURRENCY, REPO_SSH_VERIFY_TIMEOUT_MS, DATABASE_DUMP_TOOL_MISSING_ERROR_CODE, DATABASE_DUMP_CLIENT_VERSION_MISMATCH_ERROR_CODE, DATABASE_DUMP_FAILED_ERROR_CODE, MULTIPART_UPLOAD_URL_REFRESH_SKEW_MS, nowIso7, trim10, toErrorMessage, toRedactedError, normalizeAgentConfigSelection2, createAgentConfigSnapshot, normalizeAgentThreadHistorySelection, normalizeAgentThreadImportWarning, normalizeAgentThreadImportScope, createAgentThreadHistorySnapshot, assertGitSigningReadyForBundle, shellQuote5, ensureDir7, pathExists4, readJsonFile2, writeJsonFile4, writeRepoMarker, runCommand7, runCommandToFile, formatMissingDatabaseDumpToolMessage, createMissingDatabaseDumpToolError, createPostgresDumpVersionMismatchError, DATABASE_DUMP_FAILURE_USER_MESSAGES, createDatabaseDumpExecutionError, classifyDatabaseDumpFailure, executeDatabaseDumpCommand, runDatabaseDumpCommand, spawnCommand, isRepoInitArtifactPath2, readDirtyWorktreeState, readProjectDirtyWorktreeState, hasGitHead, readGitHeadInfo, copyPathIntoRoot, isPathInside, copyLocalPath2, createUserFacingEnvFileError, deriveEnvStagingId, snapshotEnvStagingFile, deleteEnvStagingFile, pruneEnvStagingFilesExcept, copyStagedEditableSetupFile, createRepoPayloadOwnership, createProjectPayloadOwnership, relativeFromStagingRoot2, resolveRepoPayloadRoot, addCopiedInventoryLeaf2, copyPathWithInventory2, copyPathWithRepoPayloadExclusions, directorySize3, createInitialScanState, createApprovals, createUploadState, setUploadProgressState, createBundleOptions, createLfsWithoutRepoSshWarning, buildLocalPrepWarnings, createForkStartupScriptSetup, createDestroyedLocalPrepSnapshot, mergeSetupPlanForRescan, SETUP_REVIEW_SECTION_SCAN_CATEGORY, reviewStatusForScanStatus, buildReviewSectionStatusesFromScanState, buildReviewState, normalizeSetupReviewRescanRequest, getSetupReviewSectionsForScanCategories, normalizeSetupReviewRetryFailedScansRequest, assertRetryableInterruptedScanCategories, DESKTOP_INIT_SCAN_FOCUS_SET, createDesktopInitRequestValidationError, isDesktopInitRequestValidationError, normalizeDesktopInitScanFocus, normalizeLocalPrepScanCategories, hasStartedOrSkippedInitialScan, resolveLockedScanFocus, isInitialScanCategoryResolved, areInitialScanCategoriesResolved, getRunnableInitialScanCategories, getSkippableInitialScanCategories, applyRescanStateToReview, markScanCategories, normalizeDirtyWorktreeForSnapshot, normalizeScanStateForSnapshot, createSnapshotFromState, createLocalPrepState, buildSkippedRepoSshSetup, getRepoSshBundleDecisionKey, parseGitRemoteHost2, acquireLocalLock, releaseLocalLock, captureShellEnvironment, safeName2, resolveSetupArtifactSource, findOwningProjectLayoutRepo, gitCommandSucceeds, isIgnoredUntrackedRepoFile, resolveEnvFileArtifactSource, isEligibleAgentEnvFileSource, buildReviewEnvFileEntry, enrichSetupPlanEnvFiles, DESKTOP_SHELL_RC_IMPORTS, resolveShellRcSourcePath, deriveShellRcStagingId, resolvesToShellRcSource, enrichSetupPlanShellRcFiles, wrapSetupArtifactCopyError, copySetupArtifacts, collectRepoScopedSetupArtifactPaths, copyGitMetadata, copyGlobalGitConfig, ensureDevboxAccessPublicKey, writeDirtyPayloads, GIT_CHECK_ATTR_PATH_CHUNK_SIZE, forEachTrackedLfsManagedPath, createLfsWorktreePayloads, createRepoPayloads, createProjectRootPayloads, createAggregateRepoPayloadState, addRepoPayloadState, buildSkippedRepoSshSetupForLayoutRepo, shouldConvertHttpsRepoOriginToSsh, buildRepoSshSetupForLayoutRepo, getPreOwnedRepoPathsForLayoutRepo, createProjectRepoPayloads, stripEnvValueQuotes, readRawEnvFileValues, resolveLocalReferencePath, parseEnvFileRef, readDatabaseEnvFileValue, createDatabaseSourceValidationError, getDatabaseValueForRole, isSupportedDatabaseUrlProtocol, parseDatabaseUrlForDump, appendEnvValue, normalizeDatabasePort, resolveDatabaseConnectionFields, resolveDatabaseDumpCommand, safeDatabaseDumpBaseName, formatDatabaseDumpFailureMessage, createPublicDatabaseDumpFailure, createDatabaseDumpFailureError, buildDatabasePreflightArgs, preflightDatabaseDumpCandidates, createDatabasePayloads, stripLocalEnvFileReviewMetadata, stripLocalExternalConfigReviewMetadata, buildRemoteSetupPlan, createInnerBundleStaging, stageRepoSshSetup, createTarGz, sha256File2, encryptBundle, buildX25519PublicKey, createKeyEnvelope, createPrivatePublicX25519Pair, MULTIPART_UPLOAD_RECOVERY_ROUND_COUNT, MULTIPART_UPLOAD_RECOVERY_BASE_DELAY_MS, REMOTE_DESTROY_POLL_INTERVAL_MS, REMOTE_DESTROY_TIMEOUT_MS, sleep5, sanitizeMultipartUploadPartsForState, createMultipartUploadState, shouldRefreshMultipartUploadUrlsBeforeUpload, normalizeRepo, normalizeOptionalProjectInstanceTypeKey, normalizeSelectedProjectRepoRelPaths, buildDesktopProjectLayoutRepo, readGitConfigValues, unsetGitConfigIfExactlyMatches, removeEmptyDirectoryIfPresent, shouldCleanupProjectLayoutClaims, cleanupProjectLayoutClaims, resolveSelectedProjectRepoRelPaths, claimDesktopProjectLayout, buildLocalScanProjectLayoutContext, normalizeSelectedAgents, normalizeBackendJobReference, getRemoteDestroyFailureMessage, waitForRemoteDestroyCompletion, normalizeApprovedEnvFile, normalizeApprovedPlan, shouldPreserveVerifiedRepoSshSetup, normalizeManagedGithubAccessRepository, normalizeManagedGithubAccess, buildManagedGithubAccessForProjectLayout, createDesktopLocalPrepService;
303589
303583
  var init_localPrepService = __esm({
303590
303584
  "../../../../shared/initPrep/src/localPrepService.mjs"() {
303591
303585
  "use strict";
@@ -303605,6 +303599,8 @@ var init_localPrepService = __esm({
303605
303599
  SNAPSHOT_VERSION = DESKTOP_INIT_CONTRACT_VERSION;
303606
303600
  X25519_SPKI_DER_PREFIX = Buffer.from("302a300506032b656e032100", "hex");
303607
303601
  DATABASE_DUMP_TIMEOUT_MS = 10 * 60 * 1e3;
303602
+ DATABASE_APPROVAL_PREFLIGHT_TIMEOUT_MS = 5 * 1e3;
303603
+ DATABASE_APPROVAL_PREFLIGHT_CONCURRENCY = 3;
303608
303604
  REPO_SSH_VERIFY_TIMEOUT_MS = 30 * 1e3;
303609
303605
  DATABASE_DUMP_TOOL_MISSING_ERROR_CODE = "desktop_database_dump_tool_missing";
303610
303606
  DATABASE_DUMP_CLIENT_VERSION_MISMATCH_ERROR_CODE = "desktop_database_dump_client_version_mismatch";
@@ -303619,7 +303615,8 @@ var init_localPrepService = __esm({
303619
303615
  reason: error55 instanceof Error && typeof error55.desktopInitErrorReason === "string" ? error55.desktopInitErrorReason : void 0,
303620
303616
  requestId: null,
303621
303617
  retryable: error55 instanceof Error && typeof error55.retryable === "boolean" ? error55.retryable : true,
303622
- userMessage: error55 instanceof Error && typeof error55.userMessage === "string" ? error55.userMessage : void 0
303618
+ userMessage: error55 instanceof Error && typeof error55.userMessage === "string" ? error55.userMessage : void 0,
303619
+ ...error55 instanceof Error && Array.isArray(error55.desktopDatabaseDumpFailures) ? { databaseDumpFailures: error55.desktopDatabaseDumpFailures } : {}
303623
303620
  });
303624
303621
  normalizeAgentConfigSelection2 = ({ agentConfig, selection }) => {
303625
303622
  const validItemIds = new Set(
@@ -303892,7 +303889,7 @@ var init_localPrepService = __esm({
303892
303889
  if (command === "pg_dump") {
303893
303890
  return [
303894
303891
  "boxes.dev could not find a usable pg_dump tool, so database copy was skipped.",
303895
- "Update or reinstall boxes.dev to restore its included PostgreSQL tools, or install PostgreSQL client tools and make sure pg_dump is on PATH, then retry bundle preparation.",
303892
+ "Update or reinstall boxes.dev to restore its included PostgreSQL tools, or install PostgreSQL client tools and make sure pg_dump is on PATH, then retry the database copy.",
303896
303893
  "On macOS: run `brew install libpq` and add `$(brew --prefix libpq)/bin` to PATH, or install Postgres.app and add `/Applications/Postgres.app/Contents/Versions/latest/bin` to PATH.",
303897
303894
  "Verify with `pg_dump --version`."
303898
303895
  ].join(" ");
@@ -303900,7 +303897,7 @@ var init_localPrepService = __esm({
303900
303897
  if (command === "mysqldump") {
303901
303898
  return [
303902
303899
  "mysqldump is not installed locally, so database copy was skipped.",
303903
- "Install MySQL or MariaDB client tools from the same database family and major or LTS release as the local server, make sure mysqldump is on PATH, then retry bundle preparation.",
303900
+ "Install MySQL or MariaDB client tools from the same database family and major or LTS release as the local server, make sure mysqldump is on PATH, then retry the database copy.",
303904
303901
  "Verify with `mysqldump --version`."
303905
303902
  ].join(" ");
303906
303903
  }
@@ -303910,7 +303907,7 @@ var init_localPrepService = __esm({
303910
303907
  const error55 = new Error(formatMissingDatabaseDumpToolMessage(command));
303911
303908
  error55.desktopInitErrorCode = DATABASE_DUMP_TOOL_MISSING_ERROR_CODE;
303912
303909
  error55.desktopInitErrorReason = command;
303913
- error55.userMessage = command === "pg_dump" ? "Update or reinstall boxes.dev to restore its included PostgreSQL tools, or install pg_dump and make sure it is available on PATH, then retry bundle preparation." : command === "mysqldump" ? "Install mysqldump from the same database family and major or LTS release as the local server, verify it with `mysqldump --version`, then retry. To proceed without local database data, change this database copy to skip." : `Install ${command}, make sure it is available on PATH, then retry bundle preparation.`;
303910
+ error55.userMessage = command === "pg_dump" ? "Update or reinstall boxes.dev to restore its included PostgreSQL tools, or install pg_dump and make sure it is available on PATH, then retry the database copy." : command === "mysqldump" ? "Install mysqldump from the same database family and major or LTS release as the local server, verify it with `mysqldump --version`, then retry the database copy. To proceed without local database data, skip this database." : `Install ${command}, make sure it is available on PATH, then retry the database copy.`;
303914
303911
  return error55;
303915
303912
  };
303916
303913
  createPostgresDumpVersionMismatchError = (stderr, { source = "system" } = {}) => {
@@ -303927,10 +303924,20 @@ var init_localPrepService = __esm({
303927
303924
  );
303928
303925
  error55.desktopInitErrorCode = DATABASE_DUMP_CLIENT_VERSION_MISMATCH_ERROR_CODE;
303929
303926
  error55.desktopInitErrorReason = "pg_dump";
303930
- error55.userMessage = source === "managed" ? "This PostgreSQL server is newer than the pg_dump included with this version of boxes.dev. Update boxes.dev or install a compatible client, then re-run `dvb agent-init check`." : "Install a pg_dump client at least as new as the PostgreSQL server, verify it with `pg_dump --version`, then re-run `dvb agent-init check`.";
303927
+ error55.userMessage = source === "managed" ? "This PostgreSQL server is newer than the pg_dump included with this version of boxes.dev. Update boxes.dev or install a compatible client, then retry the database copy." : "Install a pg_dump client at least as new as the PostgreSQL server, verify it with `pg_dump --version`, then retry the database copy.";
303931
303928
  return error55;
303932
303929
  };
303933
- createDatabaseDumpExecutionError = (toolName, { timedOut = false } = {}) => {
303930
+ DATABASE_DUMP_FAILURE_USER_MESSAGES = {
303931
+ authentication_failed: "The database rejected the selected credentials. Check the project\u2019s database settings, then retry.",
303932
+ connection_refused: "Nothing accepted the connection at the selected host and port. Start the database or update the connection, then retry.",
303933
+ database_missing: "The selected database does not exist. Update the database name, then retry.",
303934
+ host_unresolved: "This computer cannot resolve the selected database host. Use a host-reachable endpoint, then retry.",
303935
+ password_missing: "The connection needs a password, but the selected credential reference did not provide one. Update the database settings, then retry.",
303936
+ permission_denied: "The selected database user cannot read the database catalog. Grant dump access or use a different database user, then retry.",
303937
+ source_url_missing: "The selected database URL wasn\u2019t available from the project environment or an env file. Update the connection or skip this database.",
303938
+ timeout: "The database did not respond in time. Start it or make the selected endpoint reachable, then retry."
303939
+ };
303940
+ createDatabaseDumpExecutionError = (toolName, { failureKind = "unknown", timedOut = false } = {}) => {
303934
303941
  const summary = timedOut ? `${toolName} timed out while creating a database dump.` : `${toolName} failed while creating a database dump.`;
303935
303942
  const error55 = new Error(
303936
303943
  toolName === "mysqldump" ? [
@@ -303941,9 +303948,65 @@ var init_localPrepService = __esm({
303941
303948
  );
303942
303949
  error55.desktopInitErrorCode = DATABASE_DUMP_FAILED_ERROR_CODE;
303943
303950
  error55.desktopInitErrorReason = toolName;
303944
- error55.userMessage = toolName === "mysqldump" ? "Confirm the local MySQL or MariaDB server and credentials work. If needed, install mysqldump from the same database family and major or LTS release as the server, verify it with `mysqldump --version`, then re-run `dvb agent-init check`. To proceed without local database data, change this database copy to skip." : `Fix the ${toolName} failure, then retry. To proceed without local database data, change this database copy to skip.`;
303951
+ const effectiveFailureKind = timedOut ? "timeout" : failureKind;
303952
+ error55.desktopDatabaseFailureKind = effectiveFailureKind;
303953
+ error55.userMessage = DATABASE_DUMP_FAILURE_USER_MESSAGES[effectiveFailureKind] ?? (toolName === "mysqldump" ? "Confirm the local MySQL or MariaDB server and credentials work. If needed, install mysqldump from the same database family and major or LTS release as the server, verify it with `mysqldump --version`, then retry the database copy or skip this database." : `Fix the ${toolName} failure, then retry the database copy or skip this database.`);
303945
303954
  return error55;
303946
303955
  };
303956
+ classifyDatabaseDumpFailure = ({ stderr, toolName }) => {
303957
+ const normalized = trim10(stderr);
303958
+ if (!normalized) {
303959
+ return "unknown";
303960
+ }
303961
+ if (toolName === "pg_dump") {
303962
+ if (/could not translate host name/iu.test(normalized)) {
303963
+ return "host_unresolved";
303964
+ }
303965
+ if (/connection to server[\s\S]*failed:[\s\S]*Connection refused/iu.test(
303966
+ normalized
303967
+ )) {
303968
+ return "connection_refused";
303969
+ }
303970
+ if (/password authentication failed for user/iu.test(normalized)) {
303971
+ return "authentication_failed";
303972
+ }
303973
+ if (/(?:fe_sendauth: )?no password supplied/iu.test(normalized)) {
303974
+ return "password_missing";
303975
+ }
303976
+ if (/database [\s\S]+ does not exist/iu.test(normalized)) {
303977
+ return "database_missing";
303978
+ }
303979
+ if (/permission denied/iu.test(normalized)) {
303980
+ return "permission_denied";
303981
+ }
303982
+ return "unknown";
303983
+ }
303984
+ if (toolName === "mysqldump") {
303985
+ if (/Unknown MySQL server host|Name or service not known|nodename nor servname provided/iu.test(
303986
+ normalized
303987
+ )) {
303988
+ return "host_unresolved";
303989
+ }
303990
+ if (/Can(?:not|'t) connect to (?:local )?MySQL server|Connection refused/iu.test(
303991
+ normalized
303992
+ )) {
303993
+ return "connection_refused";
303994
+ }
303995
+ if (/Access denied for user[\s\S]*using password: NO/iu.test(normalized)) {
303996
+ return "password_missing";
303997
+ }
303998
+ if (/Access denied for user/iu.test(normalized)) {
303999
+ return "authentication_failed";
304000
+ }
304001
+ if (/Unknown database/iu.test(normalized)) {
304002
+ return "database_missing";
304003
+ }
304004
+ if (/command denied to user|permission denied/iu.test(normalized)) {
304005
+ return "permission_denied";
304006
+ }
304007
+ }
304008
+ return "unknown";
304009
+ };
303947
304010
  executeDatabaseDumpCommand = (command, args, {
303948
304011
  cwd: cwd2,
303949
304012
  env: env3,
@@ -303977,9 +304040,10 @@ var init_localPrepService = __esm({
303977
304040
  );
303978
304041
  return;
303979
304042
  }
304043
+ const stderrText = Buffer.isBuffer(stderr) ? stderr.toString("utf8") : "";
303980
304044
  if (toolName === "pg_dump") {
303981
304045
  const versionMismatch = createPostgresDumpVersionMismatchError(
303982
- Buffer.isBuffer(stderr) ? stderr.toString("utf8") : "",
304046
+ stderrText,
303983
304047
  { source }
303984
304048
  );
303985
304049
  if (versionMismatch) {
@@ -303987,7 +304051,14 @@ var init_localPrepService = __esm({
303987
304051
  return;
303988
304052
  }
303989
304053
  }
303990
- reject(createDatabaseDumpExecutionError(toolName));
304054
+ reject(
304055
+ createDatabaseDumpExecutionError(toolName, {
304056
+ failureKind: classifyDatabaseDumpFailure({
304057
+ stderr: stderrText,
304058
+ toolName
304059
+ })
304060
+ })
304061
+ );
303991
304062
  }
303992
304063
  );
303993
304064
  });
@@ -306536,6 +306607,16 @@ var init_localPrepService = __esm({
306536
306607
  }
306537
306608
  return null;
306538
306609
  };
306610
+ createDatabaseSourceValidationError = ({
306611
+ failureKind,
306612
+ message,
306613
+ userMessage
306614
+ }) => {
306615
+ const error55 = new Error(message);
306616
+ error55.desktopDatabaseFailureKind = failureKind;
306617
+ error55.userMessage = userMessage;
306618
+ return error55;
306619
+ };
306539
306620
  getDatabaseValueForRole = async ({
306540
306621
  databaseEnv,
306541
306622
  homeDir: homeDir2,
@@ -306643,7 +306724,11 @@ var init_localPrepService = __esm({
306643
306724
  role: "url"
306644
306725
  });
306645
306726
  if (!rawUrl) {
306646
- throw new Error("Missing database URL value.");
306727
+ throw createDatabaseSourceValidationError({
306728
+ failureKind: "source_url_missing",
306729
+ message: "Missing database URL value.",
306730
+ userMessage: DATABASE_DUMP_FAILURE_USER_MESSAGES.source_url_missing
306731
+ });
306647
306732
  }
306648
306733
  return parseDatabaseUrlForDump({ expectedEngine, rawUrl });
306649
306734
  }
@@ -306720,7 +306805,7 @@ var init_localPrepService = __esm({
306720
306805
  homeDir: homeDir2,
306721
306806
  repoRoot
306722
306807
  });
306723
- const envForDump2 = { ...databaseEnv };
306808
+ const envForDump2 = { ...databaseEnv, LC_ALL: "C" };
306724
306809
  appendEnvValue(envForDump2, "PGHOST", parsed2.host);
306725
306810
  appendEnvValue(envForDump2, "PGPORT", normalizeDatabasePort(parsed2.port));
306726
306811
  appendEnvValue(envForDump2, "PGDATABASE", parsed2.database);
@@ -306772,7 +306857,7 @@ var init_localPrepService = __esm({
306772
306857
  args.push(`--ssl-mode=${parsed.sslMode}`);
306773
306858
  }
306774
306859
  args.push(parsed.database);
306775
- const envForDump = { ...databaseEnv };
306860
+ const envForDump = { ...databaseEnv, LC_ALL: "C" };
306776
306861
  appendEnvValue(envForDump, "MYSQL_PWD", parsed.password);
306777
306862
  return {
306778
306863
  command: "mysqldump",
@@ -306788,8 +306873,19 @@ var init_localPrepService = __esm({
306788
306873
  }).join("; ");
306789
306874
  return `Database dump creation failed for ${failures.length === 1 ? "an approved database" : "approved databases"}: ${details}`;
306790
306875
  };
306876
+ createPublicDatabaseDumpFailure = ({ candidate, error: error55 }) => ({
306877
+ candidateId: typeof candidate?.id === "string" && candidate.id.trim() ? candidate.id : null,
306878
+ label: typeof candidate?.displayLabel === "string" && candidate.displayLabel.trim() ? candidate.displayLabel : candidate?.id ?? "database",
306879
+ engine: candidate?.engine === "postgres" || candidate?.engine === "mysql" ? candidate.engine : null,
306880
+ code: error55 instanceof Error && typeof error55.desktopInitErrorCode === "string" ? error55.desktopInitErrorCode : null,
306881
+ failureKind: error55 instanceof Error && typeof error55.desktopDatabaseFailureKind === "string" ? error55.desktopDatabaseFailureKind : null,
306882
+ userMessage: error55 instanceof Error && typeof error55.userMessage === "string" ? error55.userMessage : "Setup could not copy this database. Check that it is running and that the selected connection works, then retry."
306883
+ });
306791
306884
  createDatabaseDumpFailureError = (failures) => {
306792
306885
  const error55 = new Error(formatDatabaseDumpFailureMessage(failures));
306886
+ error55.desktopDatabaseDumpFailures = failures.map(
306887
+ createPublicDatabaseDumpFailure
306888
+ );
306793
306889
  if (failures.length === 1) {
306794
306890
  const failureError = failures[0].error;
306795
306891
  if (failureError instanceof Error && typeof failureError.desktopInitErrorCode === "string") {
@@ -306809,7 +306905,7 @@ var init_localPrepService = __esm({
306809
306905
  ];
306810
306906
  error55.desktopInitErrorCode = DATABASE_DUMP_TOOL_MISSING_ERROR_CODE;
306811
306907
  error55.desktopInitErrorReason = missingCommands.length === 1 ? missingCommands[0] : "multiple";
306812
- error55.userMessage = missingCommands.length === 1 ? createMissingDatabaseDumpToolError(missingCommands[0]).userMessage : "Install the missing database dump tools, make sure they are available on PATH, then retry bundle preparation.";
306908
+ error55.userMessage = missingCommands.length === 1 ? createMissingDatabaseDumpToolError(missingCommands[0]).userMessage : "Install the missing database dump tools, make sure they are available on PATH, then retry the database copy.";
306813
306909
  return error55;
306814
306910
  }
306815
306911
  const executionErrors = failures.map((failure) => failure.error).filter(
@@ -306827,53 +306923,100 @@ var init_localPrepService = __esm({
306827
306923
  }
306828
306924
  return error55;
306829
306925
  };
306926
+ buildDatabasePreflightArgs = ({ command, validationMode }) => {
306927
+ if (validationMode !== "connection") {
306928
+ return command.command === "pg_dump" ? ["--schema-only", ...command.args] : ["--no-data", ...command.args];
306929
+ }
306930
+ if (command.command === "pg_dump") {
306931
+ return ["--schema-only", "--exclude-schema=*", ...command.args];
306932
+ }
306933
+ const connectionArgs = [];
306934
+ for (let index = 0; index < command.args.length; index += 1) {
306935
+ const arg2 = command.args[index];
306936
+ if (arg2 === "--single-transaction" || arg2 === "--routines" || arg2 === "--events" || arg2 === "--triggers" || arg2 === "--skip-comments") {
306937
+ continue;
306938
+ }
306939
+ if (arg2 === "--result-file") {
306940
+ index += 1;
306941
+ continue;
306942
+ }
306943
+ if (arg2.startsWith("--result-file=")) {
306944
+ continue;
306945
+ }
306946
+ connectionArgs.push(arg2);
306947
+ }
306948
+ return [
306949
+ "--no-data",
306950
+ "--no-create-info",
306951
+ "--skip-lock-tables",
306952
+ ...connectionArgs
306953
+ ];
306954
+ };
306830
306955
  preflightDatabaseDumpCandidates = async ({
306831
306956
  candidates,
306832
306957
  databaseDumpToolResolver = null,
306833
306958
  databaseEnv,
306834
306959
  homeDir: homeDir2,
306835
- repoRoot
306960
+ repoRoot,
306961
+ validationMode = "schema"
306836
306962
  }) => {
306837
306963
  const tempRoot = await fs41.mkdtemp(
306838
306964
  path51.join(os25.tmpdir(), "boxes-database-preflight-")
306839
306965
  );
306840
- const failures = [];
306966
+ const selectedCandidates = candidates.filter(
306967
+ (candidate) => candidate?.canAutomate === true
306968
+ );
306969
+ const failuresByIndex = new Array(selectedCandidates.length).fill(null);
306970
+ let nextCandidateIndex = 0;
306841
306971
  try {
306842
- for (const candidate of candidates) {
306843
- if (candidate?.canAutomate !== true) {
306844
- continue;
306845
- }
306846
- try {
306847
- const outputPath = path51.join(
306848
- tempRoot,
306849
- `${safeDatabaseDumpBaseName(candidate)}.${candidate.engine === "postgres" ? "dump" : "sql"}`
306850
- );
306851
- const command = await resolveDatabaseDumpCommand({
306852
- candidate,
306853
- databaseEnv,
306854
- homeDir: homeDir2,
306855
- outputPath,
306856
- repoRoot
306857
- });
306858
- const preflightArgs = command.command === "pg_dump" ? ["--schema-only", ...command.args] : ["--no-data", ...command.args];
306859
- await runDatabaseDumpCommand(command.command, preflightArgs, {
306860
- cwd: repoRoot,
306861
- databaseDumpToolResolver,
306862
- env: command.env
306863
- });
306864
- } catch (error55) {
306865
- failures.push({
306866
- candidateId: candidate.id ?? null,
306867
- label: candidate.displayLabel ?? candidate.id ?? "database",
306868
- message: toErrorMessage(error55),
306869
- code: error55 instanceof Error && typeof error55.desktopInitErrorCode === "string" ? error55.desktopInitErrorCode : null,
306870
- userMessage: error55 instanceof Error && typeof error55.userMessage === "string" ? error55.userMessage : null
306871
- });
306972
+ const worker = async () => {
306973
+ while (nextCandidateIndex < selectedCandidates.length) {
306974
+ const candidateIndex = nextCandidateIndex;
306975
+ nextCandidateIndex += 1;
306976
+ const candidate = selectedCandidates[candidateIndex];
306977
+ try {
306978
+ const outputPath = path51.join(
306979
+ tempRoot,
306980
+ `${candidateIndex}-${safeDatabaseDumpBaseName(candidate)}.${candidate.engine === "postgres" ? "dump" : "sql"}`
306981
+ );
306982
+ const command = await resolveDatabaseDumpCommand({
306983
+ candidate,
306984
+ databaseEnv,
306985
+ homeDir: homeDir2,
306986
+ outputPath,
306987
+ repoRoot
306988
+ });
306989
+ await runDatabaseDumpCommand(
306990
+ command.command,
306991
+ buildDatabasePreflightArgs({ command, validationMode }),
306992
+ {
306993
+ cwd: repoRoot,
306994
+ databaseDumpToolResolver,
306995
+ env: command.env,
306996
+ timeoutMs: validationMode === "connection" ? DATABASE_APPROVAL_PREFLIGHT_TIMEOUT_MS : DATABASE_DUMP_TIMEOUT_MS
306997
+ }
306998
+ );
306999
+ } catch (error55) {
307000
+ failuresByIndex[candidateIndex] = {
307001
+ ...createPublicDatabaseDumpFailure({ candidate, error: error55 }),
307002
+ message: toErrorMessage(error55)
307003
+ };
307004
+ }
306872
307005
  }
306873
- }
307006
+ };
307007
+ const concurrency = validationMode === "connection" ? DATABASE_APPROVAL_PREFLIGHT_CONCURRENCY : 1;
307008
+ await Promise.all(
307009
+ Array.from(
307010
+ {
307011
+ length: Math.min(concurrency, selectedCandidates.length)
307012
+ },
307013
+ () => worker()
307014
+ )
307015
+ );
306874
307016
  } finally {
306875
307017
  await fs41.rm(tempRoot, { recursive: true, force: true });
306876
307018
  }
307019
+ const failures = failuresByIndex.filter(Boolean);
306877
307020
  return { ok: failures.length === 0, failures };
306878
307021
  };
306879
307022
  createDatabasePayloads = async ({
@@ -311125,7 +311268,8 @@ var init_localPrepService = __esm({
311125
311268
  databaseDumpToolResolver,
311126
311269
  databaseEnv: capturedEnv.env,
311127
311270
  homeDir: homeDir2,
311128
- repoRoot: repo.repoRoot
311271
+ repoRoot: repo.repoRoot,
311272
+ validationMode: request2.databaseValidationMode === "connection" ? "connection" : "schema"
311129
311273
  });
311130
311274
  }),
311131
311275
  async getSnapshot(request2) {
@@ -328250,7 +328394,7 @@ var init_plan = __esm({
328250
328394
  };
328251
328395
  isDatabaseCopyCandidate2 = (value) => {
328252
328396
  if (!isObject10(value)) return false;
328253
- if (typeof value.id !== "string" || typeof value.engine !== "string" || typeof value.displayLabel !== "string" || typeof value.canAutomate !== "boolean" || typeof value.confidence !== "string" || !Array.isArray(value.evidence)) {
328397
+ if (typeof value.id !== "string" || value.id.trim().length === 0 || typeof value.engine !== "string" || typeof value.displayLabel !== "string" || typeof value.canAutomate !== "boolean" || typeof value.confidence !== "string" || !Array.isArray(value.evidence)) {
328254
328398
  return false;
328255
328399
  }
328256
328400
  const source = value.source;
@@ -328286,7 +328430,8 @@ var init_plan = __esm({
328286
328430
  };
328287
328431
  isSetupDatabasesPlan = (value) => {
328288
328432
  if (!isObject10(value)) return false;
328289
- return typeof value.schemaVersion === "number" && typeof value.scanFullyCompleted === "boolean" && Array.isArray(value.databaseCandidates) && value.databaseCandidates.every(isDatabaseCopyCandidate2);
328433
+ const databaseCandidates = Array.isArray(value.databaseCandidates) ? value.databaseCandidates : null;
328434
+ return typeof value.schemaVersion === "number" && typeof value.scanFullyCompleted === "boolean" && databaseCandidates !== null && databaseCandidates.every(isDatabaseCopyCandidate2) && new Set(databaseCandidates.map((candidate) => candidate.id)).size === databaseCandidates.length;
328290
328435
  };
328291
328436
  isServicesPlan = (value) => {
328292
328437
  if (!isObject10(value)) return false;
@@ -357364,4 +357509,4 @@ react/cjs/react-jsx-runtime.development.js:
357364
357509
  *)
357365
357510
  */
357366
357511
 
357367
- //# debugId=8cb3e81f-1a45-5309-aca4-748b6f610d13
357512
+ //# debugId=622a15c0-7c29-5be9-a35c-b1a193a6b0f0
package/dist/bin/dvbd.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
 
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]="9693a639-b909-5aca-a5d7-5c8663346d95")}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]="273915e4-19f9-5515-bec4-e13639bb51de")}catch(e){}}();
4
4
  import { createRequire as __dvbCreateRequire } from "node:module";
5
5
  import { dirname as __dvbDirname } from "node:path";
6
6
  import { fileURLToPath as __dvbFileURLToPath } from "node:url";
@@ -96328,8 +96328,8 @@ var init_otel = __esm({
96328
96328
  return trimmed && trimmed.length > 0 ? trimmed : void 0;
96329
96329
  };
96330
96330
  readBuildMetadata = () => {
96331
- const rawPackageVersion = "1.0.958";
96332
- const rawGitSha = "1436ae0e44cbd7325937bad75a389dc22a69ba80";
96331
+ const rawPackageVersion = "1.0.959";
96332
+ const rawGitSha = "c5992d38486ffdbc188773dfe7556175ffb24abc";
96333
96333
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
96334
96334
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
96335
96335
  return { packageVersion, gitSha };
@@ -128624,9 +128624,9 @@ var init_sentry = __esm({
128624
128624
  uncaughtExceptionMonitorInstalled = false;
128625
128625
  currentDevboxSentryUser = null;
128626
128626
  readBuildMetadata2 = () => {
128627
- const rawPackageVersion = "1.0.958";
128628
- const rawGitSha = "1436ae0e44cbd7325937bad75a389dc22a69ba80";
128629
- const rawSentryRelease = "boxes-dev-dvb@1.0.958+1436ae0e44cbd7325937bad75a389dc22a69ba80";
128627
+ const rawPackageVersion = "1.0.959";
128628
+ const rawGitSha = "c5992d38486ffdbc188773dfe7556175ffb24abc";
128629
+ const rawSentryRelease = "boxes-dev-dvb@1.0.959+c5992d38486ffdbc188773dfe7556175ffb24abc";
128630
128630
  const packageVersion = typeof rawPackageVersion === "string" ? rawPackageVersion : void 0;
128631
128631
  const gitSha = typeof rawGitSha === "string" ? rawGitSha : void 0;
128632
128632
  const sentryRelease = typeof rawSentryRelease === "string" ? rawSentryRelease : void 0;
@@ -130818,7 +130818,7 @@ var init_packageVersion = __esm({
130818
130818
  return path8.join(process.cwd(), "dvb");
130819
130819
  };
130820
130820
  readEmbeddedPackageVersion = () => {
130821
- const raw = "1.0.958";
130821
+ const raw = "1.0.959";
130822
130822
  return trimVersion(raw);
130823
130823
  };
130824
130824
  readNearestPackageMetadata = (basePath) => {
@@ -144013,4 +144013,4 @@ long/umd/index.js:
144013
144013
  *)
144014
144014
  */
144015
144015
 
144016
- //# debugId=9693a639-b909-5aca-a5d7-5c8663346d95
144016
+ //# debugId=273915e4-19f9-5515-bec4-e13639bb51de
@@ -199,9 +199,6 @@ another thread:
199
199
  a time. Moving it between the desktop app and the terminal asks first; the
200
200
  desktop app can continue showing progress, interrupt the terminal turn, or
201
201
  take control again.
202
- - A Claude Code CLI thread reuses its existing persistent terminal. Moving it
203
- to another surface disconnects the prior terminal view without restarting
204
- Claude.
205
202
 
206
203
  In Codex, press `Ctrl+D` with an empty composer to return to the switchboard
207
204
  without interrupting a running turn. Press `Esc` to interrupt the current turn
@@ -229,9 +226,7 @@ complete key guide.
229
226
  Press Space on a Codex or Claude row to preview recent saved messages without
230
227
  waking its machine, attaching to its terminal, or moving input ownership. The
231
228
  preview clears unread only after the exact ready content is rendered. Loading,
232
- unavailable, and stale content do not clear it. Claude Code CLI preview is
233
- deferred; Space explains that it is unavailable and Enter still reattaches the
234
- persistent terminal normally.
229
+ unavailable, and stale content do not clear it.
235
230
 
236
231
  Use `p` to pin or unpin an eligible Template-box thread or devbox anchor, `r`
237
232
  to rename a thread, and `x` to archive or restore it. On an archived
@@ -265,8 +260,8 @@ draft or keep a non-blank draft; while waiting for `Ctrl+O`, `Esc` cancels only
265
260
  the automatic open and leaves the agent running.
266
261
 
267
262
  CLI-created Claude threads use a persistent Claude terminal but remain ordinary
268
- Claude threads in the desktop app. They do not become separate Claude Code CLI
269
- threads. The desktop app can observe their progress and use the usual
263
+ Claude threads in the desktop app. They do not use a separate conversation
264
+ type. The desktop app can observe their progress and use the usual
270
265
  interrupt-and-transfer flow when control needs to move between surfaces. They
271
266
  use the same autonomous permission mode as Claude threads started from the
272
267
  desktop app.
@@ -405,10 +405,11 @@ dvb-onbox threads read \
405
405
  --json
406
406
  ```
407
407
 
408
- This returns the durable boxes.dev transcript projection, thread status, and
409
- older-page cursor. It can briefly lag the live runtime. Pending Codex and Claude
410
- queue entries remain runtime state and do not appear as transcript messages
411
- until the provider accepts them as turns.
408
+ This returns a bounded preview of the durable boxes.dev transcript, thread
409
+ status, and older-page cursor. Long messages are marked as shortened. It can
410
+ briefly lag the live runtime. Pending Codex and Claude queue entries remain
411
+ runtime state and do not appear as transcript messages until the provider
412
+ accepts them as turns.
412
413
 
413
414
  List and observe that same source-scoped child pool without waking a child
414
415
  devbox:
@@ -416,6 +417,10 @@ devbox:
416
417
  ```bash
417
418
  dvb-onbox threads list [--include-archived] [--cursor <cursor> | --all] --json
418
419
 
420
+ dvb-onbox threads result <delegated-thread-id> \
421
+ --turn <turn-id> \
422
+ --json
423
+
419
424
  dvb-onbox threads wait <delegated-thread-id> \
420
425
  [--turn <turn-id>] \
421
426
  [--timeout <duration>] \
@@ -428,15 +433,19 @@ dvb-onbox threads events <delegated-thread-id> \
428
433
 
429
434
  `threads list` uses the current source box's project automatically and never
430
435
  shows other project threads, including children created by a different source
431
- box. `threads wait` snapshots the current active turn once when `--turn` is
432
- omitted; Ctrl+C stops only the local wait. `threads events` emits durable
433
- lifecycle events with an opaque resume cursor on every JSONL row. With no turn,
434
- cursor, or `--from-start`, it follows only events created after the command
435
- starts. An exact-turn stream ends after needs-input or a terminal event.
436
-
437
- Read, list, wait, and events operate on durable control-service state, so they
438
- can inspect archived, cold, and history-only children without waking their
439
- devboxes or claiming a live input surface. The source box's live **Create
436
+ box. `threads result` returns the complete stored final response for one exact
437
+ terminal turn and automatically assembles its transport pages. Use it instead
438
+ of asking the child to summarize a shortened `threads read` preview. When
439
+ `threads wait` omits `--turn`, it snapshots the current active turn once. A
440
+ completed wait includes that same complete response as `output.text`; Ctrl+C
441
+ stops only the local wait. `threads events` emits durable lifecycle events with
442
+ an opaque resume cursor on every JSONL row. With no turn, cursor, or
443
+ `--from-start`, it follows only events created after the command starts. An
444
+ exact-turn stream ends after needs-input or a terminal event.
445
+
446
+ Read, result, list, wait, and events operate on durable control-service state,
447
+ so they can inspect archived, cold, and history-only children without waking
448
+ their devboxes or claiming a live input surface. The source box's live **Create
440
449
  devboxes and threads** permission is checked on every observation and control.
441
450
  Prompt files are limited to 32 KiB.
442
451
 
@@ -395,6 +395,14 @@ The review page also has an optional freeform note for anything the setup coding
395
395
  agent should know; that note is included in the approved setup plan for the
396
396
  Template box setup thread.
397
397
 
398
+ When the user approves **Local database dumps**, desktop setup briefly checks
399
+ each selected PostgreSQL or MySQL/MariaDB connection without copying database
400
+ contents. If a database is stopped, missing, unreachable, or rejects the
401
+ selected credentials, that row stays unapproved and explains what went wrong.
402
+ The user can retry after starting the database, skip that database, or ask the
403
+ scan agent once to correct its connection finding. Agent repair receives only
404
+ credential-free connection diagnostics.
405
+
398
406
  When the scan finds an environment file, boxes.dev snapshots a copy of it at
399
407
  scan time and sends that copy to the Template box. Users can open any env file
400
408
  in an in-app editor and change exactly what gets sent (for example, removing a
@@ -448,12 +456,14 @@ copies. Setup continues to prefer a usable `pg_dump` already on `PATH`, then
448
456
  uses the included client when the host command is missing or is older than the
449
457
  source server. If the included payload is unavailable, or the Postgres server
450
458
  is newer than the included client, setup explains how to update or reinstall
451
- boxes.dev or use a compatible host client. The user can also continue without
452
- the database dump if the database copy is not essential. MySQL copies still
453
- require `mysqldump` on `PATH`. If a MySQL dump fails, setup explains how to use
454
- a client from the same MySQL or MariaDB family and major or LTS release as the
455
- local server. The user can retry after fixing the connection or client, or
456
- continue immediately without importing the local database data.
459
+ boxes.dev or use a compatible host client. The user can also skip that database
460
+ if its local data is not essential. MySQL copies still require `mysqldump` on
461
+ `PATH`. If a MySQL dump fails, setup explains how to use a client from the same
462
+ MySQL or MariaDB family and major or LTS release as the local server. The user
463
+ can retry after fixing the connection or client, or skip the failed database
464
+ and continue. When several database copies were selected, skipping removes only
465
+ the copies that failed; successful selections remain in the setup bundle. Every
466
+ full-dump failure is shown before upload rather than silently omitting its data.
457
467
 
458
468
  The bundle screen also shows size information and warns if the bundle is too
459
469
  large.
@@ -611,6 +621,15 @@ summary before it requests completion.
611
621
 
612
622
  Setup state is persisted so interrupted setup can usually be resumed.
613
623
 
624
+ Interrupted desktop setups appear under **Setups in progress** in two places:
625
+ below the setup options on the wizard's Project step, and in their own section
626
+ of the titlebar project selector. Choosing an entry in either place will
627
+ reopen setup at the step where it left off. The wizard row also offers
628
+ **Continue setup** and a delete button; deleting removes only the incomplete
629
+ setup state, and the local folder and its files won't be affected. A setup
630
+ waiting on a recoverable error shows **Needs attention** in the project
631
+ selector.
632
+
614
633
  Common recovery paths:
615
634
 
616
635
  - Existing completed project: open the existing project.
@@ -86,8 +86,7 @@ it cannot retry safely instead of risking a duplicate prompt.
86
86
  Space shows a compact read-only preview of recent saved Codex or Claude
87
87
  messages. Preview does not wake the machine, connect to the agent, or move
88
88
  Claude input ownership. Unread clears only after the exact ready attention
89
- event renders. Claude Code CLI preview is deferred, but Enter can still
90
- reattach its persistent terminal.
89
+ event renders.
91
90
 
92
91
  The switchboard can pin or unpin eligible Template-box threads and devbox
93
92
  anchors with `p`, rename with `r`, and archive or restore with `x`. Restoring a
@@ -271,8 +270,7 @@ For eligible new Codex and Claude Code devbox drafts, typing can begin preparing
271
270
  the devbox and agent in the background. If the first prompt is sent before that
272
271
  preparation finishes, the startup area shows `Preparing devbox` while the same
273
272
  work completes. If the devbox and agent are already prepared, the prompt
274
- proceeds directly without that wait. This does not apply to Claude Code CLI
275
- threads.
273
+ proceeds directly without that wait.
276
274
 
277
275
  On mobile, you can return to the thread list immediately after tapping Send.
278
276
  boxes.dev keeps the first prompt and its attachments while devbox and agent
@@ -418,31 +416,31 @@ catalog install and lets the turn proceed; Not now declines it. Plugin requests
418
416
  use the scope-aware actions described under **Plugins**. Pending requests
419
417
  remain visible after returning to or reloading the thread until resolved.
420
418
 
421
- ## Claude Code Controls
419
+ ## Claude Controls
422
420
 
423
- Claude Code threads expose model and reasoning controls when available. Claude
424
- Code also supports slash commands when the thread surface has command lookup
421
+ Claude threads expose model and reasoning controls when available. Claude also
422
+ supports slash commands when the thread surface has command lookup
425
423
  enabled. On desktop, `/model` opens the model picker, and `/model <model>`
426
424
  switches directly to a known model. Older supported model generations appear
427
425
  under **More models** in the picker.
428
426
 
429
- An idle Claude Code chat can continue in a separate chat on the same Template
427
+ An idle Claude chat can continue in a separate chat on the same Template
430
428
  box or devbox. Use exact `/fork` to continue from the current tip, or use the
431
429
  Split icon beneath a completed desktop response to keep history only through
432
430
  that response. Its tooltip reads **Continue in new chat**. Mobile exposes only
433
431
  exact `/fork`. The new chat shares the same files and working directory; this
434
432
  does not create or rewind a devbox, worktree, or snapshot. The original chat is
435
433
  unchanged, and both chats can continue independently. These controls appear
436
- only for managed Claude Code chats whose connected runtime supports chat
437
- forking; Claude Code CLI threads do not expose them.
434
+ only for managed Claude chats whose connected runtime supports chat
435
+ forking.
438
436
 
439
- Model and reasoning selections belong to the Claude Code thread. A new
437
+ Model and reasoning selections belong to the Claude thread. A new
440
438
  selection remains associated with that thread while it is applied, and the
441
439
  confirmed settings follow the thread when it is reopened or resumed on desktop
442
440
  or mobile. Changing one thread does not change another existing thread; the
443
441
  last-used selection can still become the starting default for a new thread.
444
442
 
445
- On a connected managed Claude Code thread, the desktop and mobile composers
443
+ On a connected managed Claude thread, the desktop and mobile composers
446
444
  also offer these modes when the runtime supports switching them:
447
445
 
448
446
  - **Full-access** is the standard boxes.dev mode and the default for every new
@@ -462,7 +460,7 @@ choice, so leaving Plan restores the prior mode. While a mode change is being
462
460
  confirmed, the selector and Send action stay disabled so a prompt cannot run
463
461
  under the previous mode.
464
462
 
465
- Claude Code can switch a Fable thread to Opus when Fable's safeguards decline
463
+ Claude can switch a Fable thread to Opus when Fable's safeguards decline
466
464
  part of the conversation and Claude retries it with a fallback model. The
467
465
  transcript shows a **Switched to Opus 4.8** notice with a link to Anthropic's
468
466
  explanation, and the model picker then shows Opus 4.8 as the thread's current
@@ -658,7 +656,7 @@ conversation, status, commands, tool output, diffs, attachments, and images, so
658
656
  review the conversation for source, credentials, or other sensitive content
659
657
  before sharing it. GUI and Terminal views share the same ordinary conversation,
660
658
  so the selected view does not change sharing eligibility. Drafts, setup threads,
661
- and legacy Claude CLI threads cannot be shared.
659
+ and conversations that have not started cannot be shared.
662
660
 
663
661
  Under **All threads**, sharing a thread that is not private takes one click:
664
662
  boxes.dev creates the link and copies it without asking for confirmation,
@@ -91,7 +91,7 @@ then retry setup.
91
91
 
92
92
  ## Agent Auth Problems
93
93
 
94
- If a Codex or Claude Code thread cannot start or continue because auth is
94
+ If a Codex or Claude thread cannot start or continue because auth is
95
95
  missing or expired, open **Configure agents** from the desktop app and reconnect
96
96
  the affected agent.
97
97
 
@@ -111,7 +111,7 @@ is shared through boxes.dev, so the same auth can be applied to all of your
111
111
  Template boxes and devboxes. To repair Codex auth from a terminal, run
112
112
  `dvb setup --agents` on your laptop.
113
113
 
114
- Codex can be connected through ChatGPT login or an API key. Claude Code can be
114
+ Codex can be connected through ChatGPT login or an API key. Claude can be
115
115
  connected through Claude login or an API key. After reconnecting, retry the
116
116
  thread or start a new one.
117
117
 
@@ -73,7 +73,7 @@ Return JSON with this shape:
73
73
 
74
74
  Each `databaseCandidates` entry must include:
75
75
 
76
- - `id`: stable short slug
76
+ - `id`: non-empty stable short slug, unique within `databaseCandidates`
77
77
  - `engine`: `postgres` or `mysql`
78
78
  - `displayLabel`: concise user-facing label for approval UI
79
79
  - `source`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boxes-dev/dvb-runtime",
3
- "version": "1.0.958",
3
+ "version": "1.0.959",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "imports": {
@@ -77,5 +77,5 @@
77
77
  "e2b": "^2.18.0",
78
78
  "ink-testing-library": "^4.0.0"
79
79
  },
80
- "devboxReleasedAt": "2026-08-26T22:43:53Z"
80
+ "devboxReleasedAt": "2026-08-27T22:42:48Z"
81
81
  }