@carllee1983/dbcli 1.45.1 → 1.46.0

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/cli.mjs CHANGED
@@ -52,7 +52,7 @@ var package_default;
52
52
  var init_package = __esm(() => {
53
53
  package_default = {
54
54
  name: "@carllee1983/dbcli",
55
- version: "1.45.1",
55
+ version: "1.46.0",
56
56
  description: "Database CLI for AI agents",
57
57
  type: "module",
58
58
  publishConfig: {
@@ -7463,7 +7463,11 @@ var init_validation = __esm(() => {
7463
7463
  port: OptNumberOrEnvRef,
7464
7464
  user: OptStringOrEnvRef,
7465
7465
  password: OptStringOrEnvRef,
7466
- database: OptStringOrEnvRef
7466
+ database: OptStringOrEnvRef,
7467
+ authSource: exports_external.union([exports_external.string(), EnvRefSchema]).optional(),
7468
+ replicaSet: exports_external.union([exports_external.string(), EnvRefSchema]).optional(),
7469
+ tls: exports_external.boolean().optional(),
7470
+ srv: exports_external.boolean().optional().default(false)
7467
7471
  });
7468
7472
  SqlConnectionConfigSchema = exports_external.object({
7469
7473
  system: exports_external.enum(["postgresql", "mysql", "mariadb"]),
@@ -24355,12 +24359,40 @@ class MongoDBAdapter {
24355
24359
  buildUri() {
24356
24360
  if (this.options.uri)
24357
24361
  return this.options.uri;
24358
- const { user, password, host, port, database, authSource } = this.options;
24359
- if (user && password) {
24360
- const auth = authSource ?? "admin";
24361
- return `mongodb://${user}:${encodeURIComponent(password)}@${host}:${port}/${database}?authSource=${auth}`;
24362
+ const { user, password, host, port, database, authSource, replicaSet, tls, srv } = this.options;
24363
+ if (!host) {
24364
+ throw new ConnectionError("UNKNOWN", "MongoDB host \u672A\u8A2D\u5B9A", [
24365
+ "\u8ACB\u586B\u5BEB host\uFF0C\u6216\u6539\u7528 uri \u6B04\u4F4D\u6307\u5B9A\u5B8C\u6574\u9023\u7DDA\u5B57\u4E32"
24366
+ ]);
24367
+ }
24368
+ const isBracketedIpv6 = /^\[[0-9a-f:]+\]$/i.test(host);
24369
+ if (!isBracketedIpv6 && /[/@?#:\s\\]/.test(host)) {
24370
+ throw new ConnectionError("UNKNOWN", `MongoDB host \u542B\u6709\u975E\u6CD5\u5B57\u5143: ${host}`, [
24371
+ "host \u53EA\u61C9\u5305\u542B\u4E3B\u6A5F\u540D\u7A31\u6216 IP\uFF0C\u4E0D\u8981\u542B /\u3001@\u3001?\u3001#\u3001: \u6216\u7A7A\u767D",
24372
+ "\u57E0\u865F\u8ACB\u586B\u5728 port \u6B04\u4F4D\uFF0C\u4E0D\u8981\u4F75\u9032 host",
24373
+ "IPv6 \u4F4D\u5740\u8ACB\u52A0\u65B9\u62EC\u865F\uFF0C\u4F8B\u5982 [::1]",
24374
+ "\u82E5\u8981\u6307\u5B9A\u5B8C\u6574\u9023\u7DDA\u5B57\u4E32\uFF0C\u8ACB\u6539\u7528 uri \u6B04\u4F4D"
24375
+ ]);
24376
+ }
24377
+ if (user && !password) {
24378
+ throw new ConnectionError("UNKNOWN", "\u5DF2\u6307\u5B9A user \u4F46\u672A\u63D0\u4F9B password", [
24379
+ '\u8ACB\u88DC\u4E0A password\uFF0C\u6216\u6539\u7528\u74B0\u5883\u8B8A\u6578\u53C3\u7167 {"$env": "..."}',
24380
+ "\u82E5\u78BA\u5B9A\u8981\u4EE5\u7121\u8A8D\u8B49\u65B9\u5F0F\u9023\u7DDA\uFF0C\u8ACB\u4E00\u4F75\u6E05\u7A7A user"
24381
+ ]);
24362
24382
  }
24363
- return `mongodb://${host}:${port}/${database}`;
24383
+ const userInfo = user ? `${encodeURIComponent(user)}:${encodeURIComponent(password)}@` : "";
24384
+ const scheme = srv ? "mongodb+srv://" : "mongodb://";
24385
+ const authority = srv ? host : `${host}:${port}`;
24386
+ const path5 = database ? `/${encodeURIComponent(database)}` : "/";
24387
+ const query = new URLSearchParams;
24388
+ if (user)
24389
+ query.set("authSource", authSource || "admin");
24390
+ if (replicaSet)
24391
+ query.set("replicaSet", replicaSet);
24392
+ if (tls !== undefined)
24393
+ query.set("tls", String(tls));
24394
+ const search = query.toString();
24395
+ return `${scheme}${userInfo}${authority}${path5}${search ? `?${search}` : ""}`;
24364
24396
  }
24365
24397
  parseTxtRecords(records) {
24366
24398
  const combined = records.flat().map((record) => record.replace(/^"|"$/g, "")).join("&");
@@ -24422,13 +24454,11 @@ class MongoDBAdapter {
24422
24454
  return this.parseTxtRecords(payload.Answer.map((answer) => [answer.data]));
24423
24455
  }
24424
24456
  async buildResolvedUri() {
24425
- if (!this.options.uri) {
24426
- return this.buildUri();
24427
- }
24428
- if (!this.options.uri.startsWith("mongodb+srv://")) {
24429
- return this.options.uri;
24457
+ const canonical = this.buildUri();
24458
+ if (!canonical.startsWith("mongodb+srv://")) {
24459
+ return canonical;
24430
24460
  }
24431
- const url = new URL(this.options.uri);
24461
+ const url = new URL(canonical);
24432
24462
  const hosts = await this.resolveSrvHosts(url.hostname);
24433
24463
  const txtOptions = await this.resolveTxtOptions(url.hostname);
24434
24464
  const query = new URLSearchParams(url.searchParams);
@@ -24448,6 +24478,37 @@ class MongoDBAdapter {
24448
24478
  const search = query.toString();
24449
24479
  return `mongodb://${userInfo}${hosts.join(",")}${path5}${search ? `?${search}` : ""}`;
24450
24480
  }
24481
+ connectionHints(error, message) {
24482
+ const AUTH_HINTS = [
24483
+ "\u8A8D\u8B49\u5931\u6557\uFF1A\u8ACB\u78BA\u8A8D user / password \u6B63\u78BA",
24484
+ "\u8ACB\u78BA\u8A8D authSource \u6307\u5411\u5B58\u653E\u8A72\u5E33\u865F\u7684\u8CC7\u6599\u5EAB\uFF08Atlas \u8207\u591A\u6578\u81EA\u67B6\u74B0\u5883\u70BA admin\uFF09"
24485
+ ];
24486
+ const DNS_HINTS = [
24487
+ "DNS/SRV \u89E3\u6790\u5931\u6557\uFF1A\u8ACB\u78BA\u8A8D host \u70BA SRV \u7DB2\u57DF\uFF0C\u4E14 srv \u8A2D\u5B9A\u8207\u5B83\u4E00\u81F4",
24488
+ "\u82E5\u8A72\u4E3B\u6A5F\u4E0D\u662F SRV \u7DB2\u57DF\uFF0C\u8ACB\u95DC\u9589 srv \u4E26\u6539\u586B host \u8207 port",
24489
+ "\u8ACB\u78BA\u8A8D\u672C\u6A5F DNS \u6216\u7DB2\u8DEF\uFF08VPN\u3001\u516C\u53F8\u7DB2\u8DEF\uFF09\u5141\u8A31 SRV \u67E5\u8A62"
24490
+ ];
24491
+ const TLS_HINTS = [
24492
+ "TLS \u63E1\u624B\u5931\u6557\uFF1A\u8ACB\u78BA\u8A8D tls \u6B04\u4F4D\u8A2D\u5B9A\u8207\u4F3A\u670D\u5668\u4E00\u81F4",
24493
+ "\u81EA\u7C3D\u6191\u8B49\u74B0\u5883\u9700\u8981\u5728\u4F3A\u670D\u5668\u7AEF\u6216\u7CFB\u7D71\u4FE1\u4EFB\u93C8\u4E2D\u5B89\u88DD CA \u6191\u8B49"
24494
+ ];
24495
+ const err = error;
24496
+ const causeCode = String(err?.cause?.code ?? err?.code ?? "");
24497
+ if (err?.code === 18 || err?.codeName === "AuthenticationFailed")
24498
+ return AUTH_HINTS;
24499
+ if (["ENOTFOUND", "EAI_AGAIN"].includes(causeCode))
24500
+ return DNS_HINTS;
24501
+ if (causeCode.startsWith("ERR_TLS") || causeCode.startsWith("SELF_SIGNED"))
24502
+ return TLS_HINTS;
24503
+ if (/authentication failed|not authorized|bad auth/i.test(message))
24504
+ return AUTH_HINTS;
24505
+ if (/querySrv|getaddrinfo (ENOTFOUND|EAI_AGAIN)/i.test(message))
24506
+ return DNS_HINTS;
24507
+ if (/unable to verify the first certificate|self.signed certificate|certificate has expired|ERR_TLS/i.test(message)) {
24508
+ return TLS_HINTS;
24509
+ }
24510
+ return ["\u8ACB\u78BA\u8A8D MongoDB \u670D\u52D9\u6B63\u5728\u57F7\u884C", "\u8ACB\u78BA\u8A8D\u9023\u7DDA\u8A2D\u5B9A\uFF08URI \u6216 host/port\uFF09\u6B63\u78BA"];
24511
+ }
24451
24512
  getDatabase() {
24452
24513
  if (!this.client) {
24453
24514
  throw new ConnectionError("UNKNOWN", "\u5C1A\u672A\u9023\u7DDA\uFF0C\u8ACB\u5148\u547C\u53EB connect()", []);
@@ -24463,10 +24524,7 @@ class MongoDBAdapter {
24463
24524
  } catch (err) {
24464
24525
  const message = err.message ?? "Unknown error";
24465
24526
  const code = message.includes("ECONNREFUSED") ? "ECONNREFUSED" : message.includes("ETIMEDOUT") ? "ETIMEDOUT" : "UNKNOWN";
24466
- throw new ConnectionError(code, `MongoDB \u9023\u7DDA\u5931\u6557: ${message}`, [
24467
- "\u8ACB\u78BA\u8A8D MongoDB \u670D\u52D9\u6B63\u5728\u57F7\u884C",
24468
- "\u8ACB\u78BA\u8A8D\u9023\u7DDA\u8A2D\u5B9A\uFF08URI \u6216 host/port\uFF09\u6B63\u78BA"
24469
- ]);
24527
+ throw new ConnectionError(code, `MongoDB \u9023\u7DDA\u5931\u6557: ${message}`, this.connectionHints(err, message));
24470
24528
  }
24471
24529
  }
24472
24530
  async disconnect() {
@@ -26112,9 +26170,8 @@ var init_adapters = __esm(() => {
26112
26170
  init_elasticsearch_adapter();
26113
26171
  });
26114
26172
 
26115
- // src/commands/init.ts
26173
+ // src/commands/init-shared.ts
26116
26174
  import { join as join14 } from "path";
26117
- import { mkdir as mkdir5 } from "fs/promises";
26118
26175
  async function checkOverwrite(configPath, shouldPrompt, force) {
26119
26176
  const storagePath = await resolveConfigStoragePath(configPath);
26120
26177
  const fileExists = await Bun.file(configPath).exists();
@@ -26132,68 +26189,6 @@ async function checkOverwrite(configPath, shouldPrompt, force) {
26132
26189
  }
26133
26190
  throw new Error(t("init.config_exists_use_force"));
26134
26191
  }
26135
- async function handleRemove(configPath, name2) {
26136
- const storagePath = await resolveConfigStoragePath(configPath);
26137
- const configFile = Bun.file(join14(storagePath, "config.json"));
26138
- if (!await configFile.exists()) {
26139
- throw new Error(t("init.config_not_found"));
26140
- }
26141
- const raw = JSON.parse(await configFile.text());
26142
- if (detectConfigVersion(raw) !== 2) {
26143
- throw new Error(t("init.requires_v2_remove"));
26144
- }
26145
- const config = await readV2Config(storagePath);
26146
- if (!config.connections[name2]) {
26147
- throw new Error(t_vars("init.connection_not_found", { name: name2 }));
26148
- }
26149
- const connectionCount = Object.keys(config.connections).length;
26150
- if (connectionCount <= 1) {
26151
- throw new Error(t("init.cannot_remove_last"));
26152
- }
26153
- const remaining = Object.fromEntries(Object.entries(config.connections).filter(([connectionName]) => connectionName !== name2));
26154
- const newDefault = config.default === name2 ? Object.keys(remaining)[0] : config.default;
26155
- const updated = {
26156
- ...config,
26157
- default: newDefault,
26158
- connections: remaining
26159
- };
26160
- await writeV2Config(storagePath, updated);
26161
- if (config.default === name2) {
26162
- console.log(t_vars("init.connection_removed_switched", { name: name2, newDefault }));
26163
- } else {
26164
- console.log(t_vars("init.connection_removed", { name: name2 }));
26165
- }
26166
- }
26167
- async function handleRename(configPath, renameArg) {
26168
- const [oldName, newName] = renameArg.split(":");
26169
- if (!oldName || !newName) {
26170
- throw new Error(t("init.rename_invalid_format"));
26171
- }
26172
- const storagePath = await resolveConfigStoragePath(configPath);
26173
- const configFile = Bun.file(join14(storagePath, "config.json"));
26174
- if (!await configFile.exists()) {
26175
- throw new Error(t("init.config_not_found"));
26176
- }
26177
- const raw = JSON.parse(await configFile.text());
26178
- if (detectConfigVersion(raw) !== 2) {
26179
- throw new Error(t("init.requires_v2_rename"));
26180
- }
26181
- const config = await readV2Config(storagePath);
26182
- if (!config.connections[oldName]) {
26183
- throw new Error(t_vars("init.connection_not_found", { name: oldName }));
26184
- }
26185
- if (config.connections[newName]) {
26186
- throw new Error(t_vars("init.connection_already_exists", { name: newName }));
26187
- }
26188
- const entries = Object.entries(config.connections).map(([key, value]) => [key === oldName ? newName : key, value]);
26189
- const updated = {
26190
- ...config,
26191
- default: config.default === oldName ? newName : config.default,
26192
- connections: Object.fromEntries(entries)
26193
- };
26194
- await writeV2Config(storagePath, updated);
26195
- console.log(t_vars("init.connection_renamed", { oldName, newName }));
26196
- }
26197
26192
  async function writeV2InitConfig(configPath, connectionName, connection, permission, envFile) {
26198
26193
  const globalConfig = isGlobalConfigPath(configPath);
26199
26194
  const storagePath = globalConfig ? configPath : getProjectStoragePath(configPath);
@@ -26319,6 +26314,270 @@ async function writeV2InitConfig(configPath, connectionName, connection, permiss
26319
26314
  }
26320
26315
  console.log(globalConfig ? t_vars("init.config_saved_global", { path: join14(configPath, "config.json") }) : t("init.config_saved"));
26321
26316
  }
26317
+ var init_init_shared = __esm(() => {
26318
+ init_message_loader();
26319
+ init_config();
26320
+ init_config_v2();
26321
+ init_prompts();
26322
+ init_config_binding();
26323
+ });
26324
+
26325
+ // src/commands/init-mongodb.ts
26326
+ import { mkdir as mkdir5 } from "fs/promises";
26327
+ async function handleMongoDBInit(ctx) {
26328
+ const { options, configPath, connectionName, isV2Init, existingConfig } = ctx;
26329
+ const isInteractive = options.interactive !== false && process.stdin.isTTY;
26330
+ const SETUP_MODES = ["\u9010\u6B04\u586B\u5BEB\uFF08\u5EFA\u8B70\uFF09", "\u8CBC\u4E0A\u5B8C\u6574\u9023\u7DDA\u5B57\u4E32\uFF08\u9032\u968E\uFF09"];
26331
+ const URI_MODE_INDEX = 1;
26332
+ const useEnvRefs = Boolean(options.useEnvRefs);
26333
+ let mongoUri = options.uri;
26334
+ let useUriMode = Boolean(mongoUri);
26335
+ if (!mongoUri && isInteractive) {
26336
+ const mode = await promptUser.select("\u9023\u7DDA\u8A2D\u5B9A\u65B9\u5F0F / Connection setup", [...SETUP_MODES]);
26337
+ useUriMode = mode === SETUP_MODES[URI_MODE_INDEX];
26338
+ while (useUriMode && !mongoUri) {
26339
+ const input = await promptUser.text("MongoDB \u9023\u7DDA\u5B57\u4E32 / connection string (mongodb://user:pass@host:27017/db)", "");
26340
+ if (input.trim()) {
26341
+ mongoUri = input.trim();
26342
+ } else {
26343
+ console.log("\u672A\u8F38\u5165\u9023\u7DDA\u5B57\u4E32\uFF0C\u6539\u7528\u9010\u6B04\u586B\u5BEB\u3002");
26344
+ useUriMode = false;
26345
+ }
26346
+ }
26347
+ }
26348
+ const useFieldEnvRefs = useEnvRefs && !useUriMode;
26349
+ if (useEnvRefs && useUriMode) {
26350
+ console.warn("\u26A0\uFE0F --use-env-refs \u4E0D\u9069\u7528\u65BC\u5B8C\u6574\u9023\u7DDA\u5B57\u4E32\uFF1AURI \u6703\u539F\u6A23\u5BEB\u5165\u8A2D\u5B9A\u6A94\uFF0C\u5E33\u5BC6\u4E0D\u6703\u88AB\u62BD\u6210\u74B0\u5883\u8B8A\u6578\u53C3\u7167\u3002");
26351
+ }
26352
+ const fields = {
26353
+ host: options.host || "localhost",
26354
+ port: parseInt(options.port || "27017", 10),
26355
+ user: options.user || "",
26356
+ password: options.password || "",
26357
+ authSource: options.authSource || "",
26358
+ replicaSet: "",
26359
+ tls: undefined,
26360
+ srv: false
26361
+ };
26362
+ const promptPort = async (fallback) => {
26363
+ for (;; ) {
26364
+ const raw = await promptUser.text("Port\uFF08\u57E0\u865F\uFF09", String(fallback));
26365
+ const parsed = parseInt(raw, 10);
26366
+ if (Number.isInteger(parsed) && parsed > 0 && parsed <= 65535)
26367
+ return parsed;
26368
+ console.log("\u8ACB\u8F38\u5165 1-65535 \u7684\u6574\u6578\u3002");
26369
+ }
26370
+ };
26371
+ if (!useUriMode && isInteractive) {
26372
+ if (!useFieldEnvRefs) {
26373
+ fields.host = await promptUser.text("Host\uFF08\u4E3B\u6A5F\u4F4D\u5740\uFF09", fields.host);
26374
+ }
26375
+ fields.srv = await promptUser.confirm("\u9019\u662F SRV \u7DB2\u57DF\u55CE\uFF08Atlas \u7B49 mongodb+srv \u9023\u7DDA\uFF09\uFF1F");
26376
+ if (!fields.srv && !useFieldEnvRefs) {
26377
+ fields.port = await promptPort(fields.port);
26378
+ }
26379
+ if (!useFieldEnvRefs) {
26380
+ fields.user = await promptUser.text("User\uFF08\u5E33\u865F\uFF0C\u7121\u8A8D\u8B49\u8ACB\u7559\u7A7A\uFF09", fields.user);
26381
+ if (fields.user) {
26382
+ fields.password = await promptUser.text("Password\uFF08\u5BC6\u78BC\uFF09", fields.password);
26383
+ fields.authSource = await promptUser.text("authSource\uFF08\u8A8D\u8B49\u8CC7\u6599\u5EAB\uFF09", fields.authSource || "admin");
26384
+ }
26385
+ }
26386
+ if (await promptUser.confirm("\u8A2D\u5B9A\u9032\u968E\u9078\u9805\uFF08replicaSet / tls\uFF09\uFF1F")) {
26387
+ fields.replicaSet = await promptUser.text("replicaSet\uFF08\u8907\u672C\u96C6\u540D\u7A31\uFF0C\u53EF\u7559\u7A7A\uFF09", "");
26388
+ fields.tls = await promptUser.confirm("\u555F\u7528 tls\uFF1F");
26389
+ }
26390
+ }
26391
+ let database = options.name || "";
26392
+ if (!database && isInteractive && !useFieldEnvRefs) {
26393
+ database = await promptUser.text("Database name", "testdb");
26394
+ }
26395
+ const envRefFor = async (flag, label, suggestion) => {
26396
+ const name2 = flag ?? (isInteractive ? await promptUser.text(label, suggestion) : "");
26397
+ return name2.trim() ? { $env: name2.trim() } : null;
26398
+ };
26399
+ let envRefConfig = null;
26400
+ if (useFieldEnvRefs) {
26401
+ const hostRef = await envRefFor(options.envHost, "Host \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31", "MONGO_HOST");
26402
+ const portRef = await envRefFor(options.envPort, "Port \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31\uFF08\u53EF\u7559\u7A7A\uFF09", "");
26403
+ const userRef = await envRefFor(options.envUser, "User \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31\uFF08\u53EF\u7559\u7A7A\uFF09", "");
26404
+ const passwordRef = await envRefFor(options.envPassword, "Password \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31\uFF08\u53EF\u7559\u7A7A\uFF09", "");
26405
+ const databaseRef = await envRefFor(options.envDatabase, "Database \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31\uFF08\u53EF\u7559\u7A7A\uFF09", "");
26406
+ if (!hostRef) {
26407
+ throw new Error("--use-env-refs \u9700\u8981 host \u7684\u74B0\u5883\u8B8A\u6578\u540D\u7A31\uFF08--env-host\uFF09");
26408
+ }
26409
+ if (!databaseRef && !database && isInteractive) {
26410
+ database = await promptUser.text("Database name", "testdb");
26411
+ }
26412
+ if (!databaseRef && !database) {
26413
+ throw new Error(t("errors.require_name"));
26414
+ }
26415
+ envRefConfig = {
26416
+ system: "mongodb",
26417
+ host: hostRef,
26418
+ port: portRef ?? fields.port,
26419
+ user: userRef ?? "",
26420
+ password: passwordRef ?? "",
26421
+ database: databaseRef ?? database,
26422
+ ...fields.authSource ? { authSource: fields.authSource } : {},
26423
+ ...fields.replicaSet ? { replicaSet: fields.replicaSet } : {},
26424
+ ...fields.tls !== undefined ? { tls: fields.tls } : {},
26425
+ ...fields.srv ? { srv: true } : {}
26426
+ };
26427
+ }
26428
+ if (!database && !isInteractive && !useFieldEnvRefs) {
26429
+ throw new Error(t("errors.require_name"));
26430
+ }
26431
+ const mongoConfig = envRefConfig ?? (useUriMode ? {
26432
+ system: "mongodb",
26433
+ uri: mongoUri,
26434
+ database,
26435
+ host: "",
26436
+ port: 27017,
26437
+ user: "",
26438
+ password: ""
26439
+ } : {
26440
+ system: "mongodb",
26441
+ host: fields.host,
26442
+ port: fields.port,
26443
+ user: fields.user,
26444
+ password: fields.password,
26445
+ database,
26446
+ ...fields.user ? { authSource: fields.authSource || "admin" } : {},
26447
+ ...fields.replicaSet ? { replicaSet: fields.replicaSet } : {},
26448
+ ...fields.tls !== undefined ? { tls: fields.tls } : {},
26449
+ ...fields.srv ? { srv: true } : {}
26450
+ });
26451
+ let permission = options.permission || "query-only";
26452
+ if (isInteractive && !options.permission) {
26453
+ permission = await promptUser.select(t("init.prompt_permission"), [
26454
+ "query-only",
26455
+ "read-write",
26456
+ "data-admin",
26457
+ "admin"
26458
+ ]);
26459
+ }
26460
+ if (!VALID_PERMISSIONS.includes(permission)) {
26461
+ throw new Error(t_vars("errors.invalid_permission", { permission }));
26462
+ }
26463
+ const canProceed = await checkOverwrite(configPath, isInteractive, !!options.force);
26464
+ if (!canProceed)
26465
+ return;
26466
+ if (!options.skipTest && !useFieldEnvRefs) {
26467
+ console.log(t("init.connection_testing"));
26468
+ const mongoAdapter = AdapterFactory.createMongoDBAdapter(mongoConfig);
26469
+ try {
26470
+ await mongoAdapter.connect();
26471
+ await mongoAdapter.testConnection();
26472
+ console.log(t("init.connection_success"));
26473
+ } catch (error) {
26474
+ if (error instanceof ConnectionError) {
26475
+ console.error(t_vars("errors.connection_failed", { message: error.message }));
26476
+ console.error(t("init.connection_hints"));
26477
+ error.hints.forEach((hint) => console.error(` \u2022 ${hint}`));
26478
+ process.exit(1);
26479
+ }
26480
+ throw error;
26481
+ } finally {
26482
+ await mongoAdapter.disconnect();
26483
+ }
26484
+ } else {
26485
+ console.log(`\u23ED\uFE0F ${t(useFieldEnvRefs ? "init.skip_test_env_ref" : "init.skip_test")}`);
26486
+ }
26487
+ if (isV2Init) {
26488
+ await writeV2InitConfig(configPath, connectionName, mongoConfig, permission, options.envFile);
26489
+ return;
26490
+ }
26491
+ const newConfig = configModule.merge(existingConfig, {
26492
+ connection: mongoConfig,
26493
+ permission
26494
+ });
26495
+ const globalConfig = isGlobalConfigPath(configPath);
26496
+ const storagePath = globalConfig ? configPath : getProjectStoragePath(configPath);
26497
+ await mkdir5(storagePath, { recursive: true });
26498
+ await configModule.write(storagePath, newConfig);
26499
+ if (!globalConfig) {
26500
+ await migrateLegacyProjectEnvLocal(configPath, storagePath);
26501
+ await writeProjectBinding(configPath, storagePath);
26502
+ }
26503
+ console.log(t("init.config_saved"));
26504
+ }
26505
+ var VALID_PERMISSIONS;
26506
+ var init_init_mongodb = __esm(() => {
26507
+ init_message_loader();
26508
+ init_config();
26509
+ init_prompts();
26510
+ init_adapters();
26511
+ init_config_binding();
26512
+ init_init_shared();
26513
+ VALID_PERMISSIONS = ["query-only", "read-write", "data-admin", "admin"];
26514
+ });
26515
+
26516
+ // src/commands/init.ts
26517
+ import { join as join15 } from "path";
26518
+ import { mkdir as mkdir6 } from "fs/promises";
26519
+ async function handleRemove(configPath, name2) {
26520
+ const storagePath = await resolveConfigStoragePath(configPath);
26521
+ const configFile = Bun.file(join15(storagePath, "config.json"));
26522
+ if (!await configFile.exists()) {
26523
+ throw new Error(t("init.config_not_found"));
26524
+ }
26525
+ const raw = JSON.parse(await configFile.text());
26526
+ if (detectConfigVersion(raw) !== 2) {
26527
+ throw new Error(t("init.requires_v2_remove"));
26528
+ }
26529
+ const config = await readV2Config(storagePath);
26530
+ if (!config.connections[name2]) {
26531
+ throw new Error(t_vars("init.connection_not_found", { name: name2 }));
26532
+ }
26533
+ const connectionCount = Object.keys(config.connections).length;
26534
+ if (connectionCount <= 1) {
26535
+ throw new Error(t("init.cannot_remove_last"));
26536
+ }
26537
+ const remaining = Object.fromEntries(Object.entries(config.connections).filter(([connectionName]) => connectionName !== name2));
26538
+ const newDefault = config.default === name2 ? Object.keys(remaining)[0] : config.default;
26539
+ const updated = {
26540
+ ...config,
26541
+ default: newDefault,
26542
+ connections: remaining
26543
+ };
26544
+ await writeV2Config(storagePath, updated);
26545
+ if (config.default === name2) {
26546
+ console.log(t_vars("init.connection_removed_switched", { name: name2, newDefault }));
26547
+ } else {
26548
+ console.log(t_vars("init.connection_removed", { name: name2 }));
26549
+ }
26550
+ }
26551
+ async function handleRename(configPath, renameArg) {
26552
+ const [oldName, newName] = renameArg.split(":");
26553
+ if (!oldName || !newName) {
26554
+ throw new Error(t("init.rename_invalid_format"));
26555
+ }
26556
+ const storagePath = await resolveConfigStoragePath(configPath);
26557
+ const configFile = Bun.file(join15(storagePath, "config.json"));
26558
+ if (!await configFile.exists()) {
26559
+ throw new Error(t("init.config_not_found"));
26560
+ }
26561
+ const raw = JSON.parse(await configFile.text());
26562
+ if (detectConfigVersion(raw) !== 2) {
26563
+ throw new Error(t("init.requires_v2_rename"));
26564
+ }
26565
+ const config = await readV2Config(storagePath);
26566
+ if (!config.connections[oldName]) {
26567
+ throw new Error(t_vars("init.connection_not_found", { name: oldName }));
26568
+ }
26569
+ if (config.connections[newName]) {
26570
+ throw new Error(t_vars("init.connection_already_exists", { name: newName }));
26571
+ }
26572
+ const entries = Object.entries(config.connections).map(([key, value]) => [key === oldName ? newName : key, value]);
26573
+ const updated = {
26574
+ ...config,
26575
+ default: config.default === oldName ? newName : config.default,
26576
+ connections: Object.fromEntries(entries)
26577
+ };
26578
+ await writeV2Config(storagePath, updated);
26579
+ console.log(t_vars("init.connection_renamed", { oldName, newName }));
26580
+ }
26322
26581
  async function initCommandHandler(options, command) {
26323
26582
  const configPath = resolveConfigPath(command);
26324
26583
  if (options.remove) {
@@ -26399,7 +26658,7 @@ async function initCommandHandler(options, command) {
26399
26658
  "admin"
26400
26659
  ]);
26401
26660
  }
26402
- if (!VALID_PERMISSIONS.includes(permission2)) {
26661
+ if (!VALID_PERMISSIONS2.includes(permission2)) {
26403
26662
  throw new Error(t_vars("errors.invalid_permission", { permission: permission2 }));
26404
26663
  }
26405
26664
  const newConfig2 = configModule.merge(existingConfig, {
@@ -26415,7 +26674,7 @@ async function initCommandHandler(options, command) {
26415
26674
  return;
26416
26675
  }
26417
26676
  const storagePath2 = isGlobalConfig ? configPath : getProjectStoragePath(configPath);
26418
- await mkdir5(storagePath2, { recursive: true });
26677
+ await mkdir6(storagePath2, { recursive: true });
26419
26678
  await configModule.write(storagePath2, newConfig2);
26420
26679
  if (!isGlobalConfig) {
26421
26680
  await migrateLegacyProjectEnvLocal(configPath, storagePath2);
@@ -26454,7 +26713,7 @@ async function initCommandHandler(options, command) {
26454
26713
  "admin"
26455
26714
  ]);
26456
26715
  }
26457
- if (!VALID_PERMISSIONS.includes(permission)) {
26716
+ if (!VALID_PERMISSIONS2.includes(permission)) {
26458
26717
  throw new Error(t_vars("errors.invalid_permission", { permission }));
26459
26718
  }
26460
26719
  configForWrite = connection;
@@ -26531,7 +26790,7 @@ async function initCommandHandler(options, command) {
26531
26790
  return;
26532
26791
  }
26533
26792
  const storagePath = isGlobalConfig ? configPath : getProjectStoragePath(configPath);
26534
- await mkdir5(storagePath, { recursive: true });
26793
+ await mkdir6(storagePath, { recursive: true });
26535
26794
  await configModule.write(storagePath, newConfig);
26536
26795
  if (!isGlobalConfig) {
26537
26796
  await migrateLegacyProjectEnvLocal(configPath, storagePath);
@@ -26539,95 +26798,7 @@ async function initCommandHandler(options, command) {
26539
26798
  }
26540
26799
  console.log(t("init.config_saved"));
26541
26800
  }
26542
- async function handleMongoDBInit(ctx) {
26543
- const { options, configPath, connectionName, isV2Init, existingConfig } = ctx;
26544
- const isInteractive = options.interactive !== false && process.stdin.isTTY;
26545
- let mongoUri = options.uri;
26546
- if (!mongoUri && isInteractive) {
26547
- const input = await promptUser.text("MongoDB URI (e.g. mongodb://user:pass@host:27017/db?authSource=admin) \u2014 \u7559\u7A7A\u7528 host/port/user/password", "");
26548
- if (input.trim())
26549
- mongoUri = input.trim();
26550
- }
26551
- let database = options.name || "";
26552
- if (!database && isInteractive) {
26553
- database = await promptUser.text("Database name", "testdb");
26554
- }
26555
- if (!database && !isInteractive) {
26556
- throw new Error(t("errors.require_name"));
26557
- }
26558
- const authSource = options.authSource || "";
26559
- const mongoConfig = mongoUri ? {
26560
- system: "mongodb",
26561
- uri: mongoUri,
26562
- database,
26563
- host: "",
26564
- port: 27017,
26565
- user: "",
26566
- password: ""
26567
- } : {
26568
- system: "mongodb",
26569
- host: options.host || "localhost",
26570
- port: parseInt(options.port || "27017", 10),
26571
- user: options.user || "",
26572
- password: options.password || "",
26573
- database,
26574
- ...authSource ? { authSource } : {}
26575
- };
26576
- let permission = options.permission || "query-only";
26577
- if (isInteractive && !options.permission) {
26578
- permission = await promptUser.select(t("init.prompt_permission"), [
26579
- "query-only",
26580
- "read-write",
26581
- "data-admin",
26582
- "admin"
26583
- ]);
26584
- }
26585
- if (!VALID_PERMISSIONS.includes(permission)) {
26586
- throw new Error(t_vars("errors.invalid_permission", { permission }));
26587
- }
26588
- const canProceed = await checkOverwrite(configPath, isInteractive, !!options.force);
26589
- if (!canProceed)
26590
- return;
26591
- if (!options.skipTest) {
26592
- console.log(t("init.connection_testing"));
26593
- const mongoAdapter = AdapterFactory.createMongoDBAdapter(mongoConfig);
26594
- try {
26595
- await mongoAdapter.connect();
26596
- await mongoAdapter.testConnection();
26597
- console.log(t("init.connection_success"));
26598
- } catch (error) {
26599
- if (error instanceof ConnectionError) {
26600
- console.error(t_vars("errors.connection_failed", { message: error.message }));
26601
- console.error(t("init.connection_hints"));
26602
- error.hints.forEach((hint) => console.error(` \u2022 ${hint}`));
26603
- process.exit(1);
26604
- }
26605
- throw error;
26606
- } finally {
26607
- await mongoAdapter.disconnect();
26608
- }
26609
- } else {
26610
- console.log(`\u23ED\uFE0F ${t("init.skip_test")}`);
26611
- }
26612
- if (isV2Init) {
26613
- await writeV2InitConfig(configPath, connectionName, mongoConfig, permission, options.envFile);
26614
- return;
26615
- }
26616
- const newConfig = configModule.merge(existingConfig, {
26617
- connection: mongoConfig,
26618
- permission
26619
- });
26620
- const globalConfig = isGlobalConfigPath(configPath);
26621
- const storagePath = globalConfig ? configPath : getProjectStoragePath(configPath);
26622
- await mkdir5(storagePath, { recursive: true });
26623
- await configModule.write(storagePath, newConfig);
26624
- if (!globalConfig) {
26625
- await migrateLegacyProjectEnvLocal(configPath, storagePath);
26626
- await writeProjectBinding(configPath, storagePath);
26627
- }
26628
- console.log(t("init.config_saved"));
26629
- }
26630
- var VALID_PERMISSIONS, initCommand;
26801
+ var VALID_PERMISSIONS2, initCommand;
26631
26802
  var init_init = __esm(() => {
26632
26803
  init_esm();
26633
26804
  init_message_loader();
@@ -26638,7 +26809,9 @@ var init_init = __esm(() => {
26638
26809
  init_adapters();
26639
26810
  init_config_path();
26640
26811
  init_config_binding();
26641
- VALID_PERMISSIONS = ["query-only", "read-write", "data-admin", "admin"];
26812
+ init_init_shared();
26813
+ init_init_mongodb();
26814
+ VALID_PERMISSIONS2 = ["query-only", "read-write", "data-admin", "admin"];
26642
26815
  initCommand = new Command("init").description("Initialize dbcli configuration with .env parsing and interactive prompts").option("--host <host>", "Database host").option("--port <port>", "Database port").option("--user <user>", "Database user").option("--password <password>", "Database password").option("--name <name>", "Database name").option("--system <system>", "Database system (postgresql, mysql, mariadb, mongodb, redis, elasticsearch)").option("--cloud-id <id>", "Elasticsearch Cloud ID").option("--api-key <key>", "Elasticsearch API Key").option("--uri <uri>", "MongoDB connection URI (mongodb://user:pass@host:27017/db?authSource=admin)").option("--auth-source <authSource>", "MongoDB auth database (default: admin when user/password are set)").option("--permission <permission>", "Permission level (query-only, read-write, data-admin, admin)", "query-only").option("--use-env-refs", "Store env var references in config instead of actual values (for CI/CD or multi-env)", false).option("--env-host <var>", "Env var name for host (with --use-env-refs)").option("--env-port <var>", "Env var name for port (with --use-env-refs)").option("--env-user <var>", "Env var name for user (with --use-env-refs)").option("--env-password <var>", "Env var name for password (with --use-env-refs)").option("--env-database <var>", "Env var name for database (with --use-env-refs)").option("--skip-test", "Skip database connection test").option("--no-interactive", "Non-interactive mode (requires all values via flags)").option("--force", "Skip overwrite confirmation if .dbcli exists").option("--conn-name <name>", "Connection name (creates v2 multi-connection config)").option("--env-file <path>", "Path to env file for this connection").option("--remove <name>", "Remove a named connection").option("--rename <names>", "Rename a connection (format: old:new)").action(async (options) => {
26643
26816
  try {
26644
26817
  await initCommandHandler(options, initCommand);
@@ -28906,7 +29079,7 @@ class AtomicFileWriter {
28906
29079
  }
28907
29080
 
28908
29081
  // src/core/schema-writer.ts
28909
- import { join as join15 } from "path";
29082
+ import { join as join16 } from "path";
28910
29083
 
28911
29084
  class SchemaWriter {
28912
29085
  dbcliPath;
@@ -28927,7 +29100,7 @@ class SchemaWriter {
28927
29100
  hotSchemas[item.table] = tableSchema;
28928
29101
  }
28929
29102
  }
28930
- await this.writer.writeJSON(join15(schemaRoot, "hot-schemas.json"), hotSchemas);
29103
+ await this.writer.writeJSON(join16(schemaRoot, "hot-schemas.json"), hotSchemas);
28931
29104
  const coldGroups = {};
28932
29105
  for (const item of mapping.cold) {
28933
29106
  if (!coldGroups[item.file]) {
@@ -28938,10 +29111,10 @@ class SchemaWriter {
28938
29111
  coldGroups[item.file][item.table] = tableSchema;
28939
29112
  }
28940
29113
  }
28941
- const coldDir = join15(schemaRoot, "cold");
29114
+ const coldDir = join16(schemaRoot, "cold");
28942
29115
  await this.ensureDir(coldDir);
28943
29116
  for (const [fileName, tables] of Object.entries(coldGroups)) {
28944
- const filePath = join15(schemaRoot, fileName);
29117
+ const filePath = join16(schemaRoot, fileName);
28945
29118
  await this.writer.writeJSON(filePath, tables);
28946
29119
  }
28947
29120
  }
@@ -29487,8 +29660,8 @@ var init_artifact = __esm(() => {
29487
29660
  });
29488
29661
 
29489
29662
  // src/core/verification/artifact-writer.ts
29490
- import { mkdir as mkdir6, writeFile as writeFile2, link, unlink as unlink4 } from "fs/promises";
29491
- import { join as join16 } from "path";
29663
+ import { mkdir as mkdir7, writeFile as writeFile2, link, unlink as unlink4 } from "fs/promises";
29664
+ import { join as join17 } from "path";
29492
29665
  function pad(n, len = 2) {
29493
29666
  return String(n).padStart(len, "0");
29494
29667
  }
@@ -29505,9 +29678,9 @@ function verificationArtifactFilename(artifact) {
29505
29678
  return `verification-${timeStamp(artifact.createdAt)}-${shortId(artifact.id)}.json`;
29506
29679
  }
29507
29680
  async function writeVerificationArtifact(storageDir, artifact) {
29508
- const dir = join16(storageDir, VERIFICATION_DIR_RELATIVE);
29509
- await mkdir6(dir, { recursive: true });
29510
- const target = join16(dir, verificationArtifactFilename(artifact));
29681
+ const dir = join17(storageDir, VERIFICATION_DIR_RELATIVE);
29682
+ await mkdir7(dir, { recursive: true });
29683
+ const target = join17(dir, verificationArtifactFilename(artifact));
29511
29684
  const tmp = `${target}.${process.pid}.tmp`;
29512
29685
  try {
29513
29686
  await writeFile2(tmp, JSON.stringify(artifact, null, 2), "utf8");
@@ -29768,7 +29941,7 @@ var init_assert_artifact = __esm(() => {
29768
29941
 
29769
29942
  // src/core/verification/reader.ts
29770
29943
  import { lstat as lstat2, readdir as readdir2, readFile as readFile2 } from "fs/promises";
29771
- import { join as join17, isAbsolute, resolve as resolve4, sep as sep2 } from "path";
29944
+ import { join as join18, isAbsolute, resolve as resolve4, sep as sep2 } from "path";
29772
29945
  function isArtifactFilename(name2) {
29773
29946
  return /^verification-.*\.json$/.test(name2);
29774
29947
  }
@@ -29852,7 +30025,7 @@ function validateVerificationArtifact(value) {
29852
30025
  return value;
29853
30026
  }
29854
30027
  async function readVerificationArtifacts(storageRoot) {
29855
- const storageDir = join17(storageRoot, VERIFICATION_DIR_RELATIVE);
30028
+ const storageDir = join18(storageRoot, VERIFICATION_DIR_RELATIVE);
29856
30029
  let names;
29857
30030
  try {
29858
30031
  names = await readdir2(storageDir);
@@ -29865,7 +30038,7 @@ async function readVerificationArtifacts(storageRoot) {
29865
30038
  const artifacts = [];
29866
30039
  const invalid = [];
29867
30040
  for (const filename of names.filter(isArtifactFilename)) {
29868
- const path5 = join17(storageDir, filename);
30041
+ const path5 = join18(storageDir, filename);
29869
30042
  try {
29870
30043
  const stats = await lstat2(path5);
29871
30044
  if (!stats.isFile()) {
@@ -30346,7 +30519,7 @@ var init_core = __esm(() => {
30346
30519
  // src/core/audit/lock.ts
30347
30520
  import { hostname } from "os";
30348
30521
  import { dirname as dirname5 } from "path";
30349
- import { mkdir as mkdir7, open as open2, rm } from "fs/promises";
30522
+ import { mkdir as mkdir8, open as open2, rm } from "fs/promises";
30350
30523
 
30351
30524
  class AuditLockManager {
30352
30525
  auditFilePath;
@@ -30404,7 +30577,7 @@ class AuditLockManager {
30404
30577
  }
30405
30578
  async tryAcquireLock(operationName) {
30406
30579
  try {
30407
- await mkdir7(dirname5(this.lockPath), { recursive: true });
30580
+ await mkdir8(dirname5(this.lockPath), { recursive: true });
30408
30581
  const lockFile = Bun.file(this.lockPath);
30409
30582
  if (await lockFile.exists()) {
30410
30583
  const lockContent = await lockFile.json();
@@ -30457,8 +30630,8 @@ var init_rotation = __esm(() => {
30457
30630
  });
30458
30631
 
30459
30632
  // src/core/audit/logger.ts
30460
- import { appendFile, mkdir as mkdir8, readFile as readFile3, stat as stat2 } from "fs/promises";
30461
- import { join as join18 } from "path";
30633
+ import { appendFile, mkdir as mkdir9, readFile as readFile3, stat as stat2 } from "fs/promises";
30634
+ import { join as join19 } from "path";
30462
30635
  import { randomUUID as randomUUID3 } from "crypto";
30463
30636
 
30464
30637
  class AuditLogger {
@@ -30484,8 +30657,8 @@ class AuditLogger {
30484
30657
  this.enabled = opts.enabled;
30485
30658
  this.maxBytes = opts.rotation.maxBytes;
30486
30659
  this.maxEntries = opts.rotation.maxEntries;
30487
- this.auditDir = join18(opts.storagePath, ".dbcli", "audit");
30488
- this.auditFilePath = join18(this.auditDir, `${opts.connectionName}.jsonl`);
30660
+ this.auditDir = join19(opts.storagePath, ".dbcli", "audit");
30661
+ this.auditFilePath = join19(this.auditDir, `${opts.connectionName}.jsonl`);
30489
30662
  this.previousFilePath = `${this.auditFilePath}.1`;
30490
30663
  this.sessionIdService = opts.sessionIdService;
30491
30664
  this.lockManager = opts.lockManager ?? new AuditLockManager(this.auditFilePath);
@@ -30506,7 +30679,7 @@ class AuditLogger {
30506
30679
  try {
30507
30680
  const sessionId = await this.sessionIdService.resolve();
30508
30681
  this.cachedSessionId = sessionId;
30509
- await mkdir8(this.auditDir, { recursive: true });
30682
+ await mkdir9(this.auditDir, { recursive: true });
30510
30683
  if (!this.writerInitialized) {
30511
30684
  await this.syncCountersFromDisk();
30512
30685
  this.writerInitialized = true;
@@ -30611,15 +30784,15 @@ var init_logger2 = __esm(() => {
30611
30784
  });
30612
30785
 
30613
30786
  // src/core/audit/session-id.ts
30614
- import { mkdir as mkdir9, readFile as readFile4, rename as rename4, stat as stat3, writeFile as writeFile3 } from "fs/promises";
30787
+ import { mkdir as mkdir10, readFile as readFile4, rename as rename4, stat as stat3, writeFile as writeFile3 } from "fs/promises";
30615
30788
  import { randomBytes as randomBytes2 } from "crypto";
30616
- import { dirname as dirname6, join as join19 } from "path";
30789
+ import { dirname as dirname6, join as join20 } from "path";
30617
30790
  function generateSessionId(pid, nowMs) {
30618
30791
  const random = randomBytes2(3).toString("hex");
30619
30792
  return `${pid}-${nowMs}-${random}`;
30620
30793
  }
30621
30794
  async function readSessionIdFile(storagePath) {
30622
- const target = join19(storagePath, LAST_SESSION_ID_RELATIVE);
30795
+ const target = join20(storagePath, LAST_SESSION_ID_RELATIVE);
30623
30796
  try {
30624
30797
  await stat3(target);
30625
30798
  } catch {
@@ -30641,10 +30814,10 @@ async function readSessionIdFile(storagePath) {
30641
30814
  }
30642
30815
  }
30643
30816
  async function writeSessionIdFile(storagePath, payload) {
30644
- const target = join19(storagePath, LAST_SESSION_ID_RELATIVE);
30817
+ const target = join20(storagePath, LAST_SESSION_ID_RELATIVE);
30645
30818
  const tmp = `${target}.tmp`;
30646
30819
  try {
30647
- await mkdir9(dirname6(target), { recursive: true });
30820
+ await mkdir10(dirname6(target), { recursive: true });
30648
30821
  await writeFile3(tmp, JSON.stringify(payload, null, 2), "utf8");
30649
30822
  await rename4(tmp, target);
30650
30823
  } catch {}
@@ -32373,14 +32546,14 @@ var init_render_markdown = __esm(() => {
32373
32546
  });
32374
32547
 
32375
32548
  // src/core/recovery/last-envelope.ts
32376
- import { writeFile as writeFile4, readFile as readFile5, rename as rename5, mkdir as mkdir10, stat as stat4 } from "fs/promises";
32377
- import { dirname as dirname7, join as join20 } from "path";
32549
+ import { writeFile as writeFile4, readFile as readFile5, rename as rename5, mkdir as mkdir11, stat as stat4 } from "fs/promises";
32550
+ import { dirname as dirname7, join as join21 } from "path";
32378
32551
  import { randomUUID as randomUUID4 } from "crypto";
32379
32552
  function sanitizeCommandSummary(argv) {
32380
32553
  return redactArgv(argv);
32381
32554
  }
32382
32555
  async function writeLastEnvelope(cwd, envelope, argv, now = () => new Date, id = randomUUID4(), auditRef) {
32383
- const target = join20(cwd, LAST_ENVELOPE_PATH);
32556
+ const target = join21(cwd, LAST_ENVELOPE_PATH);
32384
32557
  const tmp = `${target}.tmp`;
32385
32558
  const payload = {
32386
32559
  schemaVersion: 1,
@@ -32392,13 +32565,13 @@ async function writeLastEnvelope(cwd, envelope, argv, now = () => new Date, id =
32392
32565
  envelope
32393
32566
  };
32394
32567
  try {
32395
- await mkdir10(dirname7(target), { recursive: true });
32568
+ await mkdir11(dirname7(target), { recursive: true });
32396
32569
  await writeFile4(tmp, JSON.stringify(payload, null, 2), "utf8");
32397
32570
  await rename5(tmp, target);
32398
32571
  } catch {}
32399
32572
  }
32400
32573
  async function readLastEnvelope(cwd) {
32401
- const target = join20(cwd, LAST_ENVELOPE_PATH);
32574
+ const target = join21(cwd, LAST_ENVELOPE_PATH);
32402
32575
  try {
32403
32576
  await stat4(target);
32404
32577
  } catch {
@@ -32412,7 +32585,7 @@ async function readLastEnvelope(cwd) {
32412
32585
  }
32413
32586
  }
32414
32587
  async function readLastEnvelopeRaw(cwd) {
32415
- const target = join20(cwd, LAST_ENVELOPE_PATH);
32588
+ const target = join21(cwd, LAST_ENVELOPE_PATH);
32416
32589
  try {
32417
32590
  await stat4(target);
32418
32591
  } catch {
@@ -32437,7 +32610,7 @@ var init_last_envelope = __esm(() => {
32437
32610
 
32438
32611
  // src/core/recovery/emit.ts
32439
32612
  import { writeFileSync as writeFileSync2, mkdirSync, renameSync, writeSync } from "fs";
32440
- import { dirname as dirname8, join as join21 } from "path";
32613
+ import { dirname as dirname8, join as join22 } from "path";
32441
32614
  import { randomUUID as randomUUID5 } from "crypto";
32442
32615
  function emitRecoveryEnvelope(error, ctx, options = {}) {
32443
32616
  const envelope = classifyError(error, ctx);
@@ -32454,7 +32627,7 @@ function buildArgvFromProcess() {
32454
32627
  return ["dbcli", ...userArgs];
32455
32628
  }
32456
32629
  function writeLastEnvelopeSync(cwd, envelope, argv, id, auditRef) {
32457
- const target = join21(cwd, LAST_ENVELOPE_PATH);
32630
+ const target = join22(cwd, LAST_ENVELOPE_PATH);
32458
32631
  const tmp = `${target}.tmp`;
32459
32632
  const payload = {
32460
32633
  schemaVersion: 1,
@@ -34387,7 +34560,7 @@ var init_query_size_guard = __esm(() => {
34387
34560
  // src/commands/query.ts
34388
34561
  import crypto3 from "crypto";
34389
34562
  import { tmpdir } from "os";
34390
- import { join as join22 } from "path";
34563
+ import { join as join23 } from "path";
34391
34564
  function requireSqlConnection2(connection) {
34392
34565
  if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
34393
34566
  throw new Error(`This command requires a SQL connection, got: ${connection.system}`);
@@ -34698,7 +34871,7 @@ async function presentSingleResult(query, options, execution, tableCellLimit) {
34698
34871
  } : {}
34699
34872
  });
34700
34873
  if (options.ui) {
34701
- const tempPath = join22(tmpdir(), `dbcli-query-${Date.now()}.html`);
34874
+ const tempPath = join23(tmpdir(), `dbcli-query-${Date.now()}.html`);
34702
34875
  await Bun.write(tempPath, html);
34703
34876
  await openInBrowser(tempPath);
34704
34877
  } else {
@@ -35458,7 +35631,7 @@ __export(exports_q_mongo, {
35458
35631
  qMongoBranch: () => qMongoBranch
35459
35632
  });
35460
35633
  import { tmpdir as tmpdir2 } from "os";
35461
- import { join as join23 } from "path";
35634
+ import { join as join24 } from "path";
35462
35635
  async function qMongoBranch(snippet, prepared, options, config) {
35463
35636
  const collection = options.collection ?? prepared.execHints?.collection;
35464
35637
  if (!collection) {
@@ -35490,7 +35663,7 @@ async function qMongoBranch(snippet, prepared, options, config) {
35490
35663
  ...securityNotification ? { securityNotification } : {}
35491
35664
  });
35492
35665
  if (options.ui) {
35493
- const tempPath = join23(tmpdir2(), `dbcli-report-${Date.now()}.html`);
35666
+ const tempPath = join24(tmpdir2(), `dbcli-report-${Date.now()}.html`);
35494
35667
  await Bun.write(tempPath, html);
35495
35668
  await openInBrowser(tempPath);
35496
35669
  } else {
@@ -35531,7 +35704,7 @@ var init_q_mongo = __esm(() => {
35531
35704
  // src/commands/q.ts
35532
35705
  import crypto4 from "crypto";
35533
35706
  import { tmpdir as tmpdir3 } from "os";
35534
- import { join as join24 } from "path";
35707
+ import { join as join25 } from "path";
35535
35708
  function formatDryRun(input) {
35536
35709
  const lines = ["Dry-run preview (no execution):"];
35537
35710
  if (input.family === "es") {
@@ -35632,7 +35805,7 @@ async function qCommand(name2, options, command) {
35632
35805
  ...securityNotification ? { securityNotification } : {}
35633
35806
  });
35634
35807
  if (options.ui) {
35635
- const tempPath = join24(tmpdir3(), `dbcli-report-${Date.now()}.html`);
35808
+ const tempPath = join25(tmpdir3(), `dbcli-report-${Date.now()}.html`);
35636
35809
  await Bun.write(tempPath, html);
35637
35810
  await openInBrowser(tempPath);
35638
35811
  } else {
@@ -36081,7 +36254,7 @@ var exports_queries_rename = {};
36081
36254
  __export(exports_queries_rename, {
36082
36255
  queriesRename: () => queriesRename
36083
36256
  });
36084
- import { rename as rename6, mkdir as mkdir11 } from "fs/promises";
36257
+ import { rename as rename6, mkdir as mkdir12 } from "fs/promises";
36085
36258
  import { dirname as dirname9 } from "path";
36086
36259
  async function queriesRename(oldName, newName, options = {}) {
36087
36260
  if (!oldName.startsWith("@") || !newName.startsWith("@")) {
@@ -36103,7 +36276,7 @@ async function queriesRename(oldName, newName, options = {}) {
36103
36276
  for (const v of local) {
36104
36277
  const dst = snippetKeyToFile(cwd, newName, "local");
36105
36278
  const dstWithSuffix = preserveEngineSuffix(v.query.file, dst);
36106
- await mkdir11(dirname9(dstWithSuffix), { recursive: true });
36279
+ await mkdir12(dirname9(dstWithSuffix), { recursive: true });
36107
36280
  await rename6(v.query.file, dstWithSuffix);
36108
36281
  await rewriteFrontmatterName(dstWithSuffix, newName.slice(1));
36109
36282
  console.log(`renamed ${v.query.file} \u2192 ${dstWithSuffix}`);
@@ -36129,7 +36302,7 @@ var exports_queries_copy = {};
36129
36302
  __export(exports_queries_copy, {
36130
36303
  queriesCopy: () => queriesCopy
36131
36304
  });
36132
- import { mkdir as mkdir12, copyFile } from "fs/promises";
36305
+ import { mkdir as mkdir13, copyFile } from "fs/promises";
36133
36306
  import { dirname as dirname10, basename as basename4 } from "path";
36134
36307
  async function queriesCopy(src, dst, options = {}) {
36135
36308
  if (!src.startsWith("@") || !dst.startsWith("@")) {
@@ -36148,7 +36321,7 @@ async function queriesCopy(src, dst, options = {}) {
36148
36321
  }
36149
36322
  for (const v of variants) {
36150
36323
  const dstFile = mapEngineSuffix(v.query.file, snippetKeyToFile(cwd, dst, "local"));
36151
- await mkdir12(dirname10(dstFile), { recursive: true });
36324
+ await mkdir13(dirname10(dstFile), { recursive: true });
36152
36325
  await copyFile(v.query.file, dstFile);
36153
36326
  console.log(`copied ${v.query.file} \u2192 ${dstFile}`);
36154
36327
  }
@@ -36166,8 +36339,8 @@ var exports_queries_import = {};
36166
36339
  __export(exports_queries_import, {
36167
36340
  queriesImport: () => queriesImport
36168
36341
  });
36169
- import { stat as stat6, mkdir as mkdir13, copyFile as copyFile2 } from "fs/promises";
36170
- import { basename as basename5, join as join25, extname as extname2 } from "path";
36342
+ import { stat as stat6, mkdir as mkdir14, copyFile as copyFile2 } from "fs/promises";
36343
+ import { basename as basename5, join as join26, extname as extname2 } from "path";
36171
36344
  async function queriesImport(filePath, options = {}) {
36172
36345
  const cwd = options.cwd ?? process.cwd();
36173
36346
  if (extname2(filePath) !== ".sql") {
@@ -36178,9 +36351,9 @@ async function queriesImport(filePath, options = {}) {
36178
36351
  const baseName = options.as ? options.as.replace(/^@/, "") : basename5(filePath, ".sql").replace(/\.(postgres|mysql)$/, "");
36179
36352
  const key = "@" + baseName;
36180
36353
  parseSavedQuery({ key, file: filePath, source: "local", text: text2 });
36181
- const targetDir = join25(cwd, ".dbcli/queries");
36182
- await mkdir13(targetDir, { recursive: true });
36183
- const target = join25(targetDir, basename5(filePath));
36354
+ const targetDir = join26(cwd, ".dbcli/queries");
36355
+ await mkdir14(targetDir, { recursive: true });
36356
+ const target = join26(targetDir, basename5(filePath));
36184
36357
  if (await Bun.file(target).exists()) {
36185
36358
  if (!options.force) {
36186
36359
  const ok = await dist_default6({ message: `Overwrite ${target}?`, default: false });
@@ -36233,7 +36406,7 @@ var init_queries_export = __esm(() => {
36233
36406
  });
36234
36407
 
36235
36408
  // src/commands/queries.ts
36236
- import { mkdir as mkdir14, writeFile as writeFile6 } from "fs/promises";
36409
+ import { mkdir as mkdir15, writeFile as writeFile6 } from "fs/promises";
36237
36410
  import { dirname as dirname11 } from "path";
36238
36411
  import { spawn as spawn2 } from "child_process";
36239
36412
  async function deriveEngine(command) {
@@ -36342,7 +36515,7 @@ async function queriesNew(name2, options) {
36342
36515
  process.exit(1);
36343
36516
  return;
36344
36517
  }
36345
- await mkdir14(dirname11(file), { recursive: true });
36518
+ await mkdir15(dirname11(file), { recursive: true });
36346
36519
  await writeFile6(file, scaffold(name2), "utf8");
36347
36520
  console.log(`Created ${file}`);
36348
36521
  if (source === "shared")
@@ -39064,15 +39237,15 @@ var init_types6 = __esm(() => {
39064
39237
  });
39065
39238
 
39066
39239
  // src/core/agent-tasks/task-paths.ts
39067
- import { join as join26 } from "path";
39240
+ import { join as join27 } from "path";
39068
39241
  function resolveBuiltinDir2() {
39069
39242
  return packageAssetPath("tasks");
39070
39243
  }
39071
39244
  function resolveAgentTaskDirs(workspaceRoot) {
39072
39245
  return {
39073
39246
  builtinDir: resolveBuiltinDir2(),
39074
- sharedDir: join26(workspaceRoot, ".dbcli-shared", "tasks"),
39075
- localDir: join26(workspaceRoot, ".dbcli", "tasks")
39247
+ sharedDir: join27(workspaceRoot, ".dbcli-shared", "tasks"),
39248
+ localDir: join27(workspaceRoot, ".dbcli", "tasks")
39076
39249
  };
39077
39250
  }
39078
39251
  var init_task_paths = __esm(() => {
@@ -39219,7 +39392,7 @@ var init_parser2 = __esm(() => {
39219
39392
 
39220
39393
  // src/core/agent-tasks/loader.ts
39221
39394
  import { readdir as readdir3 } from "fs/promises";
39222
- import { join as join27, relative as relative2, sep as sep4 } from "path";
39395
+ import { join as join28, relative as relative2, sep as sep4 } from "path";
39223
39396
  async function loadAgentTasks(opts, flags) {
39224
39397
  const errors3 = [];
39225
39398
  const builtin = await walkAndParse2(opts.builtinDir, "builtin", errors3);
@@ -39276,7 +39449,7 @@ async function safeCollectMd(root) {
39276
39449
  return;
39277
39450
  }
39278
39451
  for (const e of entries) {
39279
- const full = join27(dir, e.name);
39452
+ const full = join28(dir, e.name);
39280
39453
  if (e.isDirectory())
39281
39454
  await walk(full);
39282
39455
  else
@@ -92641,7 +92814,7 @@ var init_collect_snippets = __esm(() => {
92641
92814
  });
92642
92815
 
92643
92816
  // src/core/inspect/collect-schema-cache.ts
92644
- import { join as join28 } from "path";
92817
+ import { join as join29 } from "path";
92645
92818
  async function collectSchemaCache(opts) {
92646
92819
  const warnings = [];
92647
92820
  if (opts.system && !SQL_SYSTEMS2.includes(opts.system)) {
@@ -92651,7 +92824,7 @@ async function collectSchemaCache(opts) {
92651
92824
  };
92652
92825
  }
92653
92826
  const root = resolveSchemaPath(opts.dbcliPath, opts.connectionName);
92654
- const indexPath = join28(root, "index.json");
92827
+ const indexPath = join29(root, "index.json");
92655
92828
  const file = Bun.file(indexPath);
92656
92829
  if (!await file.exists()) {
92657
92830
  return { section: { available: false }, warnings };
@@ -92921,7 +93094,7 @@ function buildHints(snap, ctx = {}) {
92921
93094
  }
92922
93095
 
92923
93096
  // src/core/inspect/collector.ts
92924
- import { join as join29 } from "path";
93097
+ import { join as join30 } from "path";
92925
93098
  async function collectInspect(opts) {
92926
93099
  const warnings = [];
92927
93100
  let config = null;
@@ -93005,7 +93178,7 @@ async function collectInspect(opts) {
93005
93178
  return { ...snapWithoutSuggestions, suggestedCommands, hints, warnings };
93006
93179
  }
93007
93180
  async function hasConfig(configPath) {
93008
- if (await Bun.file(join29(configPath, "config.json")).exists())
93181
+ if (await Bun.file(join30(configPath, "config.json")).exists())
93009
93182
  return true;
93010
93183
  if (await Bun.file(configPath).exists()) {
93011
93184
  const stat7 = await Bun.file(configPath).stat().catch(() => null);
@@ -96094,9 +96267,9 @@ function relationBindings(statement) {
96094
96267
  const bindings = [];
96095
96268
  for (const item of statement.from) {
96096
96269
  const source = item;
96097
- const join30 = typeof source.join === "string" ? source.join.toUpperCase() : "";
96098
- const nullExtendsPrevious = join30.startsWith("RIGHT") || join30.startsWith("FULL");
96099
- const nullExtendsCurrent = join30.startsWith("LEFT") || join30.startsWith("FULL");
96270
+ const join31 = typeof source.join === "string" ? source.join.toUpperCase() : "";
96271
+ const nullExtendsPrevious = join31.startsWith("RIGHT") || join31.startsWith("FULL");
96272
+ const nullExtendsCurrent = join31.startsWith("LEFT") || join31.startsWith("FULL");
96100
96273
  if (nullExtendsPrevious) {
96101
96274
  for (const binding of bindings)
96102
96275
  binding.nullExtended = true;
@@ -97412,7 +97585,7 @@ var init_serializer = __esm(() => {
97412
97585
  });
97413
97586
 
97414
97587
  // src/commands/snapshot.ts
97415
- import { join as join30 } from "path";
97588
+ import { join as join31 } from "path";
97416
97589
  function requireSqlConnection9(connection) {
97417
97590
  if (!SQL_SYSTEMS6.includes(connection.system)) {
97418
97591
  throw new Error(`snapshot currently supports SQL engines only, got: ${connection.system}`);
@@ -97425,7 +97598,7 @@ function pad2(n) {
97425
97598
  function defaultSnapshotPath() {
97426
97599
  const d = new Date;
97427
97600
  const stamp = `${d.getFullYear()}${pad2(d.getMonth() + 1)}${pad2(d.getDate())}-${pad2(d.getHours())}${pad2(d.getMinutes())}${pad2(d.getSeconds())}`;
97428
- return join30(".dbcli", "snapshots", `snap-${stamp}.json`);
97601
+ return join31(".dbcli", "snapshots", `snap-${stamp}.json`);
97429
97602
  }
97430
97603
  var ALLOWED_FORMATS12, SQL_SYSTEMS6, snapshotCommand;
97431
97604
  var init_snapshot = __esm(() => {
@@ -100414,12 +100587,12 @@ Verification artifact: ${verificationArtifactPath}`);
100414
100587
 
100415
100588
  // src/commands/audit.ts
100416
100589
  import { rm as rm3, stat as stat8 } from "fs/promises";
100417
- import { join as join31 } from "path";
100590
+ import { join as join32 } from "path";
100418
100591
  async function resolveAuditPaths(configPath, config) {
100419
100592
  const storagePath = await resolveConfigStoragePath(configPath);
100420
100593
  const connName = config.effectiveConnectionName || getGlobalConnectionName() || "default";
100421
- const auditDir = join31(storagePath, ".dbcli", "audit");
100422
- const auditFile = join31(auditDir, `${connName}.jsonl`);
100594
+ const auditDir = join32(storagePath, ".dbcli", "audit");
100595
+ const auditFile = join32(auditDir, `${connName}.jsonl`);
100423
100596
  return { auditDir, connectionName: connName, auditFile };
100424
100597
  }
100425
100598
  function isAuditDisabled(config) {
@@ -100847,7 +101020,7 @@ var init_audit = __esm(() => {
100847
101020
  });
100848
101021
 
100849
101022
  // src/utils/runtime-info.ts
100850
- import { join as join32, normalize, relative as relative3, sep as sep5 } from "path";
101023
+ import { join as join33, normalize, relative as relative3, sep as sep5 } from "path";
100851
101024
  function normalized(path6) {
100852
101025
  return normalize(path6).replaceAll("\\", "/");
100853
101026
  }
@@ -100873,7 +101046,7 @@ async function collectRuntimeInfo(packageVersion) {
100873
101046
  const launcherPath = process.argv[1] ?? "unknown";
100874
101047
  let packageFileVersion = null;
100875
101048
  try {
100876
- const packageFile = Bun.file(join32(packageRoot, "package.json"));
101049
+ const packageFile = Bun.file(join33(packageRoot, "package.json"));
100877
101050
  if (await packageFile.exists()) {
100878
101051
  const parsed = await packageFile.json();
100879
101052
  if (typeof parsed.version === "string" && parsed.version.length > 0) {
@@ -100901,7 +101074,7 @@ var init_runtime_info = __esm(() => {
100901
101074
  });
100902
101075
 
100903
101076
  // src/commands/doctor.ts
100904
- import { join as join33 } from "path";
101077
+ import { join as join34 } from "path";
100905
101078
  import { resolveSrv as resolveSrv2 } from "dns/promises";
100906
101079
  function requireSqlConnection12(connection) {
100907
101080
  if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
@@ -101013,13 +101186,33 @@ async function collectMongoDoctorResults(config) {
101013
101186
  const results = [];
101014
101187
  const mongoConn = config.connection.system === "mongodb" ? config.connection : null;
101015
101188
  const mongoUriString = mongoConn && typeof mongoConn.uri === "string" ? mongoConn.uri : undefined;
101016
- const srvCheck = await runDoctorChecks.checkMongoSrvConnectivity(mongoUriString);
101189
+ const srvProbeUri = mongoUriString ?? (mongoConn?.srv === true && typeof mongoConn.host === "string" && mongoConn.host ? `mongodb+srv://${mongoConn.host}/` : undefined);
101190
+ const srvCheck = await runDoctorChecks.checkMongoSrvConnectivity(srvProbeUri);
101017
101191
  if (srvCheck) {
101018
101192
  results.push(srvCheck);
101019
101193
  if (srvCheck.status === "error") {
101020
101194
  return results;
101021
101195
  }
101022
101196
  }
101197
+ if (mongoConn) {
101198
+ const hasFieldConfig = Boolean(mongoConn.host) || Boolean(mongoConn.user);
101199
+ if (mongoUriString && hasFieldConfig) {
101200
+ results.push({
101201
+ group: "Connection & Data",
101202
+ label: "MongoDB connection fields",
101203
+ status: "warn",
101204
+ message: "Both uri and per-field settings (host/user) are present; uri takes precedence and the per-field values are ignored."
101205
+ });
101206
+ }
101207
+ if (mongoConn.srv === true && typeof mongoConn.port === "number" && mongoConn.port !== 27017) {
101208
+ results.push({
101209
+ group: "Connection & Data",
101210
+ label: "MongoDB SRV port",
101211
+ status: "warn",
101212
+ message: `srv is enabled, so port ${mongoConn.port} is ignored \u2014 SRV records carry their own ports.`
101213
+ });
101214
+ }
101215
+ }
101023
101216
  const adapter = AdapterFactory.createMongoDBAdapter(config.connection);
101024
101217
  try {
101025
101218
  await adapter.connect();
@@ -101217,7 +101410,7 @@ var init_doctor = __esm(() => {
101217
101410
  }
101218
101411
  },
101219
101412
  async checkConfigExists(configPath, existsFn) {
101220
- const exists = existsFn ? await existsFn(configPath) : await Bun.file(configPath).exists() || await Bun.file(join33(configPath, "config.json")).exists();
101413
+ const exists = existsFn ? await existsFn(configPath) : await Bun.file(configPath).exists() || await Bun.file(join34(configPath, "config.json")).exists();
101221
101414
  return {
101222
101415
  group: "Configuration",
101223
101416
  label: "Config exists",
@@ -101301,7 +101494,17 @@ var init_doctor = __esm(() => {
101301
101494
  if (!uri || !uri.startsWith("mongodb+srv://")) {
101302
101495
  return null;
101303
101496
  }
101304
- const url = new URL(uri);
101497
+ let url;
101498
+ try {
101499
+ url = new URL(uri);
101500
+ } catch {
101501
+ return {
101502
+ group: "Environment",
101503
+ label: "MongoDB SRV lookup",
101504
+ status: "error",
101505
+ message: `Cannot parse ${uri} as a connection string \u2014 check the host value`
101506
+ };
101507
+ }
101305
101508
  const srvName = `_mongodb._tcp.${url.hostname}`;
101306
101509
  const resolveSrvFn = deps.resolveSrvFn ?? resolveSrv2;
101307
101510
  const fetchFn = deps.fetchFn ?? fetch;
@@ -101384,7 +101587,7 @@ var init_doctor = __esm(() => {
101384
101587
  async checkV2Config(configPath) {
101385
101588
  const results = [];
101386
101589
  const storagePath = await resolveConfigStoragePath(configPath);
101387
- const configFile = Bun.file(join33(storagePath, "config.json"));
101590
+ const configFile = Bun.file(join34(storagePath, "config.json"));
101388
101591
  if (!await configFile.exists())
101389
101592
  return results;
101390
101593
  let raw;
@@ -101424,7 +101627,7 @@ var init_doctor = __esm(() => {
101424
101627
  }
101425
101628
  for (const [name2, conn] of Object.entries(config.connections)) {
101426
101629
  if (conn.envFile) {
101427
- const envPath = join33(storagePath, conn.envFile);
101630
+ const envPath = join34(storagePath, conn.envFile);
101428
101631
  const exists = await Bun.file(envPath).exists();
101429
101632
  results.push({
101430
101633
  group: "Configuration",
@@ -101534,7 +101737,7 @@ var init_doctor = __esm(() => {
101534
101737
  }
101535
101738
  try {
101536
101739
  const schemaConnName = await getSchemaIsolationConnectionName(configPath);
101537
- const indexPath = join33(resolveSchemaPath(storagePath, schemaConnName), "index.json");
101740
+ const indexPath = join34(resolveSchemaPath(storagePath, schemaConnName), "index.json");
101538
101741
  const indexFile = Bun.file(indexPath);
101539
101742
  let indexParsed = null;
101540
101743
  if (await indexFile.exists()) {
@@ -101643,9 +101846,9 @@ function flattenCommandTree(root) {
101643
101846
  }
101644
101847
 
101645
101848
  // src/commands/completion.ts
101646
- import { join as join34 } from "path";
101849
+ import { join as join35 } from "path";
101647
101850
  import { homedir as homedir3 } from "os";
101648
- import { mkdir as mkdir15 } from "fs/promises";
101851
+ import { mkdir as mkdir16 } from "fs/promises";
101649
101852
  function resolveHome() {
101650
101853
  return process.env.HOME ?? homedir3();
101651
101854
  }
@@ -101895,11 +102098,11 @@ function getInstallPath2(shell) {
101895
102098
  const home = resolveHome();
101896
102099
  switch (shell) {
101897
102100
  case "bash":
101898
- return join34(home, ".bashrc");
102101
+ return join35(home, ".bashrc");
101899
102102
  case "zsh":
101900
- return join34(home, ".zshrc");
102103
+ return join35(home, ".zshrc");
101901
102104
  case "fish":
101902
- return join34(home, ".config", "fish", "completions", "dbcli.fish");
102105
+ return join35(home, ".config", "fish", "completions", "dbcli.fish");
101903
102106
  default:
101904
102107
  throw new Error(`Unsupported shell: ${shell}. Supported: bash, zsh, fish`);
101905
102108
  }
@@ -101917,8 +102120,8 @@ function detectShell() {
101917
102120
  async function installCompletion(shell, script) {
101918
102121
  const targetPath = getInstallPath2(shell);
101919
102122
  if (shell === "fish") {
101920
- const dir = join34(resolveHome(), ".config", "fish", "completions");
101921
- await mkdir15(dir, { recursive: true });
102123
+ const dir = join35(resolveHome(), ".config", "fish", "completions");
102124
+ await mkdir16(dir, { recursive: true });
101922
102125
  await Bun.file(targetPath).write(script);
101923
102126
  console.log(colors.success(`\u2713 Fish completion installed to ${targetPath}`));
101924
102127
  return;
@@ -102902,7 +103105,7 @@ var init_command_registry = __esm(() => {
102902
103105
 
102903
103106
  // src/commands/shell.ts
102904
103107
  import { createInterface as createInterface3 } from "readline";
102905
- import { join as join35 } from "path";
103108
+ import { join as join36 } from "path";
102906
103109
  import { homedir as homedir4 } from "os";
102907
103110
  function requireSqlConnection13(connection) {
102908
103111
  if (!["postgresql", "mysql", "mariadb"].includes(connection.system)) {
@@ -103096,7 +103299,7 @@ var init_shell3 = __esm(() => {
103096
103299
  init_message_loader();
103097
103300
  init_es_shell();
103098
103301
  import_picocolors5 = __toESM(require_picocolors(), 1);
103099
- HISTORY_PATH = join35(homedir4(), ".dbcli_history");
103302
+ HISTORY_PATH = join36(homedir4(), ".dbcli_history");
103100
103303
  shellCommand = new Command("shell").description("Interactive database shell with auto-completion and syntax highlighting").option("--sql", "SQL-only mode (skip dbcli command parsing)").action(async (options, command) => {
103101
103304
  const configPath = resolveConfigPath(command);
103102
103305
  await runShell(options, configPath);
@@ -103941,7 +104144,7 @@ var init_migrate = __esm(() => {
103941
104144
  });
103942
104145
 
103943
104146
  // src/commands/use.ts
103944
- import { join as join36 } from "path";
104147
+ import { join as join37 } from "path";
103945
104148
  async function switchDefault(configPath, name2, config, options = {}) {
103946
104149
  const connection = config.connections[name2];
103947
104150
  if (!connection) {
@@ -103984,7 +104187,7 @@ function listConnectionIdentities(config) {
103984
104187
  }
103985
104188
  async function ensureV2Config(configPath) {
103986
104189
  const storagePath = await resolveConfigStoragePath(configPath);
103987
- const configFile = Bun.file(join36(storagePath, "config.json"));
104190
+ const configFile = Bun.file(join37(storagePath, "config.json"));
103988
104191
  const legacyFile = Bun.file(configPath);
103989
104192
  if (!await configFile.exists() && !await legacyFile.exists()) {
103990
104193
  throw new ConfigError(t("init.config_not_found"));
@@ -104142,7 +104345,7 @@ var init_sql_metadata = __esm(() => {
104142
104345
  });
104143
104346
 
104144
104347
  // src/proxy/events.ts
104145
- import { appendFile as appendFile2, mkdir as mkdir16, readFile as readFile8, stat as stat9 } from "fs/promises";
104348
+ import { appendFile as appendFile2, mkdir as mkdir17, readFile as readFile8, stat as stat9 } from "fs/promises";
104146
104349
  import { dirname as dirname13 } from "path";
104147
104350
  function hasSql(e) {
104148
104351
  return e.type === "query_observed" || e.type === "query_completed" || e.type === "query_errored";
@@ -104182,7 +104385,7 @@ class EventWriter {
104182
104385
  }
104183
104386
  async writeInternal(event) {
104184
104387
  if (!this.dirEnsured) {
104185
- await mkdir16(dirname13(this.path), { recursive: true });
104388
+ await mkdir17(dirname13(this.path), { recursive: true });
104186
104389
  this.dirEnsured = true;
104187
104390
  }
104188
104391
  if (!this.initialized) {
@@ -105111,7 +105314,7 @@ function renderAnalysisText(report, top) {
105111
105314
  }
105112
105315
 
105113
105316
  // src/commands/proxy.ts
105114
- import { join as join37 } from "path";
105317
+ import { join as join38 } from "path";
105115
105318
  function parseHostPort(value) {
105116
105319
  const idx = value.lastIndexOf(":");
105117
105320
  if (idx <= 0 || idx === value.length - 1) {
@@ -105174,7 +105377,7 @@ async function runProxy(subcommandEngine, options, command) {
105174
105377
  target: options.target,
105175
105378
  connection
105176
105379
  });
105177
- const eventsPath = options.events ?? join37(".dbcli", "proxy", "events.jsonl");
105380
+ const eventsPath = options.events ?? join38(".dbcli", "proxy", "events.jsonl");
105178
105381
  const slowMs = Number(options.slowMs ?? 1000);
105179
105382
  if (!Number.isFinite(slowMs) || slowMs < 0) {
105180
105383
  throw new Error(`Invalid --slow-ms "${options.slowMs}". Expected a non-negative number`);
@@ -105223,7 +105426,7 @@ async function runProxy(subcommandEngine, options, command) {
105223
105426
  }
105224
105427
  }
105225
105428
  function addCommonOptions(cmd) {
105226
- return cmd.option("--listen <host:port>", "Local proxy listen address (required)").option("--target <host:port>", "Upstream DB target (optional when config provides host/port)").option("--events <path>", "Event JSONL path", join37(".dbcli", "proxy", "events.jsonl")).option("--slow-ms <number>", "Threshold (ms); queries at/above it get slow:true in the event + a terminal warning", "1000").option("--redact <mode>", "SQL redaction: none | literals", "none").option("--format <format>", "Runtime status output: text | json", "text");
105429
+ return cmd.option("--listen <host:port>", "Local proxy listen address (required)").option("--target <host:port>", "Upstream DB target (optional when config provides host/port)").option("--events <path>", "Event JSONL path", join38(".dbcli", "proxy", "events.jsonl")).option("--slow-ms <number>", "Threshold (ms); queries at/above it get slow:true in the event + a terminal warning", "1000").option("--redact <mode>", "SQL redaction: none | literals", "none").option("--format <format>", "Runtime status output: text | json", "text");
105227
105430
  }
105228
105431
  function parseNonNegInt(value, flag, fallback) {
105229
105432
  if (value === undefined)
@@ -105241,7 +105444,7 @@ async function runAnalyze(options) {
105241
105444
  const top = parseNonNegInt(options.top, "top", 20);
105242
105445
  const slowMs = parseNonNegInt(options.slowMs, "slow-ms", 1000);
105243
105446
  const nPlusOne = parseNonNegInt(options.nPlusOne, "n-plus-one", 10);
105244
- const eventsPath = options.events ?? join37(".dbcli", "proxy", "events.jsonl");
105447
+ const eventsPath = options.events ?? join38(".dbcli", "proxy", "events.jsonl");
105245
105448
  const { events, malformedLines, files } = await readEvents(eventsPath, {
105246
105449
  includeRotated: options.includeRotated !== false
105247
105450
  });
@@ -105288,7 +105491,7 @@ var init_proxy = __esm(() => {
105288
105491
  });
105289
105492
  }
105290
105493
  ANALYZE_FORMATS = ["json", "text"];
105291
- proxyCommand.command("analyze").description("Analyze a proxy event log offline (no DB connection)").option("--events <path>", "Event JSONL path", join37(".dbcli", "proxy", "events.jsonl")).option("--format <format>", "Output format: json | text", "json").option("--top <number>", "Rows shown in text + suggestedCommands depth", "20").option("--slow-ms <number>", "Slow-query threshold (ms) for slowCount", "1000").option("--n-plus-one <number>", "Min repeats per (session,fingerprint) to flag N+1", "10").option("--no-include-rotated", "Do not merge the rotated <events>.1 segment").action(async (options) => {
105494
+ proxyCommand.command("analyze").description("Analyze a proxy event log offline (no DB connection)").option("--events <path>", "Event JSONL path", join38(".dbcli", "proxy", "events.jsonl")).option("--format <format>", "Output format: json | text", "json").option("--top <number>", "Rows shown in text + suggestedCommands depth", "20").option("--slow-ms <number>", "Slow-query threshold (ms) for slowCount", "1000").option("--n-plus-one <number>", "Min repeats per (session,fingerprint) to flag N+1", "10").option("--no-include-rotated", "Do not merge the rotated <events>.1 segment").action(async (options) => {
105292
105495
  await runAnalyze(options);
105293
105496
  });
105294
105497
  addCommonOptions(proxyCommand).action(async (options, command) => {
@@ -105497,7 +105700,7 @@ var init_backfill_artifact = __esm(() => {
105497
105700
 
105498
105701
  // src/commands/backfill.ts
105499
105702
  import { dirname as dirname14, resolve as resolve9 } from "path";
105500
- import { mkdir as mkdir17 } from "fs/promises";
105703
+ import { mkdir as mkdir18 } from "fs/promises";
105501
105704
  function identityFor(config, name2) {
105502
105705
  const connection = config.connections[name2];
105503
105706
  if (!connection) {
@@ -105547,7 +105750,7 @@ var init_backfill = __esm(() => {
105547
105750
  return;
105548
105751
  }
105549
105752
  const out = resolve9(options.out ?? `.dbcli/backfills/${artifact2.source.sha256.slice(0, 12)}.json`);
105550
- await mkdir17(dirname14(out), { recursive: true });
105753
+ await mkdir18(dirname14(out), { recursive: true });
105551
105754
  await Bun.write(out, JSON.stringify(artifact2, null, 2) + `
105552
105755
  `);
105553
105756
  console.log(JSON.stringify({ path: out, artifact: artifact2 }, null, 2));
@@ -105862,7 +106065,7 @@ async function claimUpdateHint(configPath, kind, sessionKey, value) {
105862
106065
  // src/cli.ts
105863
106066
  init_program();
105864
106067
  init_cli_error();
105865
- import { join as join38 } from "path";
106068
+ import { join as join39 } from "path";
105866
106069
  import { writeSync as writeSync2 } from "fs";
105867
106070
  import { format } from "util";
105868
106071
  function installSynchronousRedirectedStdout() {
@@ -105990,7 +106193,7 @@ program2.hook("preAction", (thisCommand, actionCommand) => {
105990
106193
  try {
105991
106194
  let cache = null;
105992
106195
  try {
105993
- const cacheFile = Bun.file(join38(configPath, "version-check.json"));
106196
+ const cacheFile = Bun.file(join39(configPath, "version-check.json"));
105994
106197
  if (await cacheFile.exists()) {
105995
106198
  cache = await cacheFile.json();
105996
106199
  }