@carllee1983/dbcli 0.4.0-beta → 0.5.2-beta

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
@@ -2064,6 +2064,76 @@ var require_commander = __commonJS((exports) => {
2064
2064
  exports.InvalidOptionArgumentError = InvalidArgumentError;
2065
2065
  });
2066
2066
 
2067
+ // node_modules/picocolors/picocolors.js
2068
+ var require_picocolors = __commonJS((exports, module) => {
2069
+ var p = process || {};
2070
+ var argv = p.argv || [];
2071
+ var env = p.env || {};
2072
+ var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
2073
+ var formatter = (open, close, replace = open) => (input) => {
2074
+ let string = "" + input, index = string.indexOf(close, open.length);
2075
+ return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
2076
+ };
2077
+ var replaceClose = (string, close, replace, index) => {
2078
+ let result = "", cursor = 0;
2079
+ do {
2080
+ result += string.substring(cursor, index) + replace;
2081
+ cursor = index + close.length;
2082
+ index = string.indexOf(close, cursor);
2083
+ } while (~index);
2084
+ return result + string.substring(cursor);
2085
+ };
2086
+ var createColors = (enabled = isColorSupported) => {
2087
+ let f = enabled ? formatter : () => String;
2088
+ return {
2089
+ isColorSupported: enabled,
2090
+ reset: f("\x1B[0m", "\x1B[0m"),
2091
+ bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
2092
+ dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
2093
+ italic: f("\x1B[3m", "\x1B[23m"),
2094
+ underline: f("\x1B[4m", "\x1B[24m"),
2095
+ inverse: f("\x1B[7m", "\x1B[27m"),
2096
+ hidden: f("\x1B[8m", "\x1B[28m"),
2097
+ strikethrough: f("\x1B[9m", "\x1B[29m"),
2098
+ black: f("\x1B[30m", "\x1B[39m"),
2099
+ red: f("\x1B[31m", "\x1B[39m"),
2100
+ green: f("\x1B[32m", "\x1B[39m"),
2101
+ yellow: f("\x1B[33m", "\x1B[39m"),
2102
+ blue: f("\x1B[34m", "\x1B[39m"),
2103
+ magenta: f("\x1B[35m", "\x1B[39m"),
2104
+ cyan: f("\x1B[36m", "\x1B[39m"),
2105
+ white: f("\x1B[37m", "\x1B[39m"),
2106
+ gray: f("\x1B[90m", "\x1B[39m"),
2107
+ bgBlack: f("\x1B[40m", "\x1B[49m"),
2108
+ bgRed: f("\x1B[41m", "\x1B[49m"),
2109
+ bgGreen: f("\x1B[42m", "\x1B[49m"),
2110
+ bgYellow: f("\x1B[43m", "\x1B[49m"),
2111
+ bgBlue: f("\x1B[44m", "\x1B[49m"),
2112
+ bgMagenta: f("\x1B[45m", "\x1B[49m"),
2113
+ bgCyan: f("\x1B[46m", "\x1B[49m"),
2114
+ bgWhite: f("\x1B[47m", "\x1B[49m"),
2115
+ blackBright: f("\x1B[90m", "\x1B[39m"),
2116
+ redBright: f("\x1B[91m", "\x1B[39m"),
2117
+ greenBright: f("\x1B[92m", "\x1B[39m"),
2118
+ yellowBright: f("\x1B[93m", "\x1B[39m"),
2119
+ blueBright: f("\x1B[94m", "\x1B[39m"),
2120
+ magentaBright: f("\x1B[95m", "\x1B[39m"),
2121
+ cyanBright: f("\x1B[96m", "\x1B[39m"),
2122
+ whiteBright: f("\x1B[97m", "\x1B[39m"),
2123
+ bgBlackBright: f("\x1B[100m", "\x1B[49m"),
2124
+ bgRedBright: f("\x1B[101m", "\x1B[49m"),
2125
+ bgGreenBright: f("\x1B[102m", "\x1B[49m"),
2126
+ bgYellowBright: f("\x1B[103m", "\x1B[49m"),
2127
+ bgBlueBright: f("\x1B[104m", "\x1B[49m"),
2128
+ bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
2129
+ bgCyanBright: f("\x1B[106m", "\x1B[49m"),
2130
+ bgWhiteBright: f("\x1B[107m", "\x1B[49m")
2131
+ };
2132
+ };
2133
+ module.exports = createColors();
2134
+ module.exports.createColors = createColors;
2135
+ });
2136
+
2067
2137
  // node_modules/@inquirer/core/dist/esm/lib/key.mjs
2068
2138
  var isUpKey = (key) => key.name === "up" || key.name === "k" || key.ctrl && key.name === "p", isDownKey = (key) => key.name === "down" || key.name === "j" || key.ctrl && key.name === "n", isSpaceKey = (key) => key.name === "space", isBackspaceKey = (key) => key.name === "backspace", isNumberKey = (key) => "123456789".includes(key.name), isEnterKey = (key) => key.name === "enter" || key.name === "return";
2069
2139
 
@@ -2267,49 +2337,49 @@ var require_yoctocolors_cjs = __commonJS((exports, module) => {
2267
2337
  return result;
2268
2338
  };
2269
2339
  };
2270
- var colors = {};
2271
- colors.reset = format(0, 0);
2272
- colors.bold = format(1, 22);
2273
- colors.dim = format(2, 22);
2274
- colors.italic = format(3, 23);
2275
- colors.underline = format(4, 24);
2276
- colors.overline = format(53, 55);
2277
- colors.inverse = format(7, 27);
2278
- colors.hidden = format(8, 28);
2279
- colors.strikethrough = format(9, 29);
2280
- colors.black = format(30, 39);
2281
- colors.red = format(31, 39);
2282
- colors.green = format(32, 39);
2283
- colors.yellow = format(33, 39);
2284
- colors.blue = format(34, 39);
2285
- colors.magenta = format(35, 39);
2286
- colors.cyan = format(36, 39);
2287
- colors.white = format(37, 39);
2288
- colors.gray = format(90, 39);
2289
- colors.bgBlack = format(40, 49);
2290
- colors.bgRed = format(41, 49);
2291
- colors.bgGreen = format(42, 49);
2292
- colors.bgYellow = format(43, 49);
2293
- colors.bgBlue = format(44, 49);
2294
- colors.bgMagenta = format(45, 49);
2295
- colors.bgCyan = format(46, 49);
2296
- colors.bgWhite = format(47, 49);
2297
- colors.bgGray = format(100, 49);
2298
- colors.redBright = format(91, 39);
2299
- colors.greenBright = format(92, 39);
2300
- colors.yellowBright = format(93, 39);
2301
- colors.blueBright = format(94, 39);
2302
- colors.magentaBright = format(95, 39);
2303
- colors.cyanBright = format(96, 39);
2304
- colors.whiteBright = format(97, 39);
2305
- colors.bgRedBright = format(101, 49);
2306
- colors.bgGreenBright = format(102, 49);
2307
- colors.bgYellowBright = format(103, 49);
2308
- colors.bgBlueBright = format(104, 49);
2309
- colors.bgMagentaBright = format(105, 49);
2310
- colors.bgCyanBright = format(106, 49);
2311
- colors.bgWhiteBright = format(107, 49);
2312
- module.exports = colors;
2340
+ var colors2 = {};
2341
+ colors2.reset = format(0, 0);
2342
+ colors2.bold = format(1, 22);
2343
+ colors2.dim = format(2, 22);
2344
+ colors2.italic = format(3, 23);
2345
+ colors2.underline = format(4, 24);
2346
+ colors2.overline = format(53, 55);
2347
+ colors2.inverse = format(7, 27);
2348
+ colors2.hidden = format(8, 28);
2349
+ colors2.strikethrough = format(9, 29);
2350
+ colors2.black = format(30, 39);
2351
+ colors2.red = format(31, 39);
2352
+ colors2.green = format(32, 39);
2353
+ colors2.yellow = format(33, 39);
2354
+ colors2.blue = format(34, 39);
2355
+ colors2.magenta = format(35, 39);
2356
+ colors2.cyan = format(36, 39);
2357
+ colors2.white = format(37, 39);
2358
+ colors2.gray = format(90, 39);
2359
+ colors2.bgBlack = format(40, 49);
2360
+ colors2.bgRed = format(41, 49);
2361
+ colors2.bgGreen = format(42, 49);
2362
+ colors2.bgYellow = format(43, 49);
2363
+ colors2.bgBlue = format(44, 49);
2364
+ colors2.bgMagenta = format(45, 49);
2365
+ colors2.bgCyan = format(46, 49);
2366
+ colors2.bgWhite = format(47, 49);
2367
+ colors2.bgGray = format(100, 49);
2368
+ colors2.redBright = format(91, 39);
2369
+ colors2.greenBright = format(92, 39);
2370
+ colors2.yellowBright = format(93, 39);
2371
+ colors2.blueBright = format(94, 39);
2372
+ colors2.magentaBright = format(95, 39);
2373
+ colors2.cyanBright = format(96, 39);
2374
+ colors2.whiteBright = format(97, 39);
2375
+ colors2.bgRedBright = format(101, 49);
2376
+ colors2.bgGreenBright = format(102, 49);
2377
+ colors2.bgYellowBright = format(103, 49);
2378
+ colors2.bgBlueBright = format(104, 49);
2379
+ colors2.bgMagentaBright = format(105, 49);
2380
+ colors2.bgCyanBright = format(106, 49);
2381
+ colors2.bgWhiteBright = format(107, 49);
2382
+ module.exports = colors2;
2313
2383
  });
2314
2384
 
2315
2385
  // node_modules/@inquirer/figures/dist/esm/index.js
