@carllee1983/dbcli 1.56.0 → 1.57.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.
@@ -51,7 +51,7 @@ var package_default;
51
51
  var init_package = __esm(() => {
52
52
  package_default = {
53
53
  name: "@carllee1983/dbcli",
54
- version: "1.56.0",
54
+ version: "1.57.0",
55
55
  description: "Database CLI for AI agents",
56
56
  type: "module",
57
57
  publishConfig: {
@@ -6232,7 +6232,11 @@ function resolveEnvReferences(config, env, parentKey) {
6232
6232
  }
6233
6233
  function parseEnvPassword(content) {
6234
6234
  const match = content.match(/^DBCLI_PASSWORD=(.+)$/m);
6235
- return match?.[1] != null ? match[1].trim() : null;
6235
+ if (match?.[1] == null)
6236
+ return null;
6237
+ const raw = match[1].trim();
6238
+ const quoted = raw.startsWith('"') && raw.endsWith('"') || raw.startsWith("'") && raw.endsWith("'");
6239
+ return quoted && raw.length >= 2 ? raw.slice(1, -1) : raw;
6236
6240
  }
6237
6241
  var _globalConnectionName, DEFAULT_CONFIG, configModule;
6238
6242
  var init_config = __esm(() => {
@@ -9058,6 +9062,20 @@ Reference: {referencePath}`,
9058
9062
  add_enum_description: "Create an enum type (PostgreSQL only)",
9059
9063
  alter_enum_description: "Add a value to an enum type",
9060
9064
  drop_enum_description: "Drop an enum type"
9065
+ },
9066
+ password: {
9067
+ description: "Change the password of a single connection, leaving every other setting untouched",
9068
+ arg_connection: "Connection name (defaults to the current default connection)",
9069
+ opt_stdin: "Read the new password from stdin (for rotation scripts)",
9070
+ opt_password: "New password given inline (visible in shell history and process list)",
9071
+ opt_skip_test: "Skip verifying the new password against the database before saving",
9072
+ prompt: "New password for connection '{name}'",
9073
+ source_conflict: "--password and --stdin cannot be used together; pick one source.",
9074
+ needs_source: "No terminal available for a masked prompt. Pass the value with --stdin or --password.",
9075
+ empty: "The new password is empty; nothing was changed.",
9076
+ updated: "Password for connection '{name}' updated \u2192 {envFile} ({varName})",
9077
+ converted: 'The literal password in config.json was replaced by a {{ "$env": "{varName}" }} reference; later rotations only touch the env file.',
9078
+ skipped_test: "Verification skipped (--skip-test): the new password was not checked against the database."
9061
9079
  }
9062
9080
  };
9063
9081
  });
@@ -9342,6 +9360,20 @@ var init_messages2 = __esm(() => {
9342
9360
  add_enum_description: "\u5EFA\u7ACB\u5217\u8209\u578B\u5225\uFF08\u50C5 PostgreSQL\uFF09",
9343
9361
  alter_enum_description: "\u65B0\u589E\u5217\u8209\u503C",
9344
9362
  drop_enum_description: "\u522A\u9664\u5217\u8209\u578B\u5225"
9363
+ },
9364
+ password: {
9365
+ description: "\u53EA\u8B8A\u66F4\u55AE\u4E00\u9023\u7DDA\u7684\u5BC6\u78BC\uFF0C\u5176\u9918\u8A2D\u5B9A\u539F\u5C01\u4E0D\u52D5",
9366
+ arg_connection: "\u9023\u7DDA\u540D\u7A31\uFF08\u7701\u7565\u6642\u6539\u9810\u8A2D\u9023\u7DDA\uFF09",
9367
+ opt_stdin: "\u5F9E stdin \u8B80\u53D6\u65B0\u5BC6\u78BC\uFF08\u4F9B\u8F2A\u66FF\u8173\u672C\u4F7F\u7528\uFF09",
9368
+ opt_password: "\u76F4\u63A5\u5E36\u5165\u65B0\u5BC6\u78BC\uFF08\u6703\u7559\u5728 shell \u6B77\u53F2\u8207\u884C\u7A0B\u5217\u8868\uFF09",
9369
+ opt_skip_test: "\u5B58\u6A94\u524D\u4E0D\u5148\u7528\u65B0\u5BC6\u78BC\u9023\u7DDA\u9A57\u8B49",
9370
+ prompt: "\u9023\u7DDA '{name}' \u7684\u65B0\u5BC6\u78BC",
9371
+ source_conflict: "--password \u8207 --stdin \u53EA\u80FD\u64C7\u4E00\u3002",
9372
+ needs_source: "\u6C92\u6709\u7D42\u7AEF\u6A5F\u53EF\u505A\u906E\u853D\u8F38\u5165\uFF0C\u8ACB\u6539\u7528 --stdin \u6216 --password \u50B3\u5165\u3002",
9373
+ empty: "\u65B0\u5BC6\u78BC\u662F\u7A7A\u7684\uFF0C\u672A\u505A\u4EFB\u4F55\u8B8A\u66F4\u3002",
9374
+ updated: "\u5DF2\u66F4\u65B0\u9023\u7DDA '{name}' \u7684\u5BC6\u78BC \u2192 {envFile}\uFF08{varName}\uFF09",
9375
+ converted: 'config.json \u88E1\u7684\u660E\u6587\u5BC6\u78BC\u5DF2\u6539\u6210 {{ "$env": "{varName}" }} \u53C3\u7167\uFF0C\u4E4B\u5F8C\u8F2A\u66FF\u53EA\u6703\u52D5 env \u6A94\u3002',
9376
+ skipped_test: "\u5DF2\u8DF3\u904E\u9A57\u8B49\uFF08--skip-test\uFF09\uFF1A\u65B0\u5BC6\u78BC\u672A\u7D93\u8CC7\u6599\u5EAB\u78BA\u8A8D\u3002"
9345
9377
  }
9346
9378
  };
9347
9379
  });
@@ -9651,6 +9683,13 @@ async function select(message, choices) {
9651
9683
  return await selectFallback(message, choices);
9652
9684
  return await inquirer.select({ message, choices });
9653
9685
  }
9686
+ async function secret(message) {
9687
+ const inquirer = await loadInquirer();
9688
+ if (!inquirer) {
9689
+ throw new Error("Masked input is unavailable; pass the value with --stdin or --password instead.");
9690
+ }
9691
+ return await inquirer.password({ message, mask: "*" });
9692
+ }
9654
9693
  async function confirm(message) {
9655
9694
  if (!process.stdin.isTTY)
9656
9695
  return await confirmFallback(message);
@@ -9664,7 +9703,8 @@ var init_prompts = __esm(() => {
9664
9703
  promptUser = {
9665
9704
  text,
9666
9705
  select,
9667
- confirm
9706
+ confirm,
9707
+ secret
9668
9708
  };
9669
9709
  });
9670
9710
 
@@ -45685,6 +45725,258 @@ var init_use = __esm(() => {
45685
45725
  });
45686
45726
  });
45687
45727
 
45728
+ // src/core/config-v2-mutations.ts
45729
+ function envVarNameFor(connName, field) {
45730
+ const slug = connName.toUpperCase().replace(/[^A-Z0-9]+/g, "_").replace(/^_+|_+$/g, "");
45731
+ return `DBCLI_${slug}_${field.toUpperCase()}`;
45732
+ }
45733
+ var init_config_v2_mutations = () => {};
45734
+
45735
+ // src/core/env-file-writer.ts
45736
+ import { chmod as chmod2, mkdir as mkdir18, readFile as readFile9, writeFile as writeFile9 } from "fs/promises";
45737
+ import { dirname as dirname16 } from "path";
45738
+ function escapeForRegExp(value) {
45739
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
45740
+ }
45741
+ async function upsertEnvVar(envPath, varName, value) {
45742
+ let content = "";
45743
+ try {
45744
+ content = await readFile9(envPath, "utf8");
45745
+ } catch (cause) {
45746
+ const code = cause.code;
45747
+ if (code !== "ENOENT")
45748
+ throw cause;
45749
+ await mkdir18(dirname16(envPath), { recursive: true });
45750
+ }
45751
+ const line = `${varName}="${value}"`;
45752
+ const existing = new RegExp(`^${escapeForRegExp(varName)}=.*$`, "m");
45753
+ if (existing.test(content)) {
45754
+ content = content.replace(existing, () => line);
45755
+ } else {
45756
+ content = content.length && !content.endsWith(`
45757
+ `) ? `${content}
45758
+ ${line}
45759
+ ` : `${content}${line}
45760
+ `;
45761
+ }
45762
+ await writeFile9(envPath, content, { mode: SECRET_FILE_MODE });
45763
+ await chmod2(envPath, SECRET_FILE_MODE);
45764
+ }
45765
+ var SECRET_FILE_MODE = 384;
45766
+ var init_env_file_writer = () => {};
45767
+
45768
+ // src/core/connection-credential.ts
45769
+ import { join as join39 } from "path";
45770
+ async function readRawConfig(storagePath) {
45771
+ const configPath = join39(storagePath, "config.json");
45772
+ const file = Bun.file(configPath);
45773
+ if (!await file.exists()) {
45774
+ throw new ConfigError(`\u627E\u4E0D\u5230\u8A2D\u5B9A\u6A94\uFF1A${configPath}`);
45775
+ }
45776
+ return JSON.parse(await file.text());
45777
+ }
45778
+ function envRefName(value) {
45779
+ if (typeof value === "object" && value !== null && "$env" in value) {
45780
+ return String(value.$env);
45781
+ }
45782
+ return;
45783
+ }
45784
+ async function resolvePasswordTarget(projectPath, connectionName) {
45785
+ const storagePath = await resolveConfigStoragePath(projectPath);
45786
+ const raw = await readRawConfig(storagePath);
45787
+ if (detectConfigVersion(raw) !== 2) {
45788
+ if (connectionName && connectionName !== V1_CONNECTION_NAME) {
45789
+ throw new ConfigError(`\u9019\u662F v1 \u8A2D\u5B9A\uFF0C\u53EA\u6709\u4E00\u689D\u9023\u7DDA\uFF0C\u7121\u6CD5\u6307\u5B9A\u9023\u7DDA\u540D\u7A31 '${connectionName}'\u3002` + `\u9700\u8981\u591A\u9023\u7DDA\u8ACB\u5148\u7528 dbcli init --conn-name <name> \u5347\u7D1A\u5230 v2\u3002`);
45790
+ }
45791
+ const connection2 = raw.connection ?? {};
45792
+ const customRef = envRefName(connection2.password);
45793
+ if (customRef !== undefined && customRef !== V1_VAR_NAME) {
45794
+ throw new ConfigError(`\u9019\u500B v1 \u8A2D\u5B9A\u7684\u5BC6\u78BC\u4F86\u81EA\u74B0\u5883\u8B8A\u6578 '${customRef}'\uFF0Cdbcli \u7121\u6CD5\u4EE3\u70BA\u8F2A\u66FF\u3002` + `\u8ACB\u76F4\u63A5\u66F4\u65B0\u8A72\u74B0\u5883\u8B8A\u6578\uFF0C\u6216\u7528 dbcli init --conn-name <name> \u5347\u7D1A\u5230 v2 \u5F8C\u518D\u8F2A\u66FF\u3002`);
45795
+ }
45796
+ return {
45797
+ connection: V1_CONNECTION_NAME,
45798
+ envFile: DEFAULT_ENV_FILE,
45799
+ varName: V1_VAR_NAME,
45800
+ convertedToEnvRef: false
45801
+ };
45802
+ }
45803
+ const config = await readV2Config(projectPath);
45804
+ const targetName = connectionName ?? config.default;
45805
+ const connection = config.connections[targetName];
45806
+ if (!connection) {
45807
+ throw new ConfigError(connectionNotFoundMessage(targetName, Object.keys(config.connections)));
45808
+ }
45809
+ const referencedVar = envRefName(connection.password);
45810
+ return {
45811
+ connection: targetName,
45812
+ envFile: connection.envFile ?? DEFAULT_ENV_FILE,
45813
+ varName: referencedVar ?? envVarNameFor(targetName, "password"),
45814
+ convertedToEnvRef: referencedVar === undefined
45815
+ };
45816
+ }
45817
+ function assertSingleLine(value) {
45818
+ if (value.includes(`
45819
+ `) || value.includes("\r")) {
45820
+ throw new ConfigError("\u5BC6\u78BC\u4E0D\u53EF\u5305\u542B\u63DB\u884C\u5B57\u5143");
45821
+ }
45822
+ }
45823
+ async function stripV1LiteralPassword(storagePath, raw) {
45824
+ const connection = raw.connection ?? {};
45825
+ if (typeof connection.password !== "string")
45826
+ return;
45827
+ const stripped = { ...raw, connection: { ...connection } };
45828
+ delete stripped.connection.password;
45829
+ await writeConfigWithIntegrity(storagePath, JSON.stringify(stripped, null, 2));
45830
+ }
45831
+ async function setConnectionPassword(projectPath, connectionName, password) {
45832
+ assertConfigMutationApproved();
45833
+ assertSingleLine(password);
45834
+ const target = await resolvePasswordTarget(projectPath, connectionName);
45835
+ const storagePath = await resolveConfigStoragePath(projectPath);
45836
+ const raw = await readRawConfig(storagePath);
45837
+ await upsertEnvVar(join39(storagePath, target.envFile), target.varName, password);
45838
+ if (detectConfigVersion(raw) !== 2) {
45839
+ await stripV1LiteralPassword(storagePath, raw);
45840
+ return target;
45841
+ }
45842
+ const config = await readV2Config(projectPath);
45843
+ const connection = config.connections[target.connection];
45844
+ const needsEnvFile = connection.envFile === undefined;
45845
+ if (target.convertedToEnvRef || needsEnvFile) {
45846
+ await writeV2Config(projectPath, {
45847
+ ...config,
45848
+ connections: {
45849
+ ...config.connections,
45850
+ [target.connection]: {
45851
+ ...connection,
45852
+ envFile: target.envFile,
45853
+ ...target.convertedToEnvRef && { password: { $env: target.varName } }
45854
+ }
45855
+ }
45856
+ });
45857
+ }
45858
+ return target;
45859
+ }
45860
+ var DEFAULT_ENV_FILE = ".env.local", V1_VAR_NAME = "DBCLI_PASSWORD", V1_CONNECTION_NAME = "default";
45861
+ var init_connection_credential = __esm(() => {
45862
+ init_config_binding();
45863
+ init_config_v2();
45864
+ init_config_integrity();
45865
+ init_config_mutation_guard();
45866
+ init_config_v2_mutations();
45867
+ init_errors3();
45868
+ init_env_file_writer();
45869
+ });
45870
+
45871
+ // src/commands/credential.ts
45872
+ var exports_credential = {};
45873
+ __export(exports_credential, {
45874
+ resolveNewPassword: () => resolveNewPassword,
45875
+ passwordCommand: () => passwordCommand
45876
+ });
45877
+ async function readAllStdin() {
45878
+ return await Bun.stdin.text();
45879
+ }
45880
+ async function resolveNewPassword(options, io) {
45881
+ if (options.password !== undefined && options.stdin) {
45882
+ throw new ConfigError(t("password.source_conflict"));
45883
+ }
45884
+ let value;
45885
+ if (options.password !== undefined) {
45886
+ value = options.password;
45887
+ } else if (options.stdin) {
45888
+ value = (await io.readStdin()).replace(/\r?\n$/, "");
45889
+ } else if (io.isTTY) {
45890
+ value = await io.prompt();
45891
+ } else {
45892
+ throw new ConfigError(t("password.needs_source"));
45893
+ }
45894
+ if (value.length === 0) {
45895
+ throw new ConfigError(t("password.empty"));
45896
+ }
45897
+ return value;
45898
+ }
45899
+ async function verifyNewPassword(configPath, target, connectionName, password) {
45900
+ const storagePath = await resolveConfigStoragePath(configPath);
45901
+ const previous = process.env[target.varName];
45902
+ process.env[target.varName] = password;
45903
+ try {
45904
+ const config = await configModule.read(storagePath, connectionName);
45905
+ const adapter = AdapterFactory.createAdapter({
45906
+ ...config.connection,
45907
+ password
45908
+ });
45909
+ try {
45910
+ await adapter.connect();
45911
+ await adapter.testConnection();
45912
+ } finally {
45913
+ await adapter.disconnect().catch(() => {
45914
+ return;
45915
+ });
45916
+ }
45917
+ } finally {
45918
+ if (previous === undefined)
45919
+ delete process.env[target.varName];
45920
+ else
45921
+ process.env[target.varName] = previous;
45922
+ }
45923
+ }
45924
+ var passwordCommand;
45925
+ var init_credential = __esm(() => {
45926
+ init_esm();
45927
+ init_adapters();
45928
+ init_config();
45929
+ init_config_mutation_guard();
45930
+ init_config_binding();
45931
+ init_connection_credential();
45932
+ init_config_path();
45933
+ init_prompts();
45934
+ init_errors3();
45935
+ init_message_loader();
45936
+ passwordCommand = new Command("password").description(t("password.description")).argument("[connection]", t("password.arg_connection")).option("--stdin", t("password.opt_stdin")).option("--password <value>", t("password.opt_password")).option("--skip-test", t("password.opt_skip_test")).option("--format <format>", "Output format (text, json)", "text").action(async (connection, options) => {
45937
+ try {
45938
+ assertConfigMutationApproved();
45939
+ const configPath = resolveConfigPath(passwordCommand);
45940
+ const target = await resolvePasswordTarget(configPath, connection);
45941
+ const value = await resolveNewPassword({
45942
+ password: typeof options.password === "string" ? options.password : undefined,
45943
+ stdin: options.stdin === true
45944
+ }, {
45945
+ isTTY: Boolean(process.stdin.isTTY),
45946
+ readStdin: readAllStdin,
45947
+ prompt: () => promptUser.secret(t_vars("password.prompt", { name: target.connection }))
45948
+ });
45949
+ if (options.skipTest !== true) {
45950
+ await verifyNewPassword(configPath, target, connection, value);
45951
+ }
45952
+ const written = await setConnectionPassword(configPath, connection, value);
45953
+ if (options.format === "json") {
45954
+ console.log(JSON.stringify({ success: true, ...written }, null, 2));
45955
+ } else {
45956
+ console.log(t_vars("password.updated", {
45957
+ name: written.connection,
45958
+ envFile: written.envFile,
45959
+ varName: written.varName
45960
+ }));
45961
+ if (written.convertedToEnvRef) {
45962
+ console.log(t_vars("password.converted", { varName: written.varName }));
45963
+ }
45964
+ if (options.skipTest === true) {
45965
+ console.log(t("password.skipped_test"));
45966
+ }
45967
+ }
45968
+ } catch (error) {
45969
+ const message = error instanceof Error ? error.message : String(error);
45970
+ if (options.format === "json") {
45971
+ console.error(JSON.stringify({ success: false, error: message }, null, 2));
45972
+ } else {
45973
+ console.error(t_vars("errors.message", { message }));
45974
+ }
45975
+ process.exit(1);
45976
+ }
45977
+ });
45978
+ });
45979
+
45688
45980
  // src/proxy/relay.ts
45689
45981
  class TcpRelay {
45690
45982
  clientBytes = 0;
@@ -45759,8 +46051,8 @@ var init_sql_metadata = __esm(() => {
45759
46051
  });
45760
46052
 
45761
46053
  // src/proxy/events.ts
45762
- import { appendFile as appendFile2, mkdir as mkdir18, readFile as readFile9, stat as stat9 } from "fs/promises";
45763
- import { dirname as dirname16 } from "path";
46054
+ import { appendFile as appendFile2, mkdir as mkdir19, readFile as readFile10, stat as stat9 } from "fs/promises";
46055
+ import { dirname as dirname17 } from "path";
45764
46056
  function hasSql(e) {
45765
46057
  return e.type === "query_observed" || e.type === "query_completed" || e.type === "query_errored";
45766
46058
  }
@@ -45799,7 +46091,7 @@ class EventWriter {
45799
46091
  }
45800
46092
  async writeInternal(event) {
45801
46093
  if (!this.dirEnsured) {
45802
- await mkdir18(dirname16(this.path), { recursive: true });
46094
+ await mkdir19(dirname17(this.path), { recursive: true });
45803
46095
  this.dirEnsured = true;
45804
46096
  }
45805
46097
  if (!this.initialized) {
@@ -45823,7 +46115,7 @@ class EventWriter {
45823
46115
  try {
45824
46116
  const s = await stat9(this.path);
45825
46117
  this.currentSizeBytes = s.size;
45826
- const raw = await readFile9(this.path, "utf8");
46118
+ const raw = await readFile10(this.path, "utf8");
45827
46119
  this.currentEntryCount = raw.split(`
45828
46120
  `).filter(Boolean).length;
45829
46121
  } catch {
@@ -46420,7 +46712,7 @@ var init_server = __esm(() => {
46420
46712
  });
46421
46713
 
46422
46714
  // src/proxy/event-reader.ts
46423
- import { readFile as readFile10 } from "fs/promises";
46715
+ import { readFile as readFile11 } from "fs/promises";
46424
46716
  async function readEvents(path4, opts) {
46425
46717
  const candidates = opts.includeRotated ? [path4, `${path4}.1`] : [path4];
46426
46718
  const files = [];
@@ -46429,7 +46721,7 @@ async function readEvents(path4, opts) {
46429
46721
  for (const file of candidates) {
46430
46722
  let raw;
46431
46723
  try {
46432
- raw = await readFile10(file, "utf8");
46724
+ raw = await readFile11(file, "utf8");
46433
46725
  } catch (err) {
46434
46726
  if (err.code !== "ENOENT")
46435
46727
  throw err;
@@ -46860,7 +47152,7 @@ __export(exports_proxy, {
46860
47152
  proxyCommand: () => proxyCommand,
46861
47153
  parseHostPort: () => parseHostPort
46862
47154
  });
46863
- import { join as join39 } from "path";
47155
+ import { join as join40 } from "path";
46864
47156
  function parseHostPort(value) {
46865
47157
  const idx = value.lastIndexOf(":");
46866
47158
  if (idx <= 0 || idx === value.length - 1) {
@@ -46923,7 +47215,7 @@ async function runProxy(subcommandEngine, options, command) {
46923
47215
  target: options.target,
46924
47216
  connection
46925
47217
  });
46926
- const eventsPath = options.events ?? join39(".dbcli", "proxy", "events.jsonl");
47218
+ const eventsPath = options.events ?? join40(".dbcli", "proxy", "events.jsonl");
46927
47219
  const slowMs = Number(options.slowMs ?? 1000);
46928
47220
  if (!Number.isFinite(slowMs) || slowMs < 0) {
46929
47221
  throw new Error(`Invalid --slow-ms "${options.slowMs}". Expected a non-negative number`);
@@ -46972,7 +47264,7 @@ async function runProxy(subcommandEngine, options, command) {
46972
47264
  }
46973
47265
  }
46974
47266
  function addCommonOptions(cmd) {
46975
- 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", join39(".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");
47267
+ 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", join40(".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");
46976
47268
  }
46977
47269
  function parseNonNegInt(value, flag, fallback) {
46978
47270
  if (value === undefined)
@@ -46990,7 +47282,7 @@ async function runAnalyze(options) {
46990
47282
  const top = parseNonNegInt(options.top, "top", 20);
46991
47283
  const slowMs = parseNonNegInt(options.slowMs, "slow-ms", 1000);
46992
47284
  const nPlusOne = parseNonNegInt(options.nPlusOne, "n-plus-one", 10);
46993
- const eventsPath = options.events ?? join39(".dbcli", "proxy", "events.jsonl");
47285
+ const eventsPath = options.events ?? join40(".dbcli", "proxy", "events.jsonl");
46994
47286
  const { events, malformedLines, files } = await readEvents(eventsPath, {
46995
47287
  includeRotated: options.includeRotated !== false
46996
47288
  });
@@ -47043,7 +47335,7 @@ var init_proxy = __esm(() => {
47043
47335
  });
47044
47336
  }
47045
47337
  ANALYZE_FORMATS = ["json", "text", "markdown"];
47046
- proxyCommand.command("analyze").description("Analyze a proxy event log offline (no DB connection)").option("--events <path>", "Event JSONL path", join39(".dbcli", "proxy", "events.jsonl")).option("--format <format>", "Output format: json | text | markdown (QueryLens)", "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) => {
47338
+ proxyCommand.command("analyze").description("Analyze a proxy event log offline (no DB connection)").option("--events <path>", "Event JSONL path", join40(".dbcli", "proxy", "events.jsonl")).option("--format <format>", "Output format: json | text | markdown (QueryLens)", "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) => {
47047
47339
  await runAnalyze(options);
47048
47340
  });
47049
47341
  addCommonOptions(proxyCommand).action(async (options, command) => {
@@ -47377,9 +47669,9 @@ var init_semantic2 = __esm(() => {
47377
47669
  });
47378
47670
 
47379
47671
  // src/core/design/index.ts
47380
- import { join as join40 } from "path";
47672
+ import { join as join41 } from "path";
47381
47673
  function defaultDesignFile(workspaceRoot) {
47382
- return join40(workspaceRoot, DEFAULT_FILE3);
47674
+ return join41(workspaceRoot, DEFAULT_FILE3);
47383
47675
  }
47384
47676
  function parseDesignSpec(raw, filePath = DEFAULT_FILE3) {
47385
47677
  const parsed = specSchema.safeParse(raw);
@@ -48210,8 +48502,8 @@ var exports_backfill = {};
48210
48502
  __export(exports_backfill, {
48211
48503
  backfillCommand: () => backfillCommand
48212
48504
  });
48213
- import { dirname as dirname17, resolve as resolve10 } from "path";
48214
- import { mkdir as mkdir19 } from "fs/promises";
48505
+ import { dirname as dirname18, resolve as resolve10 } from "path";
48506
+ import { mkdir as mkdir20 } from "fs/promises";
48215
48507
  function identityFor(config, name) {
48216
48508
  const connection = config.connections[name];
48217
48509
  if (!connection) {
@@ -48261,7 +48553,7 @@ var init_backfill = __esm(() => {
48261
48553
  return;
48262
48554
  }
48263
48555
  const out = resolve10(options.out ?? `.dbcli/backfills/${artifact2.source.sha256.slice(0, 12)}.json`);
48264
- await mkdir19(dirname17(out), { recursive: true });
48556
+ await mkdir20(dirname18(out), { recursive: true });
48265
48557
  await Bun.write(out, JSON.stringify(artifact2, null, 2) + `
48266
48558
  `);
48267
48559
  console.log(JSON.stringify({ path: out, artifact: artifact2 }, null, 2));
@@ -48270,8 +48562,8 @@ var init_backfill = __esm(() => {
48270
48562
 
48271
48563
  // src/core/evidence-pack/index.ts
48272
48564
  import { createHash as createHash8, randomUUID as randomUUID6 } from "crypto";
48273
- import { link as link3, lstat as lstat5, mkdir as mkdir20, realpath as realpath2, unlink as unlink8, writeFile as writeFile9 } from "fs/promises";
48274
- import { basename as basename9, dirname as dirname18, relative as relative5, resolve as resolve11, sep as sep7 } from "path";
48565
+ import { link as link3, lstat as lstat5, mkdir as mkdir21, realpath as realpath2, unlink as unlink8, writeFile as writeFile10 } from "fs/promises";
48566
+ import { basename as basename9, dirname as dirname19, relative as relative5, resolve as resolve11, sep as sep7 } from "path";
48275
48567
  function isRecord4(value) {
48276
48568
  return typeof value === "object" && value !== null && !Array.isArray(value);
48277
48569
  }
@@ -48522,7 +48814,7 @@ async function realExistingAncestor(path4) {
48522
48814
  } catch (error) {
48523
48815
  if (error.code !== "ENOENT")
48524
48816
  throw error;
48525
- const parent = dirname18(candidate);
48817
+ const parent = dirname19(candidate);
48526
48818
  if (parent === candidate)
48527
48819
  throw error;
48528
48820
  candidate = parent;
@@ -48534,12 +48826,12 @@ async function writeEvidencePack(workspaceRoot, outputPath, pack) {
48534
48826
  const requestedTarget = resolve11(workspace, outputPath);
48535
48827
  if (!isInside(workspace, requestedTarget))
48536
48828
  throw new EvidencePackValidationError("output path must stay inside the workspace");
48537
- const parent = dirname18(requestedTarget);
48829
+ const parent = dirname19(requestedTarget);
48538
48830
  const existingAncestor2 = await realExistingAncestor(parent);
48539
48831
  if (!isInside(workspace, existingAncestor2) && existingAncestor2 !== workspace) {
48540
48832
  throw new EvidencePackValidationError("output path resolves outside the workspace");
48541
48833
  }
48542
- await mkdir20(parent, { recursive: true });
48834
+ await mkdir21(parent, { recursive: true });
48543
48835
  const realParent = await realpath2(parent);
48544
48836
  if (!isInside(workspace, realParent) && realParent !== workspace) {
48545
48837
  throw new EvidencePackValidationError("output path resolves outside the workspace");
@@ -48556,7 +48848,7 @@ async function writeEvidencePack(workspaceRoot, outputPath, pack) {
48556
48848
  }
48557
48849
  const temp = resolve11(realParent, `.${basename9(target)}.${process.pid}.${randomUUID6()}.tmp`);
48558
48850
  try {
48559
- await writeFile9(temp, `${JSON.stringify(pack, null, 2)}
48851
+ await writeFile10(temp, `${JSON.stringify(pack, null, 2)}
48560
48852
  `, "utf8");
48561
48853
  try {
48562
48854
  await link3(temp, target);
@@ -48633,7 +48925,7 @@ var exports_evidence = {};
48633
48925
  __export(exports_evidence, {
48634
48926
  evidenceCommand: () => evidenceCommand
48635
48927
  });
48636
- import { join as join41, relative as relative6, resolve as resolve12, sep as sep8 } from "path";
48928
+ import { join as join42, relative as relative6, resolve as resolve12, sep as sep8 } from "path";
48637
48929
  import { realpath as realpath3 } from "fs/promises";
48638
48930
  import { createHash as createHash9 } from "crypto";
48639
48931
  function safeMessage(error) {
@@ -48709,7 +49001,7 @@ async function auditEntries(configPath, config) {
48709
49001
  throw new EvidencePackValidationError("audit evidence is disabled");
48710
49002
  const storagePath = await resolveConfigStoragePath(configPath);
48711
49003
  const connectionName = config.effectiveConnectionName || getGlobalConnectionName() || "default";
48712
- const file = join41(storagePath, ".dbcli", "audit", `${connectionName}.jsonl`);
49004
+ const file = join42(storagePath, ".dbcli", "audit", `${connectionName}.jsonl`);
48713
49005
  return { connectionName, entries: await readEntries(file, { include_rotated: true }) };
48714
49006
  }
48715
49007
  function auditReference(entry, connectionName) {
@@ -50073,8 +50365,8 @@ __export(exports_impact, {
50073
50365
  impactCommand: () => impactCommand
50074
50366
  });
50075
50367
  import { randomUUID as randomUUID7 } from "crypto";
50076
- import { link as link4, lstat as lstat8, mkdir as mkdir21, realpath as realpath5, unlink as unlink9, writeFile as writeFile10 } from "fs/promises";
50077
- import { basename as basename10, dirname as dirname19, relative as relative8, resolve as resolve14, sep as sep10 } from "path";
50368
+ import { link as link4, lstat as lstat8, mkdir as mkdir22, realpath as realpath5, unlink as unlink9, writeFile as writeFile11 } from "fs/promises";
50369
+ import { basename as basename10, dirname as dirname20, relative as relative8, resolve as resolve14, sep as sep10 } from "path";
50078
50370
  function collectOption3(value, previous) {
50079
50371
  return [...previous, value];
50080
50372
  }
@@ -50278,7 +50570,7 @@ async function realExistingAncestor2(path4) {
50278
50570
  } catch (error) {
50279
50571
  if (error.code !== "ENOENT")
50280
50572
  throw error;
50281
- const parent = dirname19(candidate);
50573
+ const parent = dirname20(candidate);
50282
50574
  if (parent === candidate)
50283
50575
  throw error;
50284
50576
  candidate = parent;
@@ -50290,11 +50582,11 @@ async function resolveOutput(workspaceRoot, outputPath) {
50290
50582
  const target = resolve14(workspace, outputPath);
50291
50583
  if (!isInside2(workspace, target))
50292
50584
  throw new Error("output path must stay inside the workspace");
50293
- const parent = dirname19(target);
50585
+ const parent = dirname20(target);
50294
50586
  const existingAncestor2 = await realExistingAncestor2(parent);
50295
50587
  if (!isInside2(workspace, existingAncestor2) && existingAncestor2 !== workspace)
50296
50588
  throw new Error("output path must stay inside the workspace");
50297
- await mkdir21(parent, { recursive: true });
50589
+ await mkdir22(parent, { recursive: true });
50298
50590
  const realParent = await realpath5(parent);
50299
50591
  if (!isInside2(workspace, realParent) && realParent !== workspace)
50300
50592
  throw new Error("output path must stay inside the workspace");
@@ -50302,7 +50594,7 @@ async function resolveOutput(workspaceRoot, outputPath) {
50302
50594
  }
50303
50595
  async function assertOutputParent(workspaceRoot, path4) {
50304
50596
  const workspace = await realpath5(workspaceRoot);
50305
- const parent = await realpath5(dirname19(path4));
50597
+ const parent = await realpath5(dirname20(path4));
50306
50598
  if (!isInside2(workspace, parent) && parent !== workspace) {
50307
50599
  throw new Error("output path must stay inside the workspace");
50308
50600
  }
@@ -50316,9 +50608,9 @@ async function writeOutput(workspaceRoot, path4, content) {
50316
50608
  if (error.code !== "ENOENT")
50317
50609
  throw error;
50318
50610
  }
50319
- const temp = resolve14(dirname19(path4), `.${basename10(path4)}.${process.pid}.${randomUUID7()}.tmp`);
50611
+ const temp = resolve14(dirname20(path4), `.${basename10(path4)}.${process.pid}.${randomUUID7()}.tmp`);
50320
50612
  try {
50321
- await writeFile10(temp, content, "utf8");
50613
+ await writeFile11(temp, content, "utf8");
50322
50614
  await assertOutputParent(workspaceRoot, path4);
50323
50615
  await link4(temp, path4);
50324
50616
  } catch (error) {
@@ -50457,6 +50749,7 @@ function buildProgram() {
50457
50749
  program2.addCommand(shellCommand);
50458
50750
  program2.addCommand(migrateCommand);
50459
50751
  program2.addCommand(useCommand);
50752
+ program2.addCommand(passwordCommand);
50460
50753
  program2.addCommand(queriesCommand);
50461
50754
  program2.addCommand(explainCommand);
50462
50755
  program2.addCommand(lintCommand);
@@ -50510,6 +50803,7 @@ var init_program = __esm(() => {
50510
50803
  init_shell3();
50511
50804
  init_migrate();
50512
50805
  init_use();
50806
+ init_credential();
50513
50807
  init_proxy();
50514
50808
  init_semantic2();
50515
50809
  init_design2();
@@ -50533,9 +50827,9 @@ __export(exports_completion, {
50533
50827
  detectShell: () => detectShell,
50534
50828
  completionCommand: () => completionCommand
50535
50829
  });
50536
- import { join as join42 } from "path";
50830
+ import { join as join43 } from "path";
50537
50831
  import { homedir as homedir4 } from "os";
50538
- import { mkdir as mkdir22 } from "fs/promises";
50832
+ import { mkdir as mkdir23 } from "fs/promises";
50539
50833
  function resolveHome() {
50540
50834
  return process.env.HOME ?? homedir4();
50541
50835
  }
@@ -50785,11 +51079,11 @@ function getInstallPath2(shell) {
50785
51079
  const home = resolveHome();
50786
51080
  switch (shell) {
50787
51081
  case "bash":
50788
- return join42(home, ".bashrc");
51082
+ return join43(home, ".bashrc");
50789
51083
  case "zsh":
50790
- return join42(home, ".zshrc");
51084
+ return join43(home, ".zshrc");
50791
51085
  case "fish":
50792
- return join42(home, ".config", "fish", "completions", "dbcli.fish");
51086
+ return join43(home, ".config", "fish", "completions", "dbcli.fish");
50793
51087
  default:
50794
51088
  throw new Error(`Unsupported shell: ${shell}. Supported: bash, zsh, fish`);
50795
51089
  }
@@ -50807,8 +51101,8 @@ function detectShell() {
50807
51101
  async function installCompletion(shell, script) {
50808
51102
  const targetPath = getInstallPath2(shell);
50809
51103
  if (shell === "fish") {
50810
- const dir = join42(resolveHome(), ".config", "fish", "completions");
50811
- await mkdir22(dir, { recursive: true });
51104
+ const dir = join43(resolveHome(), ".config", "fish", "completions");
51105
+ await mkdir23(dir, { recursive: true });
50812
51106
  await Bun.file(targetPath).write(script);
50813
51107
  console.log(colors.success(`\u2713 Fish completion installed to ${targetPath}`));
50814
51108
  return;
@@ -51147,6 +51441,12 @@ var COMMAND_LOADERS = {
51147
51441
  program2.addCommand(migrateCommand2);
51148
51442
  };
51149
51443
  },
51444
+ password: async () => {
51445
+ const { passwordCommand: passwordCommand2 } = await Promise.resolve().then(() => (init_credential(), exports_credential));
51446
+ return (program2) => {
51447
+ program2.addCommand(passwordCommand2);
51448
+ };
51449
+ },
51150
51450
  use: async () => {
51151
51451
  const { useCommand: useCommand2 } = await Promise.resolve().then(() => (init_use(), exports_use));
51152
51452
  return (program2) => {
@@ -51287,7 +51587,7 @@ async function buildProgramFor(argv) {
51287
51587
 
51288
51588
  // src/cli-runtime.ts
51289
51589
  init_cli_error();
51290
- import { join as join43 } from "path";
51590
+ import { join as join44 } from "path";
51291
51591
  import { writeSync as writeSync2 } from "fs";
51292
51592
  import { format } from "util";
51293
51593
  function installSynchronousRedirectedStdout() {
@@ -51425,7 +51725,7 @@ program2.hook("preAction", (thisCommand, actionCommand) => {
51425
51725
  try {
51426
51726
  let cache = null;
51427
51727
  try {
51428
- const cacheFile = Bun.file(join43(configPath, "version-check.json"));
51728
+ const cacheFile = Bun.file(join44(configPath, "version-check.json"));
51429
51729
  if (await cacheFile.exists()) {
51430
51730
  cache = await cacheFile.json();
51431
51731
  }
package/dist/cli.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  // package.json
4
4
  var package_default = {
5
5
  name: "@carllee1983/dbcli",
6
- version: "1.56.0",
6
+ version: "1.57.0",
7
7
  description: "Database CLI for AI agents",
8
8
  type: "module",
9
9
  publishConfig: {