@@ -41827,17 +41897,17 @@ var require_zalgo = __commonJS((exports, module) => {
41827
41897
 
41828
41898
  // node_modules/@colors/colors/lib/maps/america.js
41829
41899
  var require_america = __commonJS((exports, module) => {
41830
- module["exports"] = function(colors8) {
41900
+ module["exports"] = function(colors9) {
41831
41901
  return function(letter, i, exploded) {
41832
41902
  if (letter === " ")
41833
41903
  return letter;
41834
41904
  switch (i % 3) {
41835
41905
  case 0:
41836
- return colors8.red(letter);
41906
+ return colors9.red(letter);
41837
41907
  case 1:
41838
- return colors8.white(letter);
41908
+ return colors9.white(letter);
41839
41909
  case 2:
41840
- return colors8.blue(letter);
41910
+ return colors9.blue(letter);
41841
41911
  }
41842
41912
  };
41843
41913
  };
@@ -41845,22 +41915,22 @@ var require_america = __commonJS((exports, module) => {
41845
41915
 
41846
41916
  // node_modules/@colors/colors/lib/maps/zebra.js
41847
41917
  var require_zebra = __commonJS((exports, module) => {
41848
- module["exports"] = function(colors8) {
41918
+ module["exports"] = function(colors9) {
41849
41919
  return function(letter, i, exploded) {
41850
- return i % 2 === 0 ? letter : colors8.inverse(letter);
41920
+ return i % 2 === 0 ? letter : colors9.inverse(letter);
41851
41921
  };
41852
41922
  };
41853
41923
  });
41854
41924
 
41855
41925
  // node_modules/@colors/colors/lib/maps/rainbow.js
41856
41926
  var require_rainbow = __commonJS((exports, module) => {
41857
- module["exports"] = function(colors8) {
41927
+ module["exports"] = function(colors9) {
41858
41928
  var rainbowColors = ["red", "yellow", "green", "blue", "magenta"];
41859
41929
  return function(letter, i, exploded) {
41860
41930
  if (letter === " ") {
41861
41931
  return letter;
41862
41932
  } else {
41863
- return colors8[rainbowColors[i++ % rainbowColors.length]](letter);
41933
+ return colors9[rainbowColors[i++ % rainbowColors.length]](letter);
41864
41934
  }
41865
41935
  };
41866
41936
  };
@@ -41868,7 +41938,7 @@ var require_rainbow = __commonJS((exports, module) => {
41868
41938
 
41869
41939
  // node_modules/@colors/colors/lib/maps/random.js
41870
41940
  var require_random = __commonJS((exports, module) => {
41871
- module["exports"] = function(colors8) {
41941
+ module["exports"] = function(colors9) {
41872
41942
  var available = [
41873
41943
  "underline",
41874
41944
  "inverse",
@@ -41889,40 +41959,40 @@ var require_random = __commonJS((exports, module) => {
41889
41959
  "brightMagenta"
41890
41960
  ];
41891
41961
  return function(letter, i, exploded) {
41892
- return letter === " " ? letter : colors8[available[Math.round(Math.random() * (available.length - 2))]](letter);
41962
+ return letter === " " ? letter : colors9[available[Math.round(Math.random() * (available.length - 2))]](letter);
41893
41963
  };
41894
41964
  };
41895
41965
  });
41896
41966
 
41897
41967
  // node_modules/@colors/colors/lib/colors.js
41898
41968
  var require_colors = __commonJS((exports, module) => {
41899
- var colors8 = {};
41900
- module["exports"] = colors8;
41901
- colors8.themes = {};
41969
+ var colors9 = {};
41970
+ module["exports"] = colors9;
41971
+ colors9.themes = {};
41902
41972
  var util3 = __require("util");
41903
- var ansiStyles = colors8.styles = require_styles();
41973
+ var ansiStyles = colors9.styles = require_styles();
41904
41974
  var defineProps = Object.defineProperties;
41905
41975
  var newLineRegex = new RegExp(/[\r\n]+/g);
41906
- colors8.supportsColor = require_supports_colors().supportsColor;
41907
- if (typeof colors8.enabled === "undefined") {
41908
- colors8.enabled = colors8.supportsColor() !== false;
41976
+ colors9.supportsColor = require_supports_colors().supportsColor;
41977
+ if (typeof colors9.enabled === "undefined") {
41978
+ colors9.enabled = colors9.supportsColor() !== false;
41909
41979
  }
41910
- colors8.enable = function() {
41911
- colors8.enabled = true;
41980
+ colors9.enable = function() {
41981
+ colors9.enabled = true;
41912
41982
  };
41913
- colors8.disable = function() {
41914
- colors8.enabled = false;
41983
+ colors9.disable = function() {
41984
+ colors9.enabled = false;
41915
41985
  };
41916
- colors8.stripColors = colors8.strip = function(str) {
41986
+ colors9.stripColors = colors9.strip = function(str) {
41917
41987
  return ("" + str).replace(/\x1B\[\d+m/g, "");
41918
41988
  };
41919
- var stylize = colors8.stylize = function stylize2(str, style) {
41920
- if (!colors8.enabled) {
41989
+ var stylize = colors9.stylize = function stylize2(str, style) {
41990
+ if (!colors9.enabled) {
41921
41991
  return str + "";
41922
41992
  }
41923
41993
  var styleMap = ansiStyles[style];
41924
- if (!styleMap && style in colors8) {
41925
- return colors8[style](str);
41994
+ if (!styleMap && style in colors9) {
41995
+ return colors9[style](str);
41926
41996
  }
41927
41997
  return styleMap.open + str + styleMap.close;
41928
41998
  };
@@ -41954,7 +42024,7 @@ var require_colors = __commonJS((exports, module) => {
41954
42024
  });
41955
42025
  return ret;
41956
42026
  }();
41957
- var proto = defineProps(function colors9() {}, styles);
42027
+ var proto = defineProps(function colors10() {}, styles);
41958
42028
  function applyStyle() {
41959
42029
  var args = Array.prototype.slice.call(arguments);
41960
42030
  var str = args.map(function(arg) {
@@ -41964,7 +42034,7 @@ var require_colors = __commonJS((exports, module) => {
41964
42034
  return util3.inspect(arg);
41965
42035
  }
41966
42036
  }).join(" ");
41967
- if (!colors8.enabled || !str) {
42037
+ if (!colors9.enabled || !str) {
41968
42038
  return str;
41969
42039
  }
41970
42040
  var newLinesPresent = str.indexOf(`
@@ -41982,22 +42052,22 @@ var require_colors = __commonJS((exports, module) => {
41982
42052
  }
41983
42053
  return str;
41984
42054
  }
41985
- colors8.setTheme = function(theme) {
42055
+ colors9.setTheme = function(theme) {
41986
42056
  if (typeof theme === "string") {
41987
42057
  console.log("colors.setTheme now only accepts an object, not a string. " + "If you are trying to set a theme from a file, it is now your (the " + "caller's) responsibility to require the file. The old syntax " + "looked like colors.setTheme(__dirname + " + "'/../themes/generic-logging.js'); The new syntax looks like " + "colors.setTheme(require(__dirname + " + "'/../themes/generic-logging.js'));");
41988
42058
  return;
41989
42059
  }
41990
42060
  for (var style in theme) {
41991
42061
  (function(style2) {
41992
- colors8[style2] = function(str) {
42062
+ colors9[style2] = function(str) {
41993
42063
  if (typeof theme[style2] === "object") {
41994
42064
  var out = str;
41995
42065
  for (var i in theme[style2]) {
41996
- out = colors8[theme[style2][i]](out);
42066
+ out = colors9[theme[style2][i]](out);
41997
42067
  }
41998
42068
  return out;
41999
42069
  }
42000
- return colors8[theme[style2]](str);
42070
+ return colors9[theme[style2]](str);
42001
42071
  };
42002
42072
  })(style);
42003
42073
  }
@@ -42018,28 +42088,28 @@ var require_colors = __commonJS((exports, module) => {
42018
42088
  exploded = exploded.map(map2);
42019
42089
  return exploded.join("");
42020
42090
  };
42021
- colors8.trap = require_trap();
42022
- colors8.zalgo = require_zalgo();
42023
- colors8.maps = {};
42024
- colors8.maps.america = require_america()(colors8);
42025
- colors8.maps.zebra = require_zebra()(colors8);
42026
- colors8.maps.rainbow = require_rainbow()(colors8);
42027
- colors8.maps.random = require_random()(colors8);
42028
- for (map in colors8.maps) {
42091
+ colors9.trap = require_trap();
42092
+ colors9.zalgo = require_zalgo();
42093
+ colors9.maps = {};
42094
+ colors9.maps.america = require_america()(colors9);
42095
+ colors9.maps.zebra = require_zebra()(colors9);
42096
+ colors9.maps.rainbow = require_rainbow()(colors9);
42097
+ colors9.maps.random = require_random()(colors9);
42098
+ for (map in colors9.maps) {
42029
42099
  (function(map2) {
42030
- colors8[map2] = function(str) {
42031
- return sequencer(colors8.maps[map2], str);
42100
+ colors9[map2] = function(str) {
42101
+ return sequencer(colors9.maps[map2], str);
42032
42102
  };
42033
42103
  })(map);
42034
42104
  }
42035
42105
  var map;
42036
- defineProps(colors8, init());
42106
+ defineProps(colors9, init());
42037
42107
  });
42038
42108
 
42039
42109
  // node_modules/@colors/colors/safe.js
42040
42110
  var require_safe = __commonJS((exports, module) => {
42041
- var colors8 = require_colors();
42042
- module["exports"] = colors8;
42111
+ var colors9 = require_colors();
42112
+ module["exports"] = colors9;
42043
42113
  });
42044
42114
 
42045
42115
  // node_modules/cli-table3/src/cell.js
@@ -42209,11 +42279,11 @@ var require_cell = __commonJS((exports, module) => {
42209
42279
  wrapWithStyleColors(styleProperty, content) {
42210
42280
  if (this[styleProperty] && this[styleProperty].length) {
42211
42281
  try {
42212
- let colors8 = require_safe();
42282
+ let colors9 = require_safe();
42213
42283
  for (let i = this[styleProperty].length - 1;i >= 0; i--) {
42214
- colors8 = colors8[this[styleProperty][i]];
42284
+ colors9 = colors9[this[styleProperty][i]];
42215
42285
  }
42216
- return colors8(content);
42286
+ return colors9(content);
42217
42287
  } catch (e) {
42218
42288
  return content;
42219
42289
  }
@@ -42758,7 +42828,7 @@ var {
42758
42828
  // package.json
42759
42829
  var package_default = {
42760
42830
  name: "@carllee1983/dbcli",
42761
- version: "0.4.0-beta",
42831
+ version: "0.5.2-beta",
42762
42832
  description: "Database CLI for AI agents",
42763
42833
  type: "module",
42764
42834
  publishConfig: {
@@ -42767,6 +42837,27 @@ var package_default = {
42767
42837
  bin: {
42768
42838
  dbcli: "./dist/cli.mjs"
42769
42839
  },
42840
+ license: "MIT",
42841
+ author: "Carl Lee",
42842
+ repository: {
42843
+ type: "git",
42844
+ url: "git+https://github.com/CarlLee1983/dbcli.git"
42845
+ },
42846
+ homepage: "https://github.com/CarlLee1983/dbcli#readme",
42847
+ bugs: {
42848
+ url: "https://github.com/CarlLee1983/dbcli/issues"
42849
+ },
42850
+ keywords: [
42851
+ "database",
42852
+ "cli",
42853
+ "ai",
42854
+ "agent",
42855
+ "postgresql",
42856
+ "mysql",
42857
+ "mariadb",
42858
+ "permissions",
42859
+ "blacklist"
42860
+ ],
42770
42861
  engines: {
42771
42862
  node: ">=18.0.0",
42772
42863
  bun: ">=1.3.3"
@@ -42796,6 +42887,7 @@ var package_default = {
42796
42887
  dotenv: "^16.3.1",
42797
42888
  mysql2: "^3.20.0",
42798
42889
  pg: "^8.20.0",
42890
+ picocolors: "^1.1.1",
42799
42891
  zod: "^3.22.4"
42800
42892
  },
42801
42893
  devDependencies: {
@@ -42831,7 +42923,11 @@ var messages_default = {
42831
42923
  connection_failed: "\u2717 Database connection failed",
42832
42924
  config_saved: "Configuration saved to .dbcli",
42833
42925
  config_exists_overwrite: "Configuration file .dbcli already exists. Overwrite? (y/n): ",
42834
- cancelled: "Cancelled. Configuration not changed."
42926
+ cancelled: "Cancelled. Configuration not changed.",
42927
+ skip_test_env_ref: "Skipping connection test in env-ref mode",
42928
+ skip_test: "Skipping connection test (--skip-test)",
42929
+ connection_hints: "Hints:",
42930
+ config_exists_use_force: ".dbcli exists. Use --force option to overwrite."
42835
42931
  },
42836
42932
  schema: {
42837
42933
  description: "Retrieve table structure or list all tables",
@@ -42870,7 +42966,18 @@ var messages_default = {
42870
42966
  column_already_blacklisted: "Error: Column '{table}.{column}' is already blacklisted",
42871
42967
  column_not_in_blacklist: "Error: Column '{table}.{column}' is not in the blacklist",
42872
42968
  invalid_table_name: "Error: Invalid table name: {table}",
42873
- invalid_column_format: "Error: Invalid column format. Use 'table.column'"
42969
+ invalid_column_format: "Error: Invalid column format. Use 'table.column'",
42970
+ invalid_system: "Invalid database system: {system}",
42971
+ invalid_permission: "Invalid permission level: {permission}",
42972
+ invalid_port: "Invalid port: {port}",
42973
+ require_user: "Non-interactive mode requires --user option",
42974
+ require_name: "Non-interactive mode requires --name option",
42975
+ env_refs_missing_options: `When using --use-env-refs, environment variable names must be specified.
42976
+ Provide options: --env-host, --env-port, --env-user, --env-password, --env-database
42977
+ Or use interactive mode: run "dbcli init --use-env-refs" without --no-interactive`,
42978
+ env_var_not_defined: `Cannot test connection: environment variable {envKey} is not defined.
42979
+ Set {envKey} in .env or environment variables.
42980
+ Hint: run 'export {envKey}=<value>' and retry`
42874
42981
  },
42875
42982
  success: {
42876
42983
  inserted: "Successfully inserted {count} row(s)",
@@ -42920,6 +43027,11 @@ var messages_default = {
42920
43027
  },
42921
43028
  warnings: {
42922
43029
  blacklist_override_used: "Warning: Blacklist override enabled (DBCLI_OVERRIDE_BLACKLIST=true). Executing {operation} on blacklisted table '{table}'"
43030
+ },
43031
+ version: {
43032
+ unsupported_warning: "{system} {version} is below minimum supported version {minVersion}. Some features may not work correctly.",
43033
+ doctor_pass: "{system} {version} (meets >= {minVersion})",
43034
+ doctor_warn: "{system} {version} is below supported >= {minVersion}"
42923
43035
  }
42924
43036
  };
42925
43037
  // resources/lang/zh-TW/messages.json
@@ -42940,7 +43052,11 @@ var messages_default2 = {
42940
43052
  connection_failed: "\u2717 \u8CC7\u6599\u5EAB\u9023\u63A5\u5931\u6557",
42941
43053
  config_saved: "\u914D\u7F6E\u5DF2\u4FDD\u5B58\u81F3 .dbcli",
42942
43054
  config_exists_overwrite: "\u914D\u7F6E\u6A94\u6848 .dbcli \u5DF2\u5B58\u5728\u3002\u662F\u5426\u8986\u84CB\uFF1F (y/n)\uFF1A",
42943
- cancelled: "\u5DF2\u53D6\u6D88\u3002\u914D\u7F6E\u672A\u66F4\u6539\u3002"
43055
+ cancelled: "\u5DF2\u53D6\u6D88\u3002\u914D\u7F6E\u672A\u66F4\u6539\u3002",
43056
+ skip_test_env_ref: "\u8DF3\u904E\u9023\u7DDA\u6E2C\u8A66\uFF08\u74B0\u5883\u8B8A\u6578\u53C3\u7167\u6A21\u5F0F\uFF09",
43057
+ skip_test: "\u8DF3\u904E\u9023\u7DDA\u6E2C\u8A66\uFF08--skip-test\uFF09",
43058
+ connection_hints: "\u63D0\u793A\uFF1A",
43059
+ config_exists_use_force: ".dbcli \u5DF2\u5B58\u5728\u3002\u4F7F\u7528 --force \u9078\u9805\u8986\u84CB\u3002"
42944
43060
  },
42945
43061
  schema: {
42946
43062
  description: "\u6AA2\u7D22\u8868\u683C\u7D50\u69CB\u6216\u5217\u51FA\u6240\u6709\u8868\u683C",
@@ -42979,7 +43095,18 @@ var messages_default2 = {
42979
43095
  column_already_blacklisted: "\u932F\u8AA4: \u6B04\u4F4D '{table}.{column}' \u5DF2\u5728\u9ED1\u540D\u55AE\u4E2D",
42980
43096
  column_not_in_blacklist: "\u932F\u8AA4: \u6B04\u4F4D '{table}.{column}' \u4E0D\u5728\u9ED1\u540D\u55AE\u4E2D",
42981
43097
  invalid_table_name: "\u932F\u8AA4: \u7121\u6548\u7684\u8868\u683C\u540D\u7A31: {table}",
42982
- invalid_column_format: "\u932F\u8AA4: \u7121\u6548\u7684\u6B04\u4F4D\u683C\u5F0F\u3002\u4F7F\u7528 'table.column'"
43098
+ invalid_column_format: "\u932F\u8AA4: \u7121\u6548\u7684\u6B04\u4F4D\u683C\u5F0F\u3002\u4F7F\u7528 'table.column'",
43099
+ invalid_system: "\u7121\u6548\u7684\u8CC7\u6599\u5EAB\u7CFB\u7D71\uFF1A{system}",
43100
+ invalid_permission: "\u7121\u6548\u7684\u6B0A\u9650\u7B49\u7D1A\uFF1A{permission}",
43101
+ invalid_port: "\u7121\u6548\u7684\u57E0\u865F\uFF1A{port}",
43102
+ require_user: "\u975E\u4E92\u52D5\u6A21\u5F0F\u9700\u8981 --user \u9078\u9805",
43103
+ require_name: "\u975E\u4E92\u52D5\u6A21\u5F0F\u9700\u8981 --name \u9078\u9805",
43104
+ env_refs_missing_options: `\u4F7F\u7528 --use-env-refs \u6642\uFF0C\u5FC5\u9808\u6307\u5B9A\u74B0\u5883\u8B8A\u6578\u540D\u7A31\u3002
43105
+ \u8ACB\u63D0\u4F9B\u9078\u9805\uFF1A--env-host\u3001--env-port\u3001--env-user\u3001--env-password\u3001--env-database
43106
+ \u6216\u4F7F\u7528\u4E92\u52D5\u6A21\u5F0F\uFF1A\u57F7\u884C "dbcli init --use-env-refs"\uFF08\u4E0D\u52A0 --no-interactive\uFF09`,
43107
+ env_var_not_defined: `\u7121\u6CD5\u6E2C\u8A66\u9023\u7DDA\uFF1A\u74B0\u5883\u8B8A\u6578 {envKey} \u672A\u5B9A\u7FA9\u3002
43108
+ \u8ACB\u5728 .env \u6216\u74B0\u5883\u8B8A\u6578\u4E2D\u8A2D\u5B9A {envKey}\u3002
43109
+ \u63D0\u793A\uFF1A\u57F7\u884C 'export {envKey}=<value>' \u5F8C\u91CD\u8A66`
42983
43110
  },
42984
43111
  success: {
42985
43112
  inserted: "\u6210\u529F\u63D2\u5165 {count} \u5217",
@@ -43029,6 +43156,11 @@ var messages_default2 = {
43029
43156
  },
43030
43157
  warnings: {
43031
43158
  blacklist_override_used: "\u8B66\u544A: \u5DF2\u555F\u7528\u9ED1\u540D\u55AE\u8986\u84CB (DBCLI_OVERRIDE_BLACKLIST=true)\u3002\u57F7\u884C {operation} \u5728\u5DF2\u9ED1\u540D\u55AE\u7684\u8868\u683C '{table}' \u4E0A"
43159
+ },
43160
+ version: {
43161
+ unsupported_warning: "{system} {version} \u4F4E\u65BC\u6700\u4F4E\u652F\u63F4\u7248\u672C {minVersion}\u3002\u90E8\u5206\u529F\u80FD\u53EF\u80FD\u7121\u6CD5\u6B63\u5E38\u904B\u4F5C\u3002",
43162
+ doctor_pass: "{system} {version}\uFF08\u7B26\u5408 >= {minVersion}\uFF09",
43163
+ doctor_warn: "{system} {version} \u4F4E\u65BC\u652F\u63F4\u7248\u672C >= {minVersion}"
43032
43164
  }
43033
43165
  };
43034
43166
 
@@ -43101,6 +43233,47 @@ var messageLoader = MessageLoader.getInstance();
43101
43233
  var t = (key) => messageLoader.t(key);
43102
43234
  var t_vars = (key, vars) => messageLoader.interpolate(key, vars);
43103
43235
 
43236
+ // src/utils/colors.ts
43237
+ var import_picocolors = __toESM(require_picocolors(), 1);
43238
+ var colors = {
43239
+ success: (text) => import_picocolors.default.green(text),
43240
+ error: (text) => import_picocolors.default.red(text),
43241
+ warn: (text) => import_picocolors.default.yellow(text),
43242
+ info: (text) => import_picocolors.default.blue(text),
43243
+ dim: (text) => import_picocolors.default.dim(text),
43244
+ bold: (text) => import_picocolors.default.bold(text),
43245
+ keyword: (text) => import_picocolors.default.blue(import_picocolors.default.bold(text))
43246
+ };
43247
+
43248
+ // src/utils/logger.ts
43249
+ function formatArgs(args) {
43250
+ return args.map((a) => typeof a === "string" ? a : JSON.stringify(a)).join(" ");
43251
+ }
43252
+ function createLogger(level = 1 /* NORMAL */) {
43253
+ const write = (minLevel, prefix, args) => {
43254
+ if (level < minLevel)
43255
+ return;
43256
+ const message = `${prefix} ${formatArgs(args)}
43257
+ `;
43258
+ process.stderr.write(message);
43259
+ };
43260
+ return {
43261
+ error: (...args) => write(0 /* QUIET */, colors.error("[ERROR]"), args),
43262
+ warn: (...args) => write(1 /* NORMAL */, colors.warn("[WARN]"), args),
43263
+ info: (...args) => write(1 /* NORMAL */, colors.info("[INFO]"), args),
43264
+ verbose: (...args) => write(2 /* VERBOSE */, colors.dim("[VERBOSE]"), args),
43265
+ debug: (...args) => write(3 /* DEBUG */, colors.dim("[DEBUG]"), args),
43266
+ level
43267
+ };
43268
+ }
43269
+ var globalLogger = createLogger(1 /* NORMAL */);
43270
+ function setGlobalLogger(logger) {
43271
+ globalLogger = logger;
43272
+ }
43273
+ function getLogger() {
43274
+ return globalLogger;
43275
+ }
43276
+
43104
43277
  // src/utils/errors.ts
43105
43278
  class EnvParseError extends Error {
43106
43279
  constructor(message) {
@@ -47546,6 +47719,61 @@ var Result = import_lib.default.Result;
47546
47719
  var TypeOverrides = import_lib.default.TypeOverrides;
47547
47720
  var defaults = import_lib.default.defaults;
47548
47721
 
47722
+ // src/utils/db-version-check.ts
47723
+ var MIN_SUPPORTED_VERSIONS = {
47724
+ postgresql: "12.0",
47725
+ mysql: "8.0",
47726
+ mariadb: "10.5"
47727
+ };
47728
+ function parseVersionSegments(version) {
47729
+ const match = version.match(/^(\d+(?:\.\d+)*)/);
47730
+ if (!match)
47731
+ return [];
47732
+ return match[1].split(".").map(Number);
47733
+ }
47734
+ function isMariaDBVersion(versionString) {
47735
+ return /mariadb/i.test(versionString);
47736
+ }
47737
+ function extractMariaDBVersion(versionString) {
47738
+ const match = versionString.match(/(\d+\.\d+\.\d+)-MariaDB/i);
47739
+ if (match)
47740
+ return match[1];
47741
+ const prefixMatch = versionString.match(/^5\.5\.5-(\d+\.\d+\.\d+)/);
47742
+ if (prefixMatch)
47743
+ return prefixMatch[1];
47744
+ return versionString;
47745
+ }
47746
+ function compareVersions(a, b) {
47747
+ const segA = parseVersionSegments(a);
47748
+ const segB = parseVersionSegments(b);
47749
+ const len = Math.max(segA.length, segB.length);
47750
+ for (let i = 0;i < len; i++) {
47751
+ const diff = (segA[i] ?? 0) - (segB[i] ?? 0);
47752
+ if (diff !== 0)
47753
+ return diff;
47754
+ }
47755
+ return 0;
47756
+ }
47757
+ function checkDbVersion(rawVersion, declaredSystem) {
47758
+ const isMariaDB = isMariaDBVersion(rawVersion);
47759
+ const system = isMariaDB ? "mariadb" : declaredSystem;
47760
+ const serverVersion = isMariaDB ? extractMariaDBVersion(rawVersion) : rawVersion;
47761
+ const minVersion = MIN_SUPPORTED_VERSIONS[system];
47762
+ const supported = compareVersions(serverVersion, minVersion) >= 0;
47763
+ return { serverVersion, system, supported, minVersion };
47764
+ }
47765
+ function warnIfUnsupported(result) {
47766
+ if (result.supported)
47767
+ return;
47768
+ const message = t_vars("version.unsupported_warning", {
47769
+ system: result.system,
47770
+ version: result.serverVersion,
47771
+ minVersion: result.minVersion
47772
+ });
47773
+ process.stderr.write(colors.warn(`\u26A0 ${message}`) + `
47774
+ `);
47775
+ }
47776
+
47549
47777
  // src/adapters/postgresql-adapter.ts
47550
47778
  class PostgreSQLAdapter {
47551
47779
  pool = null;
@@ -47569,6 +47797,11 @@ class PostgreSQLAdapter {
47569
47797
  statement_timeout: this.options.timeout || 5000
47570
47798
  });
47571
47799
  await this.testConnection();
47800
+ try {
47801
+ const rawVersion = await this.getServerVersion();
47802
+ const result = checkDbVersion(rawVersion, "postgresql");
47803
+ warnIfUnsupported(result);
47804
+ } catch {}
47572
47805
  } catch (error) {
47573
47806
  throw mapError(error, "postgresql", this.options);
47574
47807
  }
@@ -47607,6 +47840,10 @@ class PostgreSQLAdapter {
47607
47840
  throw mapError(error, "postgresql", this.options);
47608
47841
  }
47609
47842
  }
47843
+ async getServerVersion() {
47844
+ const rows = await this.execute("SHOW server_version");
47845
+ return rows[0]?.server_version ?? "unknown";
47846
+ }
47610
47847
  async listTables() {
47611
47848
  if (!this.pool) {
47612
47849
  throw new ConnectionError("UNKNOWN", "Database connection not established", ["Call connect() to establish a connection"]);
@@ -47817,6 +48054,11 @@ class MySQLAdapter {
47817
48054
  database: this.options.database
47818
48055
  });
47819
48056
  await this.testConnection();
48057
+ try {
48058
+ const rawVersion = await this.getServerVersion();
48059
+ const result = checkDbVersion(rawVersion, this.system);
48060
+ warnIfUnsupported(result);
48061
+ } catch {}
47820
48062
  } catch (error) {
47821
48063
  throw mapError(error, this.system, this.options);
47822
48064
  }
@@ -47851,6 +48093,10 @@ class MySQLAdapter {
47851
48093
  throw mapError(error, this.system, this.options);
47852
48094
  }
47853
48095
  }
48096
+ async getServerVersion() {
48097
+ const rows = await this.execute("SELECT VERSION() as version");
48098
+ return rows[0]?.version ?? "unknown";
48099
+ }
47854
48100
  async listTables() {
47855
48101
  if (!this.db) {
47856
48102
  throw new ConnectionError("UNKNOWN", "Database connection not established", ["Call connect() to establish a connection"]);
@@ -48002,7 +48248,23 @@ class AdapterFactory {
48002
48248
  }
48003
48249
  }
48004
48250
  // src/commands/init.ts
48005
- var 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)").option("--permission <permission>", "Permission level (query-only, read-write, data-admin, admin)", "query-only").option("--use-env-refs", "Generate config with environment variable references (for .env)", false).option("--env-host <var>", "Environment variable name for database host (when using --use-env-refs)").option("--env-port <var>", "Environment variable name for database port (when using --use-env-refs)").option("--env-user <var>", "Environment variable name for database user (when using --use-env-refs)").option("--env-password <var>", "Environment variable name for database password (when using --use-env-refs)").option("--env-database <var>", "Environment variable name for database name (when using --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").action(async (options) => {
48251
+ var VALID_PERMISSIONS = ["query-only", "read-write", "data-admin", "admin"];
48252
+ async function checkOverwrite(shouldPrompt, force) {
48253
+ const configFile = Bun.file(".dbcli");
48254
+ const fileExists = await configFile.exists();
48255
+ if (!fileExists || force)
48256
+ return true;
48257
+ if (shouldPrompt) {
48258
+ const overwrite = await promptUser.confirm(t("init.config_exists_overwrite"));
48259
+ if (!overwrite) {
48260
+ console.log(t("init.cancelled"));
48261
+ return false;
48262
+ }
48263
+ return true;
48264
+ }
48265
+ throw new Error(t("init.config_exists_use_force"));
48266
+ }
48267
+ var 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)").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").action(async (options) => {
48006
48268
  try {
48007
48269
  await initCommandHandler(options);
48008
48270
  } catch (error) {
@@ -48036,7 +48298,7 @@ async function initCommandHandler(options) {
48036
48298
  ]);
48037
48299
  }
48038
48300
  if (!["postgresql", "mysql", "mariadb"].includes(system)) {
48039
- throw new Error(`Invalid database system: ${system}`);
48301
+ throw new Error(t_vars("errors.invalid_system", { system }));
48040
48302
  }
48041
48303
  const defaults2 = getDefaultsForSystem(system);
48042
48304
  const connection = {
@@ -48058,34 +48320,25 @@ async function initCommandHandler(options) {
48058
48320
  database: { $env: envDatabase }
48059
48321
  };
48060
48322
  let permission2 = options.permission || "query-only";
48061
- if (shouldPrompt && !options.permission) {
48323
+ if (!options.permission) {
48062
48324
  permission2 = await promptUser.select(t("init.prompt_permission"), [
48063
48325
  "query-only",
48064
48326
  "read-write",
48327
+ "data-admin",
48065
48328
  "admin"
48066
48329
  ]);
48067
48330
  }
48068
- if (!["query-only", "read-write", "data-admin", "admin"].includes(permission2)) {
48069
- throw new Error(`Invalid permission level: ${permission2}`);
48331
+ if (!VALID_PERMISSIONS.includes(permission2)) {
48332
+ throw new Error(t_vars("errors.invalid_permission", { permission: permission2 }));
48070
48333
  }
48071
48334
  const newConfig2 = configModule.merge(existingConfig, {
48072
48335
  connection: configForWrite,
48073
48336
  permission: permission2
48074
48337
  });
48075
- const configFile2 = Bun.file(".dbcli");
48076
- const fileExists2 = await configFile2.exists();
48077
- if (fileExists2 && !options.force) {
48078
- if (shouldPrompt) {
48079
- const overwrite = await promptUser.confirm(t("init.config_exists_overwrite"));
48080
- if (!overwrite) {
48081
- console.log(t("init.cancelled"));
48082
- return;
48083
- }
48084
- } else {
48085
- throw new Error(".dbcli exists. Use --force option to overwrite.");
48086
- }
48087
- }
48088
- console.log("\u23ED\uFE0F Skipping connection test in env-ref mode");
48338
+ const canProceed2 = await checkOverwrite(shouldPrompt, !!options.force);
48339
+ if (!canProceed2)
48340
+ return;
48341
+ console.log(`\u23ED\uFE0F ${t("init.skip_test_env_ref")}`);
48089
48342
  await configModule.write(".dbcli", newConfig2);
48090
48343
  console.log(t("init.config_saved"));
48091
48344
  return;
@@ -48094,17 +48347,17 @@ async function initCommandHandler(options) {
48094
48347
  const portStr = options.port || (envConfig?.port ? String(envConfig.port) : null) || (shouldPrompt ? await promptUser.text(t("init.prompt_port"), String(defaults2.port || 5432)) : String(defaults2.port || 5432));
48095
48348
  const port = parseInt(portStr, 10);
48096
48349
  if (isNaN(port) || port < 1 || port > 65535) {
48097
- throw new Error(`Invalid port: ${portStr}`);
48350
+ throw new Error(t_vars("errors.invalid_port", { port: portStr }));
48098
48351
  }
48099
48352
  connection.port = port;
48100
48353
  connection.user = options.user || envConfig?.user || (shouldPrompt ? await promptUser.text(t("init.prompt_user")) : "");
48101
48354
  if (!connection.user && !shouldPrompt && !options.useEnvRefs) {
48102
- throw new Error("Non-interactive mode requires --user option");
48355
+ throw new Error(t("errors.require_user"));
48103
48356
  }
48104
48357
  connection.password = options.password || envConfig?.password || (shouldPrompt ? await promptUser.text(t("init.prompt_password")) : "");
48105
48358
  connection.database = options.name || envConfig?.database || (shouldPrompt ? await promptUser.text(t("init.prompt_name")) : "");
48106
48359
  if (!connection.database && !shouldPrompt && !options.useEnvRefs) {
48107
- throw new Error("Non-interactive mode requires --name option");
48360
+ throw new Error(t("errors.require_name"));
48108
48361
  }
48109
48362
  let permission = options.permission || "query-only";
48110
48363
  if (shouldPrompt && !options.permission) {
@@ -48115,8 +48368,8 @@ async function initCommandHandler(options) {
48115
48368
  "admin"
48116
48369
  ]);
48117
48370
  }
48118
- if (!["query-only", "read-write", "data-admin", "admin"].includes(permission)) {
48119
- throw new Error(`Invalid permission level: ${permission}`);
48371
+ if (!VALID_PERMISSIONS.includes(permission)) {
48372
+ throw new Error(t_vars("errors.invalid_permission", { permission }));
48120
48373
  }
48121
48374
  configForWrite = connection;
48122
48375
  if (options.useEnvRefs) {
@@ -48126,9 +48379,7 @@ async function initCommandHandler(options) {
48126
48379
  const envPassword = options.envPassword;
48127
48380
  const envDatabase = options.envDatabase;
48128
48381
  if (!envHost || !envPort || !envUser || !envPassword || !envDatabase) {
48129
- throw new Error(`When using --use-env-refs, environment variable names must be specified.
48130
- ` + `Provide options: --env-host, --env-port, --env-user, --env-password, --env-database
48131
- ` + 'Or use interactive mode: run "bun dev init --use-env-refs" without --no-interactive');
48382
+ throw new Error(t("errors.env_refs_missing_options"));
48132
48383
  }
48133
48384
  configForWrite = {
48134
48385
  system: connection.system,
@@ -48143,29 +48394,17 @@ async function initCommandHandler(options) {
48143
48394
  connection: configForWrite,
48144
48395
  permission
48145
48396
  });
48146
- const configFile = Bun.file(".dbcli");
48147
- const fileExists = await configFile.exists();
48148
- if (fileExists && !options.force) {
48149
- if (shouldPrompt) {
48150
- const overwrite = await promptUser.confirm(t("init.config_exists_overwrite"));
48151
- if (!overwrite) {
48152
- console.log(t("init.cancelled"));
48153
- return;
48154
- }
48155
- } else {
48156
- throw new Error(".dbcli exists. Use --force option to overwrite.");
48157
- }
48158
- }
48397
+ const canProceed = await checkOverwrite(shouldPrompt, !!options.force);
48398
+ if (!canProceed)
48399
+ return;
48159
48400
  if (!options.skipTest && !options.useEnvRefs) {
48160
48401
  console.log(t("init.connection_testing"));
48161
- const resolveValue = (value, fieldName) => {
48402
+ const resolveValue = (value, _fieldName) => {
48162
48403
  if (typeof value === "object" && value !== null && "$env" in value) {
48163
48404
  const envKey = value.$env;
48164
48405
  const envValue = process.env[envKey];
48165
48406
  if (!envValue) {
48166
- throw new Error(`Cannot test connection: environment variable ${envKey} is not defined
48167
- ` + `Set ${envKey} in .env or environment variables.
48168
- ` + `Hint: Check .env file or run 'export ${envKey}=<value>' and retry`);
48407
+ throw new Error(t_vars("errors.env_var_not_defined", { envKey }));
48169
48408
  }
48170
48409
  return envValue;
48171
48410
  }
@@ -48189,7 +48428,7 @@ async function initCommandHandler(options) {
48189
48428
  } catch (error) {
48190
48429
  if (error instanceof ConnectionError) {
48191
48430
  console.error(t_vars("errors.connection_failed", { message: error.message }));
48192
- console.error("Hints:");
48431
+ console.error(t("init.connection_hints"));
48193
48432
  error.hints.forEach((hint) => console.error(` \u2022 ${hint}`));
48194
48433
  process.exit(1);
48195
48434
  }
@@ -48198,7 +48437,8 @@ async function initCommandHandler(options) {
48198
48437
  await adapter.disconnect();
48199
48438
  }
48200
48439
  } else {
48201
- console.log("\u23ED\uFE0F Skipping connection test (--skip-test)");
48440
+ const msgKey = options.useEnvRefs ? "init.skip_test_env_ref" : "init.skip_test";
48441
+ console.log(`\u23ED\uFE0F ${t(msgKey)}`);
48202
48442
  }
48203
48443
  await configModule.write(".dbcli", newConfig);
48204
48444
  console.log(t("init.config_saved"));
@@ -48210,7 +48450,7 @@ var Table = require_table();
48210
48450
  class TableFormatter {
48211
48451
  format(columns) {
48212
48452
  const table = new Table({
48213
- head: ["Column", "Type", "Nullable", "Default", "Key"],
48453
+ head: ["Column", "Type", "Nullable", "Default", "Key"].map((h) => colors.bold(h)),
48214
48454
  style: { compact: false, "padding-left": 1, "padding-right": 1 },
48215
48455
  colWidths: [25, 25, 10, 25, 20]
48216
48456
  });
@@ -48236,7 +48476,7 @@ class TableFormatter {
48236
48476
  class TableListFormatter {
48237
48477
  format(tables) {
48238
48478
  const table = new Table({
48239
- head: ["Table", "Columns", "Rows", "Engine"],
48479
+ head: ["Table", "Columns", "Rows", "Engine"].map((h) => colors.bold(h)),
48240
48480
  style: { compact: false, "padding-left": 1, "padding-right": 1 },
48241
48481
  colWidths: [30, 12, 15, 15]
48242
48482
  });
@@ -50824,8 +51064,657 @@ var statusCommand = new Command("status").description("Show current configuratio
50824
51064
  }
50825
51065
  });
50826
51066
 
51067
+ // src/commands/doctor.ts
51068
+ import { join as join3 } from "path";
51069
+ var SENSITIVE_PATTERNS = [
51070
+ "password",
51071
+ "passwd",
51072
+ "secret",
51073
+ "token",
51074
+ "api_key",
51075
+ "apikey",
51076
+ "access_key",
51077
+ "private_key",
51078
+ "credential",
51079
+ "auth_token",
51080
+ "refresh_token",
51081
+ "session_token",
51082
+ "ssn",
51083
+ "credit_card"
51084
+ ];
51085
+ function compareSemver(a, b) {
51086
+ const pa = a.split(".").map(Number);
51087
+ const pb = b.split(".").map(Number);
51088
+ for (let i = 0;i < 3; i++) {
51089
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
51090
+ if (diff !== 0)
51091
+ return diff;
51092
+ }
51093
+ return 0;
51094
+ }
51095
+ var runDoctorChecks = {
51096
+ checkBunVersion(current, required) {
51097
+ const passes = compareSemver(current, required) >= 0;
51098
+ return {
51099
+ group: "Environment",
51100
+ label: "Bun version",
51101
+ status: passes ? "pass" : "error",
51102
+ message: passes ? `Bun v${current} (meets >= ${required})` : `Bun v${current} is below required >= ${required}`
51103
+ };
51104
+ },
51105
+ async checkLatestVersion(currentVersion) {
51106
+ try {
51107
+ const response = await fetch("https://registry.npmjs.org/@carllee1983/dbcli/latest", { signal: AbortSignal.timeout(5000) });
51108
+ if (!response.ok)
51109
+ throw new Error(`HTTP ${response.status}`);
51110
+ const data = await response.json();
51111
+ const latest = data.version;
51112
+ const isLatest = currentVersion === latest;
51113
+ return {
51114
+ group: "Environment",
51115
+ label: "dbcli version",
51116
+ status: isLatest ? "pass" : "warn",
51117
+ message: isLatest ? `dbcli v${currentVersion} (latest)` : `dbcli v${currentVersion} (latest: ${latest})`
51118
+ };
51119
+ } catch {
51120
+ return {
51121
+ group: "Environment",
51122
+ label: "dbcli version",
51123
+ status: "pass",
51124
+ message: `dbcli v${currentVersion} (version check skipped)`
51125
+ };
51126
+ }
51127
+ },
51128
+ async checkConfigExists(configPath, existsFn) {
51129
+ const exists = existsFn ? await existsFn(configPath) : await Bun.file(configPath).exists() || await Bun.file(join3(configPath, "config.json")).exists();
51130
+ return {
51131
+ group: "Configuration",
51132
+ label: "Config exists",
51133
+ status: exists ? "pass" : "error",
51134
+ message: exists ? `Config found: ${configPath}` : `No config found at ${configPath}. Run "dbcli init" first.`
51135
+ };
51136
+ },
51137
+ checkBlacklistCompleteness(tableColumns, blacklistedColumns) {
51138
+ const unprotected = [];
51139
+ for (const [table, columns] of tableColumns) {
51140
+ const blacklisted = blacklistedColumns.get(table) ?? new Set;
51141
+ for (const col of columns) {
51142
+ const colLower = col.toLowerCase();
51143
+ const isSensitive = SENSITIVE_PATTERNS.some((p) => colLower.includes(p));
51144
+ if (isSensitive && !blacklisted.has(col)) {
51145
+ unprotected.push(`${table}.${col}`);
51146
+ }
51147
+ }
51148
+ }
51149
+ if (unprotected.length === 0) {
51150
+ return {
51151
+ group: "Configuration",
51152
+ label: "Blacklist completeness",
51153
+ status: "pass",
51154
+ message: "All detected sensitive columns are protected"
51155
+ };
51156
+ }
51157
+ return {
51158
+ group: "Configuration",
51159
+ label: "Blacklist completeness",
51160
+ status: "warn",
51161
+ message: `Consider protecting: ${unprotected.join(", ")}`
51162
+ };
51163
+ },
51164
+ checkSchemaCacheFreshness(lastUpdated) {
51165
+ if (!lastUpdated) {
51166
+ return {
51167
+ group: "Connection & Data",
51168
+ label: "Schema cache",
51169
+ status: "warn",
51170
+ message: 'No schema cache found \u2014 run "dbcli schema --refresh"'
51171
+ };
51172
+ }
51173
+ const ageMs = Date.now() - new Date(lastUpdated).getTime();
51174
+ const ageDays = Math.floor(ageMs / (24 * 60 * 60 * 1000));
51175
+ if (ageDays > 7) {
51176
+ return {
51177
+ group: "Connection & Data",
51178
+ label: "Schema cache",
51179
+ status: "warn",
51180
+ message: `Schema cache is ${ageDays} days old \u2014 run "dbcli schema --refresh"`
51181
+ };
51182
+ }
51183
+ return {
51184
+ group: "Connection & Data",
51185
+ label: "Schema cache",
51186
+ status: "pass",
51187
+ message: `Schema cache is ${ageDays} day(s) old`
51188
+ };
51189
+ },
51190
+ checkDatabaseVersion(versionResult) {
51191
+ const vars = {
51192
+ system: versionResult.system,
51193
+ version: versionResult.serverVersion,
51194
+ minVersion: versionResult.minVersion
51195
+ };
51196
+ return {
51197
+ group: "Connection & Data",
51198
+ label: "Database version",
51199
+ status: versionResult.supported ? "pass" : "warn",
51200
+ message: versionResult.supported ? t_vars("version.doctor_pass", vars) : t_vars("version.doctor_warn", vars)
51201
+ };
51202
+ },
51203
+ checkLargeTables(tables) {
51204
+ const large = tables.filter((t7) => (t7.estimatedRowCount ?? 0) > 1e6);
51205
+ if (large.length === 0) {
51206
+ return {
51207
+ group: "Connection & Data",
51208
+ label: "Large tables",
51209
+ status: "pass",
51210
+ message: "No tables exceed 1M rows"
51211
+ };
51212
+ }
51213
+ const list = large.map((t7) => `${t7.name} (${((t7.estimatedRowCount ?? 0) / 1e6).toFixed(1)}M rows)`).join(", ");
51214
+ return {
51215
+ group: "Connection & Data",
51216
+ label: "Large tables",
51217
+ status: "warn",
51218
+ message: `Large tables: ${list}`
51219
+ };
51220
+ },
51221
+ formatTextOutput(results, version) {
51222
+ const lines2 = [`dbcli doctor v${version}`, ""];
51223
+ const groups = ["Environment", "Configuration", "Connection & Data"];
51224
+ for (const group of groups) {
51225
+ const groupResults = results.filter((r) => r.group === group);
51226
+ if (groupResults.length === 0)
51227
+ continue;
51228
+ lines2.push(group);
51229
+ for (const r of groupResults) {
51230
+ const icon = r.status === "pass" ? colors.success("\u2713") : r.status === "warn" ? colors.warn("\u26A0") : colors.error("\u2717");
51231
+ lines2.push(` ${icon} ${r.message}`);
51232
+ }
51233
+ lines2.push("");
51234
+ }
51235
+ const passed = results.filter((r) => r.status === "pass").length;
51236
+ const warnings = results.filter((r) => r.status === "warn").length;
51237
+ const errors3 = results.filter((r) => r.status === "error").length;
51238
+ lines2.push(`Summary: ${passed} passed, ${warnings} warning(s), ${errors3} error(s)`);
51239
+ return lines2.join(`
51240
+ `);
51241
+ }
51242
+ };
51243
+ var doctorCommand = new Command("doctor").description("Run diagnostic checks on dbcli configuration, environment, and connection").option("--format <type>", "Output format: text, json", "text").action(async (options) => {
51244
+ const logger = getLogger();
51245
+ const results = [];
51246
+ const configPath = doctorCommand.parent?.opts().config ?? ".dbcli";
51247
+ const bunVersion = process.versions.bun ?? "unknown";
51248
+ const requiredBun = package_default.engines?.bun?.replace(">=", "") ?? "1.3.3";
51249
+ results.push(runDoctorChecks.checkBunVersion(bunVersion, requiredBun));
51250
+ results.push(await runDoctorChecks.checkLatestVersion(package_default.version));
51251
+ const configExists = await runDoctorChecks.checkConfigExists(configPath);
51252
+ results.push(configExists);
51253
+ if (configExists.status !== "error") {
51254
+ try {
51255
+ const config = await configModule.read(configPath);
51256
+ results.push({
51257
+ group: "Configuration",
51258
+ label: "Config valid",
51259
+ status: "pass",
51260
+ message: "Config valid"
51261
+ });
51262
+ results.push({
51263
+ group: "Configuration",
51264
+ label: "Permission",
51265
+ status: "pass",
51266
+ message: `Permission: ${config.permission}`
51267
+ });
51268
+ const blacklistedColumns = new Map;
51269
+ if (config.blacklist?.columns) {
51270
+ for (const [table, cols] of Object.entries(config.blacklist.columns)) {
51271
+ blacklistedColumns.set(table, new Set(cols));
51272
+ }
51273
+ }
51274
+ try {
51275
+ const adapter = AdapterFactory.createAdapter(config.connection);
51276
+ await adapter.connect();
51277
+ results.push({
51278
+ group: "Connection & Data",
51279
+ label: "Connection",
51280
+ status: "pass",
51281
+ message: `Connected to ${config.connection.system} ${config.connection.database}@${config.connection.host}:${config.connection.port}`
51282
+ });
51283
+ try {
51284
+ const rawVersion = await adapter.getServerVersion();
51285
+ const versionResult = checkDbVersion(rawVersion, config.connection.system);
51286
+ results.push(runDoctorChecks.checkDatabaseVersion(versionResult));
51287
+ } catch {
51288
+ logger.debug("Could not retrieve database version");
51289
+ }
51290
+ try {
51291
+ const tables = await adapter.listTables();
51292
+ const tableColumns = new Map;
51293
+ for (const t7 of tables) {
51294
+ tableColumns.set(t7.name, t7.columns.map((c) => c.name));
51295
+ }
51296
+ results.push(runDoctorChecks.checkBlacklistCompleteness(tableColumns, blacklistedColumns));
51297
+ results.push(runDoctorChecks.checkLargeTables(tables));
51298
+ } catch {
51299
+ logger.debug("Could not list tables for blacklist/large table check");
51300
+ }
51301
+ try {
51302
+ const indexPath = join3(configPath, "schemas", "index.json");
51303
+ const indexFile = Bun.file(indexPath);
51304
+ if (await indexFile.exists()) {
51305
+ const indexContent = await indexFile.text();
51306
+ const index = JSON.parse(indexContent);
51307
+ results.push(runDoctorChecks.checkSchemaCacheFreshness(index.updatedAt ?? null));
51308
+ } else {
51309
+ results.push(runDoctorChecks.checkSchemaCacheFreshness(null));
51310
+ }
51311
+ } catch {
51312
+ results.push(runDoctorChecks.checkSchemaCacheFreshness(null));
51313
+ }
51314
+ await adapter.disconnect();
51315
+ } catch (error) {
51316
+ results.push({
51317
+ group: "Connection & Data",
51318
+ label: "Connection",
51319
+ status: "error",
51320
+ message: `Connection failed: ${error.message}`
51321
+ });
51322
+ }
51323
+ } catch (error) {
51324
+ results.push({
51325
+ group: "Configuration",
51326
+ label: "Config valid",
51327
+ status: "error",
51328
+ message: `Config invalid: ${error.message}`
51329
+ });
51330
+ }
51331
+ }
51332
+ const hasError = results.some((r) => r.status === "error");
51333
+ if (options.format === "json") {
51334
+ console.log(JSON.stringify({ results, hasError }, null, 2));
51335
+ } else {
51336
+ console.log(runDoctorChecks.formatTextOutput(results, package_default.version));
51337
+ }
51338
+ if (hasError) {
51339
+ process.exit(1);
51340
+ }
51341
+ });
51342
+
51343
+ // src/commands/completion.ts
51344
+ import { join as join4 } from "path";
51345
+ import { homedir as homedir2 } from "os";
51346
+ function extractCommands(program2) {
51347
+ return program2.commands.map((cmd) => ({
51348
+ name: cmd.name(),
51349
+ options: cmd.options.map((o) => o.long ?? o.short ?? "").filter(Boolean)
51350
+ }));
51351
+ }
51352
+ function extractGlobalOptions(program2) {
51353
+ return program2.options.map((o) => o.long ?? o.short ?? "").filter(Boolean);
51354
+ }
51355
+ function generateBashCompletion(commands, globalOptions) {
51356
+ const cmdNames = commands.map((c) => c.name).join(" ");
51357
+ const globalOpts = globalOptions.join(" ");
51358
+ const caseEntries = commands.map((c) => ` ${c.name})
51359
+ COMPREPLY=( $(compgen -W "${c.options.join(" ")}" -- "\${cur}") )
51360
+ ;;`).join(`
51361
+ `);
51362
+ return `#!/bin/bash
51363
+ # dbcli bash completion \u2014 auto-generated, do not edit
51364
+ _dbcli_completions() {
51365
+ local cur prev commands
51366
+ cur="\${COMP_WORDS[COMP_CWORD]}"
51367
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
51368
+ commands="${cmdNames}"
51369
+
51370
+ if [[ \${COMP_CWORD} -eq 1 ]]; then
51371
+ COMPREPLY=( $(compgen -W "\${commands} ${globalOpts}" -- "\${cur}") )
51372
+ return 0
51373
+ fi
51374
+
51375
+ case "\${COMP_WORDS[1]}" in
51376
+ ${caseEntries}
51377
+ *)
51378
+ COMPREPLY=( $(compgen -W "${globalOpts}" -- "\${cur}") )
51379
+ ;;
51380
+ esac
51381
+ }
51382
+ complete -F _dbcli_completions dbcli
51383
+ `;
51384
+ }
51385
+ function generateZshCompletion(commands, globalOptions) {
51386
+ const cmdLines = commands.map((c) => ` '${c.name}:${c.name} command'`).join(`
51387
+ `);
51388
+ const subcmdCases = commands.map((c) => {
51389
+ const opts = c.options.map((o) => `'${o}[${o}]'`).join(" ");
51390
+ return ` ${c.name})
51391
+ _arguments ${opts}
51392
+ ;;`;
51393
+ }).join(`
51394
+ `);
51395
+ const globalOpts = globalOptions.map((o) => `'${o}[${o}]'`).join(" ");
51396
+ return `#compdef dbcli
51397
+ # dbcli zsh completion \u2014 auto-generated, do not edit
51398
+ _dbcli() {
51399
+ local -a commands
51400
+ commands=(
51401
+ ${cmdLines}
51402
+ )
51403
+
51404
+ _arguments -C \\
51405
+ ${globalOpts} \\
51406
+ '1:command:->cmd' \\
51407
+ '*::arg:->args'
51408
+
51409
+ case "$state" in
51410
+ cmd)
51411
+ _describe 'command' commands
51412
+ ;;
51413
+ args)
51414
+ case "$words[1]" in
51415
+ ${subcmdCases}
51416
+ esac
51417
+ ;;
51418
+ esac
51419
+ }
51420
+ _dbcli
51421
+ `;
51422
+ }
51423
+ function generateFishCompletion(commands, globalOptions) {
51424
+ const lines2 = [
51425
+ "# dbcli fish completion \u2014 auto-generated, do not edit",
51426
+ ""
51427
+ ];
51428
+ for (const opt of globalOptions) {
51429
+ const longName = opt.replace(/^--/, "");
51430
+ lines2.push(`complete -c dbcli -n '__fish_use_subcommand' -l ${longName} -d '${opt}'`);
51431
+ }
51432
+ for (const cmd of commands) {
51433
+ lines2.push(`complete -c dbcli -n '__fish_use_subcommand' -a ${cmd.name} -d '${cmd.name} command'`);
51434
+ }
51435
+ for (const cmd of commands) {
51436
+ for (const opt of cmd.options) {
51437
+ const longName = opt.replace(/^--/, "");
51438
+ lines2.push(`complete -c dbcli -n '__fish_seen_subcommand_from ${cmd.name}' -l ${longName} -d '${opt}'`);
51439
+ }
51440
+ }
51441
+ return lines2.join(`
51442
+ `) + `
51443
+ `;
51444
+ }
51445
+ function getInstallPath2(shell) {
51446
+ const home = homedir2();
51447
+ switch (shell) {
51448
+ case "bash":
51449
+ return join4(home, ".bashrc");
51450
+ case "zsh":
51451
+ return join4(home, ".zshrc");
51452
+ case "fish":
51453
+ return join4(home, ".config", "fish", "completions", "dbcli.fish");
51454
+ default:
51455
+ throw new Error(`Unsupported shell: ${shell}. Supported: bash, zsh, fish`);
51456
+ }
51457
+ }
51458
+ function detectShell() {
51459
+ const shellEnv = process.env.SHELL ?? "";
51460
+ if (shellEnv.includes("zsh"))
51461
+ return "zsh";
51462
+ if (shellEnv.includes("bash"))
51463
+ return "bash";
51464
+ if (shellEnv.includes("fish"))
51465
+ return "fish";
51466
+ return "bash";
51467
+ }
51468
+ var MARKER_START = "# >>> dbcli completion >>>";
51469
+ var MARKER_END = "# <<< dbcli completion <<<";
51470
+ async function installCompletion(shell, script) {
51471
+ const targetPath = getInstallPath2(shell);
51472
+ if (shell === "fish") {
51473
+ const dir = join4(homedir2(), ".config", "fish", "completions");
51474
+ await Bun.$`mkdir -p ${dir}`.quiet();
51475
+ await Bun.file(targetPath).write(script);
51476
+ console.log(colors.success(`\u2713 Fish completion installed to ${targetPath}`));
51477
+ return;
51478
+ }
51479
+ const file = Bun.file(targetPath);
51480
+ let content = "";
51481
+ if (await file.exists()) {
51482
+ content = await file.text();
51483
+ }
51484
+ const markerRegex = new RegExp(`${MARKER_START}[\\s\\S]*?${MARKER_END}\\n?`, "g");
51485
+ content = content.replace(markerRegex, "");
51486
+ const block = `
51487
+ ${MARKER_START}
51488
+ eval "$(dbcli completion ${shell})"
51489
+ ${MARKER_END}
51490
+ `;
51491
+ content = content.trimEnd() + `
51492
+ ` + block;
51493
+ await Bun.file(targetPath).write(content);
51494
+ console.log(colors.success(`\u2713 Completion installed to ${targetPath}`));
51495
+ console.log(colors.info(` Run: source ${targetPath}`));
51496
+ }
51497
+ var completionCommand = new Command("completion").description("Generate shell completion scripts (bash, zsh, fish)").argument("[shell]", "Shell type: bash, zsh, fish").option("--install [shell]", "Auto-install completion to shell rc file").action(async (shellArg, options) => {
51498
+ const parentProgram = completionCommand.parent;
51499
+ if (!parentProgram) {
51500
+ console.error(colors.error("Error: completion command must be registered to a program"));
51501
+ process.exit(1);
51502
+ }
51503
+ const commands = extractCommands(parentProgram);
51504
+ const globalOptions = extractGlobalOptions(parentProgram);
51505
+ if (options.install !== undefined) {
51506
+ const shell2 = typeof options.install === "string" ? options.install : shellArg ?? detectShell();
51507
+ const generators2 = {
51508
+ bash: generateBashCompletion,
51509
+ zsh: generateZshCompletion,
51510
+ fish: generateFishCompletion
51511
+ };
51512
+ const generate2 = generators2[shell2];
51513
+ if (!generate2) {
51514
+ console.error(colors.error(`Unsupported shell: ${shell2}. Supported: bash, zsh, fish`));
51515
+ process.exit(1);
51516
+ }
51517
+ const script = generate2(commands, globalOptions);
51518
+ await installCompletion(shell2, script);
51519
+ return;
51520
+ }
51521
+ const shell = shellArg ?? detectShell();
51522
+ const generators = {
51523
+ bash: generateBashCompletion,
51524
+ zsh: generateZshCompletion,
51525
+ fish: generateFishCompletion
51526
+ };
51527
+ const generate = generators[shell];
51528
+ if (!generate) {
51529
+ console.error(colors.error(`Unsupported shell: ${shell}. Supported: bash, zsh, fish`));
51530
+ process.exit(1);
51531
+ }
51532
+ process.stdout.write(generate(commands, globalOptions));
51533
+ });
51534
+
51535
+ // src/utils/version-check.ts
51536
+ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@carllee1983/dbcli/latest";
51537
+ var STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
51538
+ var FETCH_TIMEOUT_MS = 3000;
51539
+ function compareVersions2(a, b) {
51540
+ const stripSuffix = (v) => v.replace(/-.*$/, "");
51541
+ const pa = stripSuffix(a).split(".").map(Number);
51542
+ const pb = stripSuffix(b).split(".").map(Number);
51543
+ for (let i = 0;i < 3; i++) {
51544
+ const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
51545
+ if (diff !== 0)
51546
+ return diff;
51547
+ }
51548
+ if (a === b)
51549
+ return 0;
51550
+ const aHasSuffix = a.includes("-");
51551
+ const bHasSuffix = b.includes("-");
51552
+ if (!aHasSuffix && bHasSuffix)
51553
+ return 1;
51554
+ if (aHasSuffix && !bHasSuffix)
51555
+ return -1;
51556
+ return a.localeCompare(b);
51557
+ }
51558
+ function isStale(checkedAt) {
51559
+ const checked = new Date(checkedAt).getTime();
51560
+ if (isNaN(checked))
51561
+ return true;
51562
+ return Date.now() - checked >= STALE_THRESHOLD_MS;
51563
+ }
51564
+ async function fetchLatestVersion() {
51565
+ try {
51566
+ const response = await fetch(NPM_REGISTRY_URL, {
51567
+ signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
51568
+ });
51569
+ if (!response.ok)
51570
+ return null;
51571
+ const data = await response.json();
51572
+ return data.version ?? null;
51573
+ } catch {
51574
+ return null;
51575
+ }
51576
+ }
51577
+ async function checkForUpdate(currentVersion, cachePath, existingCache) {
51578
+ let cache = existingCache ?? null;
51579
+ if (cache === undefined && cachePath) {
51580
+ try {
51581
+ const cacheFile = Bun.file(`${cachePath}/version-check.json`);
51582
+ if (await cacheFile.exists()) {
51583
+ cache = await cacheFile.json();
51584
+ }
51585
+ } catch {
51586
+ cache = null;
51587
+ }
51588
+ }
51589
+ if (cache && !isStale(cache.checkedAt)) {
51590
+ return {
51591
+ hasUpdate: compareVersions2(cache.latestVersion, currentVersion) > 0,
51592
+ latestVersion: cache.latestVersion
51593
+ };
51594
+ }
51595
+ const latestVersion = await fetchLatestVersion();
51596
+ if (!latestVersion)
51597
+ return null;
51598
+ if (cachePath) {
51599
+ try {
51600
+ const newCache = {
51601
+ latestVersion,
51602
+ checkedAt: new Date().toISOString()
51603
+ };
51604
+ await Bun.write(`${cachePath}/version-check.json`, JSON.stringify(newCache, null, 2));
51605
+ } catch {}
51606
+ }
51607
+ return {
51608
+ hasUpdate: compareVersions2(latestVersion, currentVersion) > 0,
51609
+ latestVersion
51610
+ };
51611
+ }
51612
+
51613
+ // src/commands/upgrade.ts
51614
+ function formatAlreadyUpToDate(version) {
51615
+ return colors.success(`\u2713 Already up to date (v${version})`);
51616
+ }
51617
+ function formatUpgradeMessage(currentVersion, latestVersion) {
51618
+ return [
51619
+ colors.info(` Current version : v${currentVersion}`),
51620
+ colors.success(` Latest version : v${latestVersion}`)
51621
+ ].join(`
51622
+ `);
51623
+ }
51624
+ function formatUpdateHint(latestVersion) {
51625
+ return colors.warn(`[INFO] dbcli v${latestVersion} available. Run "dbcli upgrade" to upgrade.`);
51626
+ }
51627
+ var upgradeCommand = new Command("upgrade").description("Check for updates and upgrade dbcli to the latest version").option("--check", "Only check for updates, do not upgrade").action(async (options) => {
51628
+ const configPath = upgradeCommand.parent?.opts().config ?? ".dbcli";
51629
+ const currentVersion = package_default.version;
51630
+ console.log(colors.bold("Checking for updates..."));
51631
+ let cachePath = null;
51632
+ try {
51633
+ const file = Bun.file(configPath);
51634
+ const isDir = !configPath.includes(".") || await file.exists() === false;
51635
+ if (isDir) {
51636
+ cachePath = configPath;
51637
+ }
51638
+ } catch {
51639
+ cachePath = null;
51640
+ }
51641
+ const result = await checkForUpdate(currentVersion, cachePath);
51642
+ if (!result) {
51643
+ console.error(colors.warn("\u26A0 Could not check for updates (network error or registry unavailable)"));
51644
+ process.exit(0);
51645
+ }
51646
+ if (!result.hasUpdate) {
51647
+ console.log(formatAlreadyUpToDate(currentVersion));
51648
+ process.exit(0);
51649
+ }
51650
+ console.log(colors.warn(`
51651
+ New version available: v${result.latestVersion}`));
51652
+ console.log(formatUpgradeMessage(currentVersion, result.latestVersion));
51653
+ console.log();
51654
+ if (options.check) {
51655
+ console.log(colors.dim(' Run "dbcli upgrade" to install the update.'));
51656
+ process.exit(0);
51657
+ }
51658
+ console.log(colors.bold("Upgrading..."));
51659
+ console.log(colors.dim(` bun add -g @carllee1983/dbcli@latest`));
51660
+ console.log();
51661
+ const proc = Bun.$`bun add -g @carllee1983/dbcli@latest`.nothrow();
51662
+ const result2 = await proc;
51663
+ if (result2.exitCode === 0) {
51664
+ console.log(colors.success(`
51665
+ \u2713 Successfully upgraded to v${result.latestVersion}`));
51666
+ } else {
51667
+ console.error(colors.error(`
51668
+ \u2717 Upgrade failed. Try running manually:`));
51669
+ console.error(colors.dim(" bun add -g @carllee1983/dbcli@latest"));
51670
+ process.exit(1);
51671
+ }
51672
+ });
51673
+
50827
51674
  // src/cli.ts
50828
- var program2 = new Command().name("dbcli").description("Database CLI for AI agents").version(package_default.version).option("--config <path>", "Path to .dbcli config file", ".dbcli");
51675
+ import { join as join5 } from "path";
51676
+ var _bgVersionCheckResult;
51677
+ var program2 = new Command().name("dbcli").description("Database CLI for AI agents").version(package_default.version).option("--no-color", "Disable colored output").option("-v, --verbose", "Increase verbosity (-v verbose, -vv debug)", (_, prev) => prev + 1, 0).option("-q, --quiet", "Suppress non-essential output").option("--config <path>", "Path to .dbcli config file", ".dbcli");
51678
+ program2.hook("preAction", (thisCommand, actionCommand) => {
51679
+ const opts = thisCommand.opts();
51680
+ if (opts.color === false) {
51681
+ process.env.NO_COLOR = "1";
51682
+ }
51683
+ let level = 1 /* NORMAL */;
51684
+ if (opts.quiet) {
51685
+ level = 0 /* QUIET */;
51686
+ } else if (opts.verbose >= 2) {
51687
+ level = 3 /* DEBUG */;
51688
+ } else if (opts.verbose >= 1) {
51689
+ level = 2 /* VERBOSE */;
51690
+ }
51691
+ setGlobalLogger(createLogger(level));
51692
+ const isUpgradeCommand = actionCommand.name() === "upgrade";
51693
+ if (!opts.quiet && !isUpgradeCommand) {
51694
+ const configPath = opts.config ?? ".dbcli";
51695
+ (async () => {
51696
+ try {
51697
+ let cache = null;
51698
+ try {
51699
+ const cacheFile = Bun.file(join5(configPath, "version-check.json"));
51700
+ if (await cacheFile.exists()) {
51701
+ cache = await cacheFile.json();
51702
+ }
51703
+ } catch {}
51704
+ const result = await checkForUpdate(package_default.version, configPath, cache);
51705
+ _bgVersionCheckResult = result;
51706
+ } catch {
51707
+ _bgVersionCheckResult = null;
51708
+ }
51709
+ })();
51710
+ }
51711
+ });
51712
+ program2.hook("postAction", () => {
51713
+ if (_bgVersionCheckResult?.hasUpdate) {
51714
+ process.stderr.write(formatUpdateHint(_bgVersionCheckResult.latestVersion) + `
51715
+ `);
51716
+ }
51717
+ });
50829
51718
  program2.addCommand(initCommand);
50830
51719
  program2.addCommand(listCommand);
50831
51720
  program2.addCommand(schemaCommand);
@@ -50885,6 +51774,9 @@ program2.addCommand(blacklistCommand);
50885
51774
  program2.addCommand(checkCommand);
50886
51775
  program2.addCommand(diffCommand);
50887
51776
  program2.addCommand(statusCommand);
51777
+ program2.addCommand(doctorCommand);
51778
+ program2.addCommand(completionCommand);
51779
+ program2.addCommand(upgradeCommand);
50888
51780
  if (!process.argv.slice(2).length) {
50889
51781
  program2.outputHelp();
50890
51782
  }