postgresai 0.15.0-dev.7 → 0.15.0-dev.9

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.
@@ -6,25 +6,43 @@ var __getProtoOf = Object.getPrototypeOf;
6
6
  var __defProp = Object.defineProperty;
7
7
  var __getOwnPropNames = Object.getOwnPropertyNames;
8
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ function __accessProp(key) {
10
+ return this[key];
11
+ }
12
+ var __toESMCache_node;
13
+ var __toESMCache_esm;
9
14
  var __toESM = (mod, isNodeMode, target) => {
15
+ var canCache = mod != null && typeof mod === "object";
16
+ if (canCache) {
17
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
18
+ var cached = cache.get(mod);
19
+ if (cached)
20
+ return cached;
21
+ }
10
22
  target = mod != null ? __create(__getProtoOf(mod)) : {};
11
23
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
12
24
  for (let key of __getOwnPropNames(mod))
13
25
  if (!__hasOwnProp.call(to, key))
14
26
  __defProp(to, key, {
15
- get: () => mod[key],
27
+ get: __accessProp.bind(mod, key),
16
28
  enumerable: true
17
29
  });
30
+ if (canCache)
31
+ cache.set(mod, to);
18
32
  return to;
19
33
  };
20
34
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
35
+ var __returnValue = (v) => v;
36
+ function __exportSetter(name, newValue) {
37
+ this[name] = __returnValue.bind(null, newValue);
38
+ }
21
39
  var __export = (target, all) => {
22
40
  for (var name in all)
23
41
  __defProp(target, name, {
24
42
  get: all[name],
25
43
  enumerable: true,
26
44
  configurable: true,
27
- set: (newValue) => all[name] = () => newValue
45
+ set: __exportSetter.bind(all, name)
28
46
  });
29
47
  };
30
48
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -80,7 +98,7 @@ var require_argument = __commonJS((exports) => {
80
98
  this._name = name;
81
99
  break;
82
100
  }
83
- if (this._name.length > 3 && this._name.slice(-3) === "...") {
101
+ if (this._name.endsWith("...")) {
84
102
  this.variadic = true;
85
103
  this._name = this._name.slice(0, -3);
86
104
  }
@@ -88,11 +106,12 @@ var require_argument = __commonJS((exports) => {
88
106
  name() {
89
107
  return this._name;
90
108
  }
91
- _concatValue(value, previous) {
109
+ _collectValue(value, previous) {
92
110
  if (previous === this.defaultValue || !Array.isArray(previous)) {
93
111
  return [value];
94
112
  }
95
- return previous.concat(value);
113
+ previous.push(value);
114
+ return previous;
96
115
  }
97
116
  default(value, description) {
98
117
  this.defaultValue = value;
@@ -110,7 +129,7 @@ var require_argument = __commonJS((exports) => {
110
129
  throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
111
130
  }
112
131
  if (this.variadic) {
113
- return this._concatValue(arg, previous);
132
+ return this._collectValue(arg, previous);
114
133
  }
115
134
  return arg;
116
135
  };
@@ -140,10 +159,14 @@ var require_help = __commonJS((exports) => {
140
159
  class Help {
141
160
  constructor() {
142
161
  this.helpWidth = undefined;
162
+ this.minWidthToWrap = 40;
143
163
  this.sortSubcommands = false;
144
164
  this.sortOptions = false;
145
165
  this.showGlobalOptions = false;
146
166
  }
167
+ prepareContext(contextOptions) {
168
+ this.helpWidth = this.helpWidth ?? contextOptions.helpWidth ?? 80;
169
+ }
147
170
  visibleCommands(cmd) {
148
171
  const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
149
172
  const helpCommand = cmd._getHelpCommand();
@@ -218,22 +241,22 @@ var require_help = __commonJS((exports) => {
218
241
  }
219
242
  longestSubcommandTermLength(cmd, helper) {
220
243
  return helper.visibleCommands(cmd).reduce((max, command) => {
221
- return Math.max(max, helper.subcommandTerm(command).length);
244
+ return Math.max(max, this.displayWidth(helper.styleSubcommandTerm(helper.subcommandTerm(command))));
222
245
  }, 0);
223
246
  }
224
247
  longestOptionTermLength(cmd, helper) {
225
248
  return helper.visibleOptions(cmd).reduce((max, option) => {
226
- return Math.max(max, helper.optionTerm(option).length);
249
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
227
250
  }, 0);
228
251
  }
229
252
  longestGlobalOptionTermLength(cmd, helper) {
230
253
  return helper.visibleGlobalOptions(cmd).reduce((max, option) => {
231
- return Math.max(max, helper.optionTerm(option).length);
254
+ return Math.max(max, this.displayWidth(helper.styleOptionTerm(helper.optionTerm(option))));
232
255
  }, 0);
233
256
  }
234
257
  longestArgumentTermLength(cmd, helper) {
235
258
  return helper.visibleArguments(cmd).reduce((max, argument) => {
236
- return Math.max(max, helper.argumentTerm(argument).length);
259
+ return Math.max(max, this.displayWidth(helper.styleArgumentTerm(helper.argumentTerm(argument))));
237
260
  }, 0);
238
261
  }
239
262
  commandUsage(cmd) {
@@ -271,7 +294,11 @@ var require_help = __commonJS((exports) => {
271
294
  extraInfo.push(`env: ${option.envVar}`);
272
295
  }
273
296
  if (extraInfo.length > 0) {
274
- return `${option.description} (${extraInfo.join(", ")})`;
297
+ const extraDescription = `(${extraInfo.join(", ")})`;
298
+ if (option.description) {
299
+ return `${option.description} ${extraDescription}`;
300
+ }
301
+ return extraDescription;
275
302
  }
276
303
  return option.description;
277
304
  }
@@ -284,102 +311,202 @@ var require_help = __commonJS((exports) => {
284
311
  extraInfo.push(`default: ${argument.defaultValueDescription || JSON.stringify(argument.defaultValue)}`);
285
312
  }
286
313
  if (extraInfo.length > 0) {
287
- const extraDescripton = `(${extraInfo.join(", ")})`;
314
+ const extraDescription = `(${extraInfo.join(", ")})`;
288
315
  if (argument.description) {
289
- return `${argument.description} ${extraDescripton}`;
316
+ return `${argument.description} ${extraDescription}`;
290
317
  }
291
- return extraDescripton;
318
+ return extraDescription;
292
319
  }
293
320
  return argument.description;
294
321
  }
322
+ formatItemList(heading, items, helper) {
323
+ if (items.length === 0)
324
+ return [];
325
+ return [helper.styleTitle(heading), ...items, ""];
326
+ }
327
+ groupItems(unsortedItems, visibleItems, getGroup) {
328
+ const result = new Map;
329
+ unsortedItems.forEach((item) => {
330
+ const group = getGroup(item);
331
+ if (!result.has(group))
332
+ result.set(group, []);
333
+ });
334
+ visibleItems.forEach((item) => {
335
+ const group = getGroup(item);
336
+ if (!result.has(group)) {
337
+ result.set(group, []);
338
+ }
339
+ result.get(group).push(item);
340
+ });
341
+ return result;
342
+ }
295
343
  formatHelp(cmd, helper) {
296
344
  const termWidth = helper.padWidth(cmd, helper);
297
- const helpWidth = helper.helpWidth || 80;
298
- const itemIndentWidth = 2;
299
- const itemSeparatorWidth = 2;
300
- function formatItem(term, description) {
301
- if (description) {
302
- const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
303
- return helper.wrap(fullText, helpWidth - itemIndentWidth, termWidth + itemSeparatorWidth);
304
- }
305
- return term;
306
- }
307
- function formatList(textArray) {
308
- return textArray.join(`
309
- `).replace(/^/gm, " ".repeat(itemIndentWidth));
345
+ const helpWidth = helper.helpWidth ?? 80;
346
+ function callFormatItem(term, description) {
347
+ return helper.formatItem(term, termWidth, description, helper);
310
348
  }
311
- let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
349
+ let output = [
350
+ `${helper.styleTitle("Usage:")} ${helper.styleUsage(helper.commandUsage(cmd))}`,
351
+ ""
352
+ ];
312
353
  const commandDescription = helper.commandDescription(cmd);
313
354
  if (commandDescription.length > 0) {
314
355
  output = output.concat([
315
- helper.wrap(commandDescription, helpWidth, 0),
356
+ helper.boxWrap(helper.styleCommandDescription(commandDescription), helpWidth),
316
357
  ""
317
358
  ]);
318
359
  }
319
360
  const argumentList = helper.visibleArguments(cmd).map((argument) => {
320
- return formatItem(helper.argumentTerm(argument), helper.argumentDescription(argument));
361
+ return callFormatItem(helper.styleArgumentTerm(helper.argumentTerm(argument)), helper.styleArgumentDescription(helper.argumentDescription(argument)));
321
362
  });
322
- if (argumentList.length > 0) {
323
- output = output.concat(["Arguments:", formatList(argumentList), ""]);
324
- }
325
- const optionList = helper.visibleOptions(cmd).map((option) => {
326
- return formatItem(helper.optionTerm(option), helper.optionDescription(option));
363
+ output = output.concat(this.formatItemList("Arguments:", argumentList, helper));
364
+ const optionGroups = this.groupItems(cmd.options, helper.visibleOptions(cmd), (option) => option.helpGroupHeading ?? "Options:");
365
+ optionGroups.forEach((options, group) => {
366
+ const optionList = options.map((option) => {
367
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
368
+ });
369
+ output = output.concat(this.formatItemList(group, optionList, helper));
327
370
  });
328
- if (optionList.length > 0) {
329
- output = output.concat(["Options:", formatList(optionList), ""]);
330
- }
331
- if (this.showGlobalOptions) {
371
+ if (helper.showGlobalOptions) {
332
372
  const globalOptionList = helper.visibleGlobalOptions(cmd).map((option) => {
333
- return formatItem(helper.optionTerm(option), helper.optionDescription(option));
373
+ return callFormatItem(helper.styleOptionTerm(helper.optionTerm(option)), helper.styleOptionDescription(helper.optionDescription(option)));
334
374
  });
335
- if (globalOptionList.length > 0) {
336
- output = output.concat([
337
- "Global Options:",
338
- formatList(globalOptionList),
339
- ""
340
- ]);
341
- }
375
+ output = output.concat(this.formatItemList("Global Options:", globalOptionList, helper));
342
376
  }
343
- const commandList = helper.visibleCommands(cmd).map((cmd2) => {
344
- return formatItem(helper.subcommandTerm(cmd2), helper.subcommandDescription(cmd2));
377
+ const commandGroups = this.groupItems(cmd.commands, helper.visibleCommands(cmd), (sub) => sub.helpGroup() || "Commands:");
378
+ commandGroups.forEach((commands, group) => {
379
+ const commandList = commands.map((sub) => {
380
+ return callFormatItem(helper.styleSubcommandTerm(helper.subcommandTerm(sub)), helper.styleSubcommandDescription(helper.subcommandDescription(sub)));
381
+ });
382
+ output = output.concat(this.formatItemList(group, commandList, helper));
345
383
  });
346
- if (commandList.length > 0) {
347
- output = output.concat(["Commands:", formatList(commandList), ""]);
348
- }
349
384
  return output.join(`
350
385
  `);
351
386
  }
387
+ displayWidth(str) {
388
+ return stripColor(str).length;
389
+ }
390
+ styleTitle(str) {
391
+ return str;
392
+ }
393
+ styleUsage(str) {
394
+ return str.split(" ").map((word) => {
395
+ if (word === "[options]")
396
+ return this.styleOptionText(word);
397
+ if (word === "[command]")
398
+ return this.styleSubcommandText(word);
399
+ if (word[0] === "[" || word[0] === "<")
400
+ return this.styleArgumentText(word);
401
+ return this.styleCommandText(word);
402
+ }).join(" ");
403
+ }
404
+ styleCommandDescription(str) {
405
+ return this.styleDescriptionText(str);
406
+ }
407
+ styleOptionDescription(str) {
408
+ return this.styleDescriptionText(str);
409
+ }
410
+ styleSubcommandDescription(str) {
411
+ return this.styleDescriptionText(str);
412
+ }
413
+ styleArgumentDescription(str) {
414
+ return this.styleDescriptionText(str);
415
+ }
416
+ styleDescriptionText(str) {
417
+ return str;
418
+ }
419
+ styleOptionTerm(str) {
420
+ return this.styleOptionText(str);
421
+ }
422
+ styleSubcommandTerm(str) {
423
+ return str.split(" ").map((word) => {
424
+ if (word === "[options]")
425
+ return this.styleOptionText(word);
426
+ if (word[0] === "[" || word[0] === "<")
427
+ return this.styleArgumentText(word);
428
+ return this.styleSubcommandText(word);
429
+ }).join(" ");
430
+ }
431
+ styleArgumentTerm(str) {
432
+ return this.styleArgumentText(str);
433
+ }
434
+ styleOptionText(str) {
435
+ return str;
436
+ }
437
+ styleArgumentText(str) {
438
+ return str;
439
+ }
440
+ styleSubcommandText(str) {
441
+ return str;
442
+ }
443
+ styleCommandText(str) {
444
+ return str;
445
+ }
352
446
  padWidth(cmd, helper) {
353
447
  return Math.max(helper.longestOptionTermLength(cmd, helper), helper.longestGlobalOptionTermLength(cmd, helper), helper.longestSubcommandTermLength(cmd, helper), helper.longestArgumentTermLength(cmd, helper));
354
448
  }
355
- wrap(str, width, indent, minColumnWidth = 40) {
356
- const indents = " \\f\\t\\v   -    \uFEFF";
357
- const manualIndent = new RegExp(`[\\n][${indents}]+`);
358
- if (str.match(manualIndent))
359
- return str;
360
- const columnWidth = width - indent;
361
- if (columnWidth < minColumnWidth)
449
+ preformatted(str) {
450
+ return /\n[^\S\r\n]/.test(str);
451
+ }
452
+ formatItem(term, termWidth, description, helper) {
453
+ const itemIndent = 2;
454
+ const itemIndentStr = " ".repeat(itemIndent);
455
+ if (!description)
456
+ return itemIndentStr + term;
457
+ const paddedTerm = term.padEnd(termWidth + term.length - helper.displayWidth(term));
458
+ const spacerWidth = 2;
459
+ const helpWidth = this.helpWidth ?? 80;
460
+ const remainingWidth = helpWidth - termWidth - spacerWidth - itemIndent;
461
+ let formattedDescription;
462
+ if (remainingWidth < this.minWidthToWrap || helper.preformatted(description)) {
463
+ formattedDescription = description;
464
+ } else {
465
+ const wrappedDescription = helper.boxWrap(description, remainingWidth);
466
+ formattedDescription = wrappedDescription.replace(/\n/g, `
467
+ ` + " ".repeat(termWidth + spacerWidth));
468
+ }
469
+ return itemIndentStr + paddedTerm + " ".repeat(spacerWidth) + formattedDescription.replace(/\n/g, `
470
+ ${itemIndentStr}`);
471
+ }
472
+ boxWrap(str, width) {
473
+ if (width < this.minWidthToWrap)
362
474
  return str;
363
- const leadingStr = str.slice(0, indent);
364
- const columnText = str.slice(indent).replace(`\r
365
- `, `
366
- `);
367
- const indentString = " ".repeat(indent);
368
- const zeroWidthSpace = "​";
369
- const breaks = `\\s${zeroWidthSpace}`;
370
- const regex = new RegExp(`
371
- |.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`, "g");
372
- const lines = columnText.match(regex) || [];
373
- return leadingStr + lines.map((line, i) => {
374
- if (line === `
375
- `)
376
- return "";
377
- return (i > 0 ? indentString : "") + line.trimEnd();
378
- }).join(`
475
+ const rawLines = str.split(/\r\n|\n/);
476
+ const chunkPattern = /[\s]*[^\s]+/g;
477
+ const wrappedLines = [];
478
+ rawLines.forEach((line) => {
479
+ const chunks = line.match(chunkPattern);
480
+ if (chunks === null) {
481
+ wrappedLines.push("");
482
+ return;
483
+ }
484
+ let sumChunks = [chunks.shift()];
485
+ let sumWidth = this.displayWidth(sumChunks[0]);
486
+ chunks.forEach((chunk) => {
487
+ const visibleWidth = this.displayWidth(chunk);
488
+ if (sumWidth + visibleWidth <= width) {
489
+ sumChunks.push(chunk);
490
+ sumWidth += visibleWidth;
491
+ return;
492
+ }
493
+ wrappedLines.push(sumChunks.join(""));
494
+ const nextChunk = chunk.trimStart();
495
+ sumChunks = [nextChunk];
496
+ sumWidth = this.displayWidth(nextChunk);
497
+ });
498
+ wrappedLines.push(sumChunks.join(""));
499
+ });
500
+ return wrappedLines.join(`
379
501
  `);
380
502
  }
381
503
  }
504
+ function stripColor(str) {
505
+ const sgrPattern = /\x1b\[\d*(;\d*)*m/g;
506
+ return str.replace(sgrPattern, "");
507
+ }
382
508
  exports.Help = Help;
509
+ exports.stripColor = stripColor;
383
510
  });
384
511
 
385
512
  // node_modules/commander/lib/option.js
@@ -410,6 +537,7 @@ var require_option = __commonJS((exports) => {
410
537
  this.argChoices = undefined;
411
538
  this.conflictsWith = [];
412
539
  this.implied = undefined;
540
+ this.helpGroupHeading = undefined;
413
541
  }
414
542
  default(value, description) {
415
543
  this.defaultValue = value;
@@ -448,11 +576,12 @@ var require_option = __commonJS((exports) => {
448
576
  this.hidden = !!hide;
449
577
  return this;
450
578
  }
451
- _concatValue(value, previous) {
579
+ _collectValue(value, previous) {
452
580
  if (previous === this.defaultValue || !Array.isArray(previous)) {
453
581
  return [value];
454
582
  }
455
- return previous.concat(value);
583
+ previous.push(value);
584
+ return previous;
456
585
  }
457
586
  choices(values) {
458
587
  this.argChoices = values.slice();
@@ -461,7 +590,7 @@ var require_option = __commonJS((exports) => {
461
590
  throw new InvalidArgumentError(`Allowed choices are ${this.argChoices.join(", ")}.`);
462
591
  }
463
592
  if (this.variadic) {
464
- return this._concatValue(arg, previous);
593
+ return this._collectValue(arg, previous);
465
594
  }
466
595
  return arg;
467
596
  };
@@ -474,7 +603,14 @@ var require_option = __commonJS((exports) => {
474
603
  return this.short.replace(/^-/, "");
475
604
  }
476
605
  attributeName() {
477
- return camelcase(this.name().replace(/^no-/, ""));
606
+ if (this.negate) {
607
+ return camelcase(this.name().replace(/^no-/, ""));
608
+ }
609
+ return camelcase(this.name());
610
+ }
611
+ helpGroup(heading) {
612
+ this.helpGroupHeading = heading;
613
+ return this;
478
614
  }
479
615
  is(arg) {
480
616
  return this.short === arg || this.long === arg;
@@ -519,14 +655,38 @@ var require_option = __commonJS((exports) => {
519
655
  function splitOptionFlags(flags) {
520
656
  let shortFlag;
521
657
  let longFlag;
522
- const flagParts = flags.split(/[ |,]+/);
523
- if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
658
+ const shortFlagExp = /^-[^-]$/;
659
+ const longFlagExp = /^--[^-]/;
660
+ const flagParts = flags.split(/[ |,]+/).concat("guard");
661
+ if (shortFlagExp.test(flagParts[0]))
524
662
  shortFlag = flagParts.shift();
525
- longFlag = flagParts.shift();
526
- if (!shortFlag && /^-[^-]$/.test(longFlag)) {
663
+ if (longFlagExp.test(flagParts[0]))
664
+ longFlag = flagParts.shift();
665
+ if (!shortFlag && shortFlagExp.test(flagParts[0]))
666
+ shortFlag = flagParts.shift();
667
+ if (!shortFlag && longFlagExp.test(flagParts[0])) {
527
668
  shortFlag = longFlag;
528
- longFlag = undefined;
529
- }
669
+ longFlag = flagParts.shift();
670
+ }
671
+ if (flagParts[0].startsWith("-")) {
672
+ const unsupportedFlag = flagParts[0];
673
+ const baseError = `option creation failed due to '${unsupportedFlag}' in option flags '${flags}'`;
674
+ if (/^-[^-][^-]/.test(unsupportedFlag))
675
+ throw new Error(`${baseError}
676
+ - a short flag is a single dash and a single character
677
+ - either use a single dash and a single character (for a short flag)
678
+ - or use a double dash for a long option (and can have two, like '--ws, --workspace')`);
679
+ if (shortFlagExp.test(unsupportedFlag))
680
+ throw new Error(`${baseError}
681
+ - too many short flags`);
682
+ if (longFlagExp.test(unsupportedFlag))
683
+ throw new Error(`${baseError}
684
+ - too many long flags`);
685
+ throw new Error(`${baseError}
686
+ - unrecognised flag format`);
687
+ }
688
+ if (shortFlag === undefined && longFlag === undefined)
689
+ throw new Error(`option creation failed due to no flags found in '${flags}'.`);
530
690
  return { shortFlag, longFlag };
531
691
  }
532
692
  exports.Option = Option;
@@ -615,7 +775,7 @@ var require_command = __commonJS((exports) => {
615
775
  var process2 = __require("node:process");
616
776
  var { Argument, humanReadableArgName } = require_argument();
617
777
  var { CommanderError } = require_error();
618
- var { Help } = require_help();
778
+ var { Help, stripColor } = require_help();
619
779
  var { Option, DualOptions } = require_option();
620
780
  var { suggestSimilar } = require_suggestSimilar();
621
781
 
@@ -626,7 +786,7 @@ var require_command = __commonJS((exports) => {
626
786
  this.options = [];
627
787
  this.parent = null;
628
788
  this._allowUnknownOption = false;
629
- this._allowExcessArguments = true;
789
+ this._allowExcessArguments = false;
630
790
  this.registeredArguments = [];
631
791
  this._args = this.registeredArguments;
632
792
  this.args = [];
@@ -653,18 +813,25 @@ var require_command = __commonJS((exports) => {
653
813
  this._lifeCycleHooks = {};
654
814
  this._showHelpAfterError = false;
655
815
  this._showSuggestionAfterError = true;
816
+ this._savedState = null;
656
817
  this._outputConfiguration = {
657
818
  writeOut: (str) => process2.stdout.write(str),
658
819
  writeErr: (str) => process2.stderr.write(str),
820
+ outputError: (str, write) => write(str),
659
821
  getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : undefined,
660
822
  getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : undefined,
661
- outputError: (str, write) => write(str)
823
+ getOutHasColors: () => useColor() ?? (process2.stdout.isTTY && process2.stdout.hasColors?.()),
824
+ getErrHasColors: () => useColor() ?? (process2.stderr.isTTY && process2.stderr.hasColors?.()),
825
+ stripColor: (str) => stripColor(str)
662
826
  };
663
827
  this._hidden = false;
664
828
  this._helpOption = undefined;
665
829
  this._addImplicitHelpCommand = undefined;
666
830
  this._helpCommand = undefined;
667
831
  this._helpConfiguration = {};
832
+ this._helpGroupHeading = undefined;
833
+ this._defaultCommandGroup = undefined;
834
+ this._defaultOptionGroup = undefined;
668
835
  }
669
836
  copyInheritedSettings(sourceCommand) {
670
837
  this._outputConfiguration = sourceCommand._outputConfiguration;
@@ -729,7 +896,10 @@ var require_command = __commonJS((exports) => {
729
896
  configureOutput(configuration) {
730
897
  if (configuration === undefined)
731
898
  return this._outputConfiguration;
732
- Object.assign(this._outputConfiguration, configuration);
899
+ this._outputConfiguration = {
900
+ ...this._outputConfiguration,
901
+ ...configuration
902
+ };
733
903
  return this;
734
904
  }
735
905
  showHelpAfterError(displayHelp = true) {
@@ -760,12 +930,12 @@ var require_command = __commonJS((exports) => {
760
930
  createArgument(name, description) {
761
931
  return new Argument(name, description);
762
932
  }
763
- argument(name, description, fn, defaultValue) {
933
+ argument(name, description, parseArg, defaultValue) {
764
934
  const argument = this.createArgument(name, description);
765
- if (typeof fn === "function") {
766
- argument.default(defaultValue).argParser(fn);
935
+ if (typeof parseArg === "function") {
936
+ argument.default(defaultValue).argParser(parseArg);
767
937
  } else {
768
- argument.default(fn);
938
+ argument.default(parseArg);
769
939
  }
770
940
  this.addArgument(argument);
771
941
  return this;
@@ -778,7 +948,7 @@ var require_command = __commonJS((exports) => {
778
948
  }
779
949
  addArgument(argument) {
780
950
  const previousArgument = this.registeredArguments.slice(-1)[0];
781
- if (previousArgument && previousArgument.variadic) {
951
+ if (previousArgument?.variadic) {
782
952
  throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);
783
953
  }
784
954
  if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {
@@ -790,10 +960,13 @@ var require_command = __commonJS((exports) => {
790
960
  helpCommand(enableOrNameAndArgs, description) {
791
961
  if (typeof enableOrNameAndArgs === "boolean") {
792
962
  this._addImplicitHelpCommand = enableOrNameAndArgs;
963
+ if (enableOrNameAndArgs && this._defaultCommandGroup) {
964
+ this._initCommandGroup(this._getHelpCommand());
965
+ }
793
966
  return this;
794
967
  }
795
- enableOrNameAndArgs = enableOrNameAndArgs ?? "help [command]";
796
- const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/);
968
+ const nameAndArgs = enableOrNameAndArgs ?? "help [command]";
969
+ const [, helpName, helpArgs] = nameAndArgs.match(/([^ ]+) *(.*)/);
797
970
  const helpDescription = description ?? "display help for command";
798
971
  const helpCommand = this.createCommand(helpName);
799
972
  helpCommand.helpOption(false);
@@ -803,6 +976,8 @@ var require_command = __commonJS((exports) => {
803
976
  helpCommand.description(helpDescription);
804
977
  this._addImplicitHelpCommand = true;
805
978
  this._helpCommand = helpCommand;
979
+ if (enableOrNameAndArgs || description)
980
+ this._initCommandGroup(helpCommand);
806
981
  return this;
807
982
  }
808
983
  addHelpCommand(helpCommand, deprecatedDescription) {
@@ -812,6 +987,7 @@ var require_command = __commonJS((exports) => {
812
987
  }
813
988
  this._addImplicitHelpCommand = true;
814
989
  this._helpCommand = helpCommand;
990
+ this._initCommandGroup(helpCommand);
815
991
  return this;
816
992
  }
817
993
  _getHelpCommand() {
@@ -891,6 +1067,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
891
1067
  throw new Error(`Cannot add option '${option.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
892
1068
  - already used by option '${matchingOption.flags}'`);
893
1069
  }
1070
+ this._initOptionGroup(option);
894
1071
  this.options.push(option);
895
1072
  }
896
1073
  _registerCommand(command) {
@@ -903,6 +1080,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
903
1080
  const newCmd = knownBy(command).join("|");
904
1081
  throw new Error(`cannot add command '${newCmd}' as already have command '${existingCmd}'`);
905
1082
  }
1083
+ this._initCommandGroup(command);
906
1084
  this.commands.push(command);
907
1085
  }
908
1086
  addOption(option) {
@@ -925,7 +1103,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
925
1103
  if (val !== null && option.parseArg) {
926
1104
  val = this._callParseArg(option, val, oldValue, invalidValueMessage);
927
1105
  } else if (val !== null && option.variadic) {
928
- val = option._concatValue(val, oldValue);
1106
+ val = option._collectValue(val, oldValue);
929
1107
  }
930
1108
  if (val == null) {
931
1109
  if (option.negate) {
@@ -1090,15 +1268,53 @@ Expecting one of '${allowedValues.join("', '")}'`);
1090
1268
  return userArgs;
1091
1269
  }
1092
1270
  parse(argv, parseOptions) {
1271
+ this._prepareForParse();
1093
1272
  const userArgs = this._prepareUserArgs(argv, parseOptions);
1094
1273
  this._parseCommand([], userArgs);
1095
1274
  return this;
1096
1275
  }
1097
1276
  async parseAsync(argv, parseOptions) {
1277
+ this._prepareForParse();
1098
1278
  const userArgs = this._prepareUserArgs(argv, parseOptions);
1099
1279
  await this._parseCommand([], userArgs);
1100
1280
  return this;
1101
1281
  }
1282
+ _prepareForParse() {
1283
+ if (this._savedState === null) {
1284
+ this.saveStateBeforeParse();
1285
+ } else {
1286
+ this.restoreStateBeforeParse();
1287
+ }
1288
+ }
1289
+ saveStateBeforeParse() {
1290
+ this._savedState = {
1291
+ _name: this._name,
1292
+ _optionValues: { ...this._optionValues },
1293
+ _optionValueSources: { ...this._optionValueSources }
1294
+ };
1295
+ }
1296
+ restoreStateBeforeParse() {
1297
+ if (this._storeOptionsAsProperties)
1298
+ throw new Error(`Can not call parse again when storeOptionsAsProperties is true.
1299
+ - either make a new Command for each call to parse, or stop storing options as properties`);
1300
+ this._name = this._savedState._name;
1301
+ this._scriptPath = null;
1302
+ this.rawArgs = [];
1303
+ this._optionValues = { ...this._savedState._optionValues };
1304
+ this._optionValueSources = { ...this._savedState._optionValueSources };
1305
+ this.args = [];
1306
+ this.processedArgs = [];
1307
+ }
1308
+ _checkForMissingExecutable(executableFile, executableDir, subcommandName) {
1309
+ if (fs.existsSync(executableFile))
1310
+ return;
1311
+ const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
1312
+ const executableMissing = `'${executableFile}' does not exist
1313
+ - if '${subcommandName}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
1314
+ - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
1315
+ - ${executableDirMessage}`;
1316
+ throw new Error(executableMissing);
1317
+ }
1102
1318
  _executeSubCommand(subcommand, args) {
1103
1319
  args = args.slice();
1104
1320
  let launchWithNode = false;
@@ -1122,7 +1338,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1122
1338
  let resolvedScriptPath;
1123
1339
  try {
1124
1340
  resolvedScriptPath = fs.realpathSync(this._scriptPath);
1125
- } catch (err) {
1341
+ } catch {
1126
1342
  resolvedScriptPath = this._scriptPath;
1127
1343
  }
1128
1344
  executableDir = path.resolve(path.dirname(resolvedScriptPath), executableDir);
@@ -1148,6 +1364,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1148
1364
  proc = childProcess.spawn(executableFile, args, { stdio: "inherit" });
1149
1365
  }
1150
1366
  } else {
1367
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1151
1368
  args.unshift(executableFile);
1152
1369
  args = incrementNodeInspectorPort(process2.execArgv).concat(args);
1153
1370
  proc = childProcess.spawn(process2.execPath, args, { stdio: "inherit" });
@@ -1173,12 +1390,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1173
1390
  });
1174
1391
  proc.on("error", (err) => {
1175
1392
  if (err.code === "ENOENT") {
1176
- const executableDirMessage = executableDir ? `searched for local subcommand relative to directory '${executableDir}'` : "no directory for search for local subcommand, use .executableDir() to supply a custom directory";
1177
- const executableMissing = `'${executableFile}' does not exist
1178
- - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead
1179
- - if the default executable name is not suitable, use the executableFile option to supply a custom name or path
1180
- - ${executableDirMessage}`;
1181
- throw new Error(executableMissing);
1393
+ this._checkForMissingExecutable(executableFile, executableDir, subcommand._name);
1182
1394
  } else if (err.code === "EACCES") {
1183
1395
  throw new Error(`'${executableFile}' not executable`);
1184
1396
  }
@@ -1196,6 +1408,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1196
1408
  const subCommand = this._findCommand(commandName);
1197
1409
  if (!subCommand)
1198
1410
  this.help({ error: true });
1411
+ subCommand._prepareForParse();
1199
1412
  let promiseChain;
1200
1413
  promiseChain = this._chainOrCallSubCommandHook(promiseChain, subCommand, "preSubcommand");
1201
1414
  promiseChain = this._chainOrCall(promiseChain, () => {
@@ -1265,7 +1478,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1265
1478
  this.processedArgs = processedArgs;
1266
1479
  }
1267
1480
  _chainOrCall(promise, fn) {
1268
- if (promise && promise.then && typeof promise.then === "function") {
1481
+ if (promise?.then && typeof promise.then === "function") {
1269
1482
  return promise.then(() => fn());
1270
1483
  }
1271
1484
  return fn();
@@ -1342,7 +1555,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1342
1555
  promiseChain = this._chainOrCallHooks(promiseChain, "postAction");
1343
1556
  return promiseChain;
1344
1557
  }
1345
- if (this.parent && this.parent.listenerCount(commandEvent)) {
1558
+ if (this.parent?.listenerCount(commandEvent)) {
1346
1559
  checkForUnknownOptions();
1347
1560
  this._processArguments();
1348
1561
  this.parent.emit(commandEvent, operands, unknown);
@@ -1404,24 +1617,31 @@ Expecting one of '${allowedValues.join("', '")}'`);
1404
1617
  cmd._checkForConflictingLocalOptions();
1405
1618
  });
1406
1619
  }
1407
- parseOptions(argv) {
1620
+ parseOptions(args) {
1408
1621
  const operands = [];
1409
1622
  const unknown = [];
1410
1623
  let dest = operands;
1411
- const args = argv.slice();
1412
1624
  function maybeOption(arg) {
1413
1625
  return arg.length > 1 && arg[0] === "-";
1414
1626
  }
1627
+ const negativeNumberArg = (arg) => {
1628
+ if (!/^-(\d+|\d*\.\d+)(e[+-]?\d+)?$/.test(arg))
1629
+ return false;
1630
+ return !this._getCommandAndAncestors().some((cmd) => cmd.options.map((opt) => opt.short).some((short) => /^-\d$/.test(short)));
1631
+ };
1415
1632
  let activeVariadicOption = null;
1416
- while (args.length) {
1417
- const arg = args.shift();
1633
+ let activeGroup = null;
1634
+ let i = 0;
1635
+ while (i < args.length || activeGroup) {
1636
+ const arg = activeGroup ?? args[i++];
1637
+ activeGroup = null;
1418
1638
  if (arg === "--") {
1419
1639
  if (dest === unknown)
1420
1640
  dest.push(arg);
1421
- dest.push(...args);
1641
+ dest.push(...args.slice(i));
1422
1642
  break;
1423
1643
  }
1424
- if (activeVariadicOption && !maybeOption(arg)) {
1644
+ if (activeVariadicOption && (!maybeOption(arg) || negativeNumberArg(arg))) {
1425
1645
  this.emit(`option:${activeVariadicOption.name()}`, arg);
1426
1646
  continue;
1427
1647
  }
@@ -1430,14 +1650,14 @@ Expecting one of '${allowedValues.join("', '")}'`);
1430
1650
  const option = this._findOption(arg);
1431
1651
  if (option) {
1432
1652
  if (option.required) {
1433
- const value = args.shift();
1653
+ const value = args[i++];
1434
1654
  if (value === undefined)
1435
1655
  this.optionMissingArgument(option);
1436
1656
  this.emit(`option:${option.name()}`, value);
1437
1657
  } else if (option.optional) {
1438
1658
  let value = null;
1439
- if (args.length > 0 && !maybeOption(args[0])) {
1440
- value = args.shift();
1659
+ if (i < args.length && (!maybeOption(args[i]) || negativeNumberArg(args[i]))) {
1660
+ value = args[i++];
1441
1661
  }
1442
1662
  this.emit(`option:${option.name()}`, value);
1443
1663
  } else {
@@ -1454,7 +1674,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1454
1674
  this.emit(`option:${option.name()}`, arg.slice(2));
1455
1675
  } else {
1456
1676
  this.emit(`option:${option.name()}`);
1457
- args.unshift(`-${arg.slice(2)}`);
1677
+ activeGroup = `-${arg.slice(2)}`;
1458
1678
  }
1459
1679
  continue;
1460
1680
  }
@@ -1467,31 +1687,24 @@ Expecting one of '${allowedValues.join("', '")}'`);
1467
1687
  continue;
1468
1688
  }
1469
1689
  }
1470
- if (maybeOption(arg)) {
1690
+ if (dest === operands && maybeOption(arg) && !(this.commands.length === 0 && negativeNumberArg(arg))) {
1471
1691
  dest = unknown;
1472
1692
  }
1473
1693
  if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
1474
1694
  if (this._findCommand(arg)) {
1475
1695
  operands.push(arg);
1476
- if (args.length > 0)
1477
- unknown.push(...args);
1696
+ unknown.push(...args.slice(i));
1478
1697
  break;
1479
1698
  } else if (this._getHelpCommand() && arg === this._getHelpCommand().name()) {
1480
- operands.push(arg);
1481
- if (args.length > 0)
1482
- operands.push(...args);
1699
+ operands.push(arg, ...args.slice(i));
1483
1700
  break;
1484
1701
  } else if (this._defaultCommandName) {
1485
- unknown.push(arg);
1486
- if (args.length > 0)
1487
- unknown.push(...args);
1702
+ unknown.push(arg, ...args.slice(i));
1488
1703
  break;
1489
1704
  }
1490
1705
  }
1491
1706
  if (this._passThroughOptions) {
1492
- dest.push(arg);
1493
- if (args.length > 0)
1494
- dest.push(...args);
1707
+ dest.push(arg, ...args.slice(i));
1495
1708
  break;
1496
1709
  }
1497
1710
  dest.push(arg);
@@ -1702,6 +1915,32 @@ Expecting one of '${allowedValues.join("', '")}'`);
1702
1915
  this._name = str;
1703
1916
  return this;
1704
1917
  }
1918
+ helpGroup(heading) {
1919
+ if (heading === undefined)
1920
+ return this._helpGroupHeading ?? "";
1921
+ this._helpGroupHeading = heading;
1922
+ return this;
1923
+ }
1924
+ commandsGroup(heading) {
1925
+ if (heading === undefined)
1926
+ return this._defaultCommandGroup ?? "";
1927
+ this._defaultCommandGroup = heading;
1928
+ return this;
1929
+ }
1930
+ optionsGroup(heading) {
1931
+ if (heading === undefined)
1932
+ return this._defaultOptionGroup ?? "";
1933
+ this._defaultOptionGroup = heading;
1934
+ return this;
1935
+ }
1936
+ _initOptionGroup(option) {
1937
+ if (this._defaultOptionGroup && !option.helpGroupHeading)
1938
+ option.helpGroup(this._defaultOptionGroup);
1939
+ }
1940
+ _initCommandGroup(cmd) {
1941
+ if (this._defaultCommandGroup && !cmd.helpGroup())
1942
+ cmd.helpGroup(this._defaultCommandGroup);
1943
+ }
1705
1944
  nameFromFilename(filename) {
1706
1945
  this._name = path.basename(filename, path.extname(filename));
1707
1946
  return this;
@@ -1714,23 +1953,38 @@ Expecting one of '${allowedValues.join("', '")}'`);
1714
1953
  }
1715
1954
  helpInformation(contextOptions) {
1716
1955
  const helper = this.createHelp();
1717
- if (helper.helpWidth === undefined) {
1718
- helper.helpWidth = contextOptions && contextOptions.error ? this._outputConfiguration.getErrHelpWidth() : this._outputConfiguration.getOutHelpWidth();
1719
- }
1720
- return helper.formatHelp(this, helper);
1956
+ const context = this._getOutputContext(contextOptions);
1957
+ helper.prepareContext({
1958
+ error: context.error,
1959
+ helpWidth: context.helpWidth,
1960
+ outputHasColors: context.hasColors
1961
+ });
1962
+ const text = helper.formatHelp(this, helper);
1963
+ if (context.hasColors)
1964
+ return text;
1965
+ return this._outputConfiguration.stripColor(text);
1721
1966
  }
1722
- _getHelpContext(contextOptions) {
1967
+ _getOutputContext(contextOptions) {
1723
1968
  contextOptions = contextOptions || {};
1724
- const context = { error: !!contextOptions.error };
1725
- let write;
1726
- if (context.error) {
1727
- write = (arg) => this._outputConfiguration.writeErr(arg);
1969
+ const error = !!contextOptions.error;
1970
+ let baseWrite;
1971
+ let hasColors;
1972
+ let helpWidth;
1973
+ if (error) {
1974
+ baseWrite = (str) => this._outputConfiguration.writeErr(str);
1975
+ hasColors = this._outputConfiguration.getErrHasColors();
1976
+ helpWidth = this._outputConfiguration.getErrHelpWidth();
1728
1977
  } else {
1729
- write = (arg) => this._outputConfiguration.writeOut(arg);
1730
- }
1731
- context.write = contextOptions.write || write;
1732
- context.command = this;
1733
- return context;
1978
+ baseWrite = (str) => this._outputConfiguration.writeOut(str);
1979
+ hasColors = this._outputConfiguration.getOutHasColors();
1980
+ helpWidth = this._outputConfiguration.getOutHelpWidth();
1981
+ }
1982
+ const write = (str) => {
1983
+ if (!hasColors)
1984
+ str = this._outputConfiguration.stripColor(str);
1985
+ return baseWrite(str);
1986
+ };
1987
+ return { error, write, hasColors, helpWidth };
1734
1988
  }
1735
1989
  outputHelp(contextOptions) {
1736
1990
  let deprecatedCallback;
@@ -1738,35 +1992,44 @@ Expecting one of '${allowedValues.join("', '")}'`);
1738
1992
  deprecatedCallback = contextOptions;
1739
1993
  contextOptions = undefined;
1740
1994
  }
1741
- const context = this._getHelpContext(contextOptions);
1742
- this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", context));
1743
- this.emit("beforeHelp", context);
1744
- let helpInformation = this.helpInformation(context);
1995
+ const outputContext = this._getOutputContext(contextOptions);
1996
+ const eventContext = {
1997
+ error: outputContext.error,
1998
+ write: outputContext.write,
1999
+ command: this
2000
+ };
2001
+ this._getCommandAndAncestors().reverse().forEach((command) => command.emit("beforeAllHelp", eventContext));
2002
+ this.emit("beforeHelp", eventContext);
2003
+ let helpInformation = this.helpInformation({ error: outputContext.error });
1745
2004
  if (deprecatedCallback) {
1746
2005
  helpInformation = deprecatedCallback(helpInformation);
1747
2006
  if (typeof helpInformation !== "string" && !Buffer.isBuffer(helpInformation)) {
1748
2007
  throw new Error("outputHelp callback must return a string or a Buffer");
1749
2008
  }
1750
2009
  }
1751
- context.write(helpInformation);
2010
+ outputContext.write(helpInformation);
1752
2011
  if (this._getHelpOption()?.long) {
1753
2012
  this.emit(this._getHelpOption().long);
1754
2013
  }
1755
- this.emit("afterHelp", context);
1756
- this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", context));
2014
+ this.emit("afterHelp", eventContext);
2015
+ this._getCommandAndAncestors().forEach((command) => command.emit("afterAllHelp", eventContext));
1757
2016
  }
1758
2017
  helpOption(flags, description) {
1759
2018
  if (typeof flags === "boolean") {
1760
2019
  if (flags) {
1761
- this._helpOption = this._helpOption ?? undefined;
2020
+ if (this._helpOption === null)
2021
+ this._helpOption = undefined;
2022
+ if (this._defaultOptionGroup) {
2023
+ this._initOptionGroup(this._getHelpOption());
2024
+ }
1762
2025
  } else {
1763
2026
  this._helpOption = null;
1764
2027
  }
1765
2028
  return this;
1766
2029
  }
1767
- flags = flags ?? "-h, --help";
1768
- description = description ?? "display help for command";
1769
- this._helpOption = this.createOption(flags, description);
2030
+ this._helpOption = this.createOption(flags ?? "-h, --help", description ?? "display help for command");
2031
+ if (flags || description)
2032
+ this._initOptionGroup(this._helpOption);
1770
2033
  return this;
1771
2034
  }
1772
2035
  _getHelpOption() {
@@ -1777,11 +2040,12 @@ Expecting one of '${allowedValues.join("', '")}'`);
1777
2040
  }
1778
2041
  addHelpOption(option) {
1779
2042
  this._helpOption = option;
2043
+ this._initOptionGroup(option);
1780
2044
  return this;
1781
2045
  }
1782
2046
  help(contextOptions) {
1783
2047
  this.outputHelp(contextOptions);
1784
- let exitCode = process2.exitCode || 0;
2048
+ let exitCode = Number(process2.exitCode ?? 0);
1785
2049
  if (exitCode === 0 && contextOptions && typeof contextOptions !== "function" && contextOptions.error) {
1786
2050
  exitCode = 1;
1787
2051
  }
@@ -1846,7 +2110,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
1846
2110
  return arg;
1847
2111
  });
1848
2112
  }
2113
+ function useColor() {
2114
+ if (process2.env.NO_COLOR || process2.env.FORCE_COLOR === "0" || process2.env.FORCE_COLOR === "false")
2115
+ return false;
2116
+ if (process2.env.FORCE_COLOR || process2.env.CLICOLOR_FORCE !== undefined)
2117
+ return true;
2118
+ return;
2119
+ }
1849
2120
  exports.Command = Command;
2121
+ exports.useColor = useColor;
1850
2122
  });
1851
2123
 
1852
2124
  // node_modules/commander/index.js
@@ -13151,7 +13423,7 @@ var {
13151
13423
  // package.json
13152
13424
  var package_default = {
13153
13425
  name: "postgresai",
13154
- version: "0.15.0-dev.7",
13426
+ version: "0.15.0-dev.9",
13155
13427
  description: "postgres_ai CLI",
13156
13428
  license: "Apache-2.0",
13157
13429
  private: false,
@@ -13179,7 +13451,7 @@ var package_default = {
13179
13451
  "embed-metrics": "bun run scripts/embed-metrics.ts",
13180
13452
  "embed-checkup-dictionary": "bun run scripts/embed-checkup-dictionary.ts",
13181
13453
  "embed-all": "bun run embed-metrics && bun run embed-checkup-dictionary",
13182
- build: `bun run embed-all && bun build ./bin/postgres-ai.ts --outdir ./dist/bin --target node && node -e "const fs=require('fs');const f='./dist/bin/postgres-ai.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('#!/usr/bin/env bun','#!/usr/bin/env node'))" && cp -r ./sql ./dist/sql`,
13454
+ build: `bun run embed-all && bun build ./bin/postgres-ai.ts --outdir ./dist/bin --target node && node -e "const fs=require('fs');const f='./dist/bin/postgres-ai.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('#!/usr/bin/env bun','#!/usr/bin/env node'))" && cp -r ./sql ./dist/sql && cp ../instances.demo.yml ./instances.demo.yml`,
13183
13455
  prepublishOnly: "npm run build",
13184
13456
  start: "bun ./bin/postgres-ai.ts --help",
13185
13457
  "start:node": "node ./dist/bin/postgres-ai.js --help",
@@ -13192,7 +13464,7 @@ var package_default = {
13192
13464
  },
13193
13465
  dependencies: {
13194
13466
  "@modelcontextprotocol/sdk": "^1.20.2",
13195
- commander: "^12.1.0",
13467
+ commander: "^14.0.3",
13196
13468
  "js-yaml": "^4.1.0",
13197
13469
  pg: "^8.16.3"
13198
13470
  },
@@ -13202,7 +13474,7 @@ var package_default = {
13202
13474
  "@types/pg": "^8.15.6",
13203
13475
  ajv: "^8.17.1",
13204
13476
  "ajv-formats": "^3.0.1",
13205
- typescript: "^5.9.3"
13477
+ typescript: "^6.0.2"
13206
13478
  },
13207
13479
  publishConfig: {
13208
13480
  access: "public"
@@ -15982,7 +16254,7 @@ var Result = import_lib.default.Result;
15982
16254
  var TypeOverrides = import_lib.default.TypeOverrides;
15983
16255
  var defaults = import_lib.default.defaults;
15984
16256
  // package.json
15985
- var version = "0.15.0-dev.7";
16257
+ var version = "0.15.0-dev.9";
15986
16258
  var package_default2 = {
15987
16259
  name: "postgresai",
15988
16260
  version,
@@ -16013,7 +16285,7 @@ var package_default2 = {
16013
16285
  "embed-metrics": "bun run scripts/embed-metrics.ts",
16014
16286
  "embed-checkup-dictionary": "bun run scripts/embed-checkup-dictionary.ts",
16015
16287
  "embed-all": "bun run embed-metrics && bun run embed-checkup-dictionary",
16016
- build: `bun run embed-all && bun build ./bin/postgres-ai.ts --outdir ./dist/bin --target node && node -e "const fs=require('fs');const f='./dist/bin/postgres-ai.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('#!/usr/bin/env bun','#!/usr/bin/env node'))" && cp -r ./sql ./dist/sql`,
16288
+ build: `bun run embed-all && bun build ./bin/postgres-ai.ts --outdir ./dist/bin --target node && node -e "const fs=require('fs');const f='./dist/bin/postgres-ai.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('#!/usr/bin/env bun','#!/usr/bin/env node'))" && cp -r ./sql ./dist/sql && cp ../instances.demo.yml ./instances.demo.yml`,
16017
16289
  prepublishOnly: "npm run build",
16018
16290
  start: "bun ./bin/postgres-ai.ts --help",
16019
16291
  "start:node": "node ./dist/bin/postgres-ai.js --help",
@@ -16026,7 +16298,7 @@ var package_default2 = {
16026
16298
  },
16027
16299
  dependencies: {
16028
16300
  "@modelcontextprotocol/sdk": "^1.20.2",
16029
- commander: "^12.1.0",
16301
+ commander: "^14.0.3",
16030
16302
  "js-yaml": "^4.1.0",
16031
16303
  pg: "^8.16.3"
16032
16304
  },
@@ -16036,7 +16308,7 @@ var package_default2 = {
16036
16308
  "@types/pg": "^8.15.6",
16037
16309
  ajv: "^8.17.1",
16038
16310
  "ajv-formats": "^3.0.1",
16039
- typescript: "^5.9.3"
16311
+ typescript: "^6.0.2"
16040
16312
  },
16041
16313
  publishConfig: {
16042
16314
  access: "public"
@@ -25439,8 +25711,9 @@ function isSslNegotiationError(err) {
25439
25711
  }
25440
25712
  async function connectWithSslFallback(ClientClass, adminConn, verbose) {
25441
25713
  const tryConnect = async (config2) => {
25442
- const client = new ClientClass(config2);
25714
+ const client = new ClientClass({ ...config2, connectionTimeoutMillis: 1e4 });
25443
25715
  await client.connect();
25716
+ await client.query("SET statement_timeout = '30s'");
25444
25717
  return client;
25445
25718
  };
25446
25719
  if (!adminConn.sslFallbackEnabled) {
@@ -25909,7 +26182,12 @@ async function verifyInitSetup(params) {
25909
26182
  if (!schemaExistsRes.rows?.[0]?.ok) {
25910
26183
  missingRequired.push("USAGE on schema postgres_ai");
25911
26184
  }
25912
- const viewExistsRes = await params.client.query("select to_regclass('postgres_ai.pg_statistic') is not null as ok");
26185
+ const viewExistsRes = await params.client.query(`
26186
+ select case
26187
+ when not has_schema_privilege(current_user, 'postgres_ai', 'USAGE') then null
26188
+ else to_regclass('postgres_ai.pg_statistic') is not null
26189
+ end as ok
26190
+ `);
25913
26191
  if (!viewExistsRes.rows?.[0]?.ok) {
25914
26192
  missingRequired.push("view postgres_ai.pg_statistic exists");
25915
26193
  } else {
@@ -25993,6 +26271,119 @@ async function verifyInitSetup(params) {
25993
26271
  } catch {}
25994
26272
  }
25995
26273
  }
26274
+ async function checkCurrentUserPermissions(client) {
26275
+ const sql = `
26276
+ with permission_checks as (
26277
+ select
26278
+ format('connect on database %I', current_database()) as permission_name,
26279
+ 'required' as status,
26280
+ has_database_privilege(current_user, current_database(), 'connect') as granted
26281
+
26282
+ union all
26283
+
26284
+ select
26285
+ 'pg_monitor role membership' as permission_name,
26286
+ 'required' as status,
26287
+ -- CASE guarantees evaluation order: pg_has_role() is only called if the
26288
+ -- pg_monitor role exists, avoiding ERROR on PostgreSQL < 10 or when dropped.
26289
+ case
26290
+ when not exists (select from pg_roles where rolname = 'pg_monitor')
26291
+ then false
26292
+ else pg_has_role(current_user, 'pg_monitor', 'member')
26293
+ end as granted
26294
+
26295
+ union all
26296
+
26297
+ select
26298
+ 'select on pg_catalog.pg_index' as permission_name,
26299
+ 'required' as status,
26300
+ has_table_privilege(current_user, 'pg_catalog.pg_index', 'select') as granted
26301
+
26302
+ union all
26303
+
26304
+ select
26305
+ 'postgres_ai.pg_statistic view exists' as permission_name,
26306
+ 'optional' as status,
26307
+ case
26308
+ when not has_schema_privilege(current_user, 'postgres_ai', 'USAGE') then null
26309
+ else to_regclass('postgres_ai.pg_statistic') is not null
26310
+ end as granted
26311
+
26312
+ union all
26313
+
26314
+ select
26315
+ 'select on postgres_ai.pg_statistic' as permission_name,
26316
+ 'optional' as status,
26317
+ case
26318
+ when not has_schema_privilege(current_user, 'postgres_ai', 'USAGE') then null
26319
+ when to_regclass('postgres_ai.pg_statistic') is null then null
26320
+ else has_table_privilege(current_user, 'postgres_ai.pg_statistic', 'select')
26321
+ end as granted
26322
+ )
26323
+ select
26324
+ permission_name,
26325
+ status,
26326
+ granted,
26327
+ case
26328
+ when status = 'required' and not coalesce(granted, false) then
26329
+ case
26330
+ when permission_name like 'connect%' then
26331
+ format('grant connect on database %I to %I;', current_database(), current_user)
26332
+ when permission_name = 'pg_monitor role membership' then
26333
+ format('grant pg_monitor to %I;', current_user)
26334
+ when permission_name like 'select on pg_catalog.pg_index' then
26335
+ format('grant select on pg_catalog.pg_index to %I;', current_user)
26336
+ end
26337
+ when permission_name = 'postgres_ai.pg_statistic view exists' and granted = false then
26338
+ '-- create postgres_ai.pg_statistic view (see setup script)'
26339
+ when permission_name = 'select on postgres_ai.pg_statistic' and granted = false then
26340
+ format('grant select on postgres_ai.pg_statistic to %I;', current_user)
26341
+ else null
26342
+ end as fix_command
26343
+ from permission_checks
26344
+ order by
26345
+ case status when 'required' then 1 else 2 end,
26346
+ permission_name;
26347
+ `;
26348
+ const res = await client.query(sql);
26349
+ const rows = res.rows;
26350
+ const missingRequired = rows.filter((r) => r.status === "required" && r.granted !== true);
26351
+ const missingOptional = rows.filter((r) => r.status === "optional" && r.granted === false);
26352
+ return {
26353
+ ok: missingRequired.length === 0,
26354
+ rows,
26355
+ missingRequired,
26356
+ missingOptional
26357
+ };
26358
+ }
26359
+ function formatPermissionCheckMessages(result) {
26360
+ const warnings = [];
26361
+ const errors3 = [];
26362
+ for (const row of result.missingOptional) {
26363
+ const fix = row.fix_command ? ` Fix: ${row.fix_command}` : "";
26364
+ warnings.push(`Warning: optional permission missing — ${row.permission_name}.${fix}`);
26365
+ }
26366
+ if (!result.ok) {
26367
+ errors3.push(`Error: the database user is missing required permissions.
26368
+ `);
26369
+ errors3.push("Missing permissions:");
26370
+ for (const row of result.missingRequired) {
26371
+ errors3.push(` - ${row.permission_name}`);
26372
+ }
26373
+ const fixes = result.missingRequired.map((r) => r.fix_command).filter(Boolean);
26374
+ if (fixes.length > 0) {
26375
+ errors3.push(`
26376
+ To fix, run the following as a superuser:
26377
+ `);
26378
+ for (const fix of fixes) {
26379
+ errors3.push(` ${fix}`);
26380
+ }
26381
+ }
26382
+ errors3.push(`
26383
+ Alternatively, run 'postgresai prepare-db' to set up permissions automatically.`);
26384
+ }
26385
+ return { failed: !result.ok, warnings, errors: errors3 };
26386
+ }
25996
26387
 
25997
26388
  // lib/supabase.ts
25998
26389
  var SUPABASE_API_BASE = "https://api.supabase.com";
@@ -26155,6 +26546,9 @@ class SupabaseClient {
26155
26546
  }
26156
26547
  }
26157
26548
  async function fetchPoolerDatabaseUrl(config2, username) {
26549
+ if (!isValidProjectRef(config2.projectRef)) {
26550
+ throw new Error(`Invalid Supabase project reference format: "${config2.projectRef}". Expected 10-30 alphanumeric characters.`);
26551
+ }
26158
26552
  const url = `${SUPABASE_API_BASE}/v1/projects/${encodeURIComponent(config2.projectRef)}/config/database/pooler`;
26159
26553
  const suffix = `.${config2.projectRef}`;
26160
26554
  const effectiveUsername = username.endsWith(suffix) ? username : `${username}${suffix}`;
@@ -26327,7 +26721,10 @@ async function verifyInitSetupViaSupabase(params) {
26327
26721
  missingRequired.push("USAGE on schema postgres_ai");
26328
26722
  }
26329
26723
  }
26330
- const viewExistsRes = await params.client.query("SELECT to_regclass('postgres_ai.pg_statistic') IS NOT NULL as ok", true);
26724
+ const viewExistsRes = await params.client.query(`SELECT CASE
26725
+ WHEN NOT has_schema_privilege(current_user, 'postgres_ai', 'USAGE') THEN NULL
26726
+ ELSE to_regclass('postgres_ai.pg_statistic') IS NOT NULL
26727
+ END as ok`, true);
26331
26728
  if (!viewExistsRes.rows?.[0]?.ok) {
26332
26729
  missingRequired.push("view postgres_ai.pg_statistic exists");
26333
26730
  } else {
@@ -27472,6 +27869,65 @@ limit 1000
27472
27869
  },
27473
27870
  gauges: ["real_size_mib", "table_size_mib", "extra_size", "extra_pct", "fillfactor", "bloat_size", "bloat_pct", "is_na", "reltuples"],
27474
27871
  statement_timeout_seconds: 15
27872
+ },
27873
+ pg_stat_io: {
27874
+ description: "Collects I/O statistics from the PostgreSQL `pg_stat_io` view (available in PostgreSQL 16+). Provides insights into read and write operations by backend type, including the number of operations, MiB transferred (divided by 1048576), and time spent on I/O. This metric is essential for monitoring I/O performance and identifying potential bottlenecks in disk operations. The data is aggregated by backend type with a total row included via ROLLUP.",
27875
+ sqls: {
27876
+ 11: "; -- pg_stat_io only available in PostgreSQL 16+",
27877
+ 16: `select /* pgwatch_generated */
27878
+ (extract(epoch from now()) * 1e9)::int8 as epoch_ns,
27879
+ current_database() as tag_datname,
27880
+ coalesce(backend_type, 'total') as tag_backend_type,
27881
+ sum(coalesce(reads, 0))::int8 as reads,
27882
+ (sum(coalesce(reads, 0) * op_bytes) / 1048576.0)::int8 as read_bytes_mb,
27883
+ sum(coalesce(read_time, 0))::int8 as read_time_ms,
27884
+ sum(coalesce(writes, 0))::int8 as writes,
27885
+ (sum(coalesce(writes, 0) * op_bytes) / 1048576.0)::int8 as write_bytes_mb,
27886
+ sum(coalesce(write_time, 0))::int8 as write_time_ms,
27887
+ sum(coalesce(writebacks, 0))::int8 as writebacks,
27888
+ (sum(coalesce(writebacks, 0) * op_bytes) / 1048576.0)::int8 as writeback_bytes_mb,
27889
+ sum(coalesce(writeback_time, 0))::int8 as writeback_time_ms,
27890
+ sum(coalesce(fsyncs, 0))::int8 as fsyncs,
27891
+ sum(coalesce(fsync_time, 0))::int8 as fsync_time_ms,
27892
+ sum(coalesce(extends, 0))::int8 as extends,
27893
+ (sum(coalesce(extends, 0) * op_bytes) / 1048576.0)::int8 as extend_bytes_mb,
27894
+ sum(coalesce(hits, 0))::int8 as hits,
27895
+ sum(coalesce(evictions, 0))::int8 as evictions,
27896
+ sum(coalesce(reuses, 0))::int8 as reuses,
27897
+ max(extract(epoch from now() - stats_reset)::int) as stats_reset_s
27898
+ from
27899
+ pg_stat_io
27900
+ group by
27901
+ rollup (backend_type)`,
27902
+ 18: `select /* pgwatch_generated */
27903
+ (extract(epoch from now()) * 1e9)::int8 as epoch_ns,
27904
+ current_database() as tag_datname,
27905
+ coalesce(backend_type, 'total') as tag_backend_type,
27906
+ sum(coalesce(reads, 0))::int8 as reads,
27907
+ (sum(coalesce(read_bytes, 0)) / 1048576.0)::int8 as read_bytes_mb,
27908
+ sum(coalesce(read_time, 0))::int8 as read_time_ms,
27909
+ sum(coalesce(writes, 0))::int8 as writes,
27910
+ (sum(coalesce(write_bytes, 0)) / 1048576.0)::int8 as write_bytes_mb,
27911
+ sum(coalesce(write_time, 0))::int8 as write_time_ms,
27912
+ sum(coalesce(writebacks, 0))::int8 as writebacks,
27913
+ -- PostgreSQL 18 has no writeback_bytes column; rows with NULL op_bytes contribute zero by design.
27914
+ (sum(coalesce(writebacks, 0) * coalesce(op_bytes, 0)) / 1048576.0)::int8 as writeback_bytes_mb,
27915
+ sum(coalesce(writeback_time, 0))::int8 as writeback_time_ms,
27916
+ sum(coalesce(fsyncs, 0))::int8 as fsyncs,
27917
+ sum(coalesce(fsync_time, 0))::int8 as fsync_time_ms,
27918
+ sum(coalesce(extends, 0))::int8 as extends,
27919
+ (sum(coalesce(extend_bytes, 0)) / 1048576.0)::int8 as extend_bytes_mb,
27920
+ sum(coalesce(hits, 0))::int8 as hits,
27921
+ sum(coalesce(evictions, 0))::int8 as evictions,
27922
+ sum(coalesce(reuses, 0))::int8 as reuses,
27923
+ max(extract(epoch from now() - stats_reset)::int) as stats_reset_s
27924
+ from
27925
+ pg_stat_io
27926
+ group by
27927
+ rollup (backend_type)`
27928
+ },
27929
+ gauges: ["*"],
27930
+ statement_timeout_seconds: 15
27475
27931
  }
27476
27932
  };
27477
27933
 
@@ -27497,7 +27953,8 @@ var METRIC_NAMES = {
27497
27953
  settings: "settings",
27498
27954
  dbStats: "db_stats",
27499
27955
  dbSize: "db_size",
27500
- statsReset: "stats_reset"
27956
+ statsReset: "stats_reset",
27957
+ I001: "pg_stat_io"
27501
27958
  };
27502
27959
  function transformMetricRow(row) {
27503
27960
  const result = {};
@@ -29044,6 +29501,140 @@ async function generateG003(client, nodeName) {
29044
29501
  };
29045
29502
  return report;
29046
29503
  }
29504
+ async function getIOStatistics(client, pgMajorVersion = 0, metricSqlOverride) {
29505
+ if (pgMajorVersion < 16) {
29506
+ return [];
29507
+ }
29508
+ try {
29509
+ const sql = metricSqlOverride ?? getMetricSql(METRIC_NAMES.I001, pgMajorVersion);
29510
+ if (!sql || sql.trim().startsWith(";")) {
29511
+ return [];
29512
+ }
29513
+ const result = await client.query(sql);
29514
+ return result.rows.map((row) => {
29515
+ const transformed = transformMetricRow(row);
29516
+ return {
29517
+ backend_type: String(transformed.backend_type || "unknown"),
29518
+ reads: parseInt(String(transformed.reads || 0), 10),
29519
+ read_bytes_mb: parseInt(String(transformed.read_bytes_mb || 0), 10),
29520
+ read_time_ms: parseInt(String(transformed.read_time_ms || 0), 10),
29521
+ writes: parseInt(String(transformed.writes || 0), 10),
29522
+ write_bytes_mb: parseInt(String(transformed.write_bytes_mb || 0), 10),
29523
+ write_time_ms: parseInt(String(transformed.write_time_ms || 0), 10),
29524
+ writebacks: parseInt(String(transformed.writebacks || 0), 10),
29525
+ writeback_bytes_mb: parseInt(String(transformed.writeback_bytes_mb || 0), 10),
29526
+ writeback_time_ms: parseInt(String(transformed.writeback_time_ms || 0), 10),
29527
+ fsyncs: parseInt(String(transformed.fsyncs || 0), 10),
29528
+ fsync_time_ms: parseInt(String(transformed.fsync_time_ms || 0), 10),
29529
+ extends: parseInt(String(transformed.extends || 0), 10),
29530
+ extend_bytes_mb: parseInt(String(transformed.extend_bytes_mb || 0), 10),
29531
+ hits: parseInt(String(transformed.hits || 0), 10),
29532
+ evictions: parseInt(String(transformed.evictions || 0), 10),
29533
+ reuses: parseInt(String(transformed.reuses || 0), 10)
29534
+ };
29535
+ });
29536
+ } catch (err) {
29537
+ const errorMsg = err instanceof Error ? err.message : String(err);
29538
+ console.log(`[I001] Error fetching I/O statistics: ${errorMsg}`);
29539
+ return [];
29540
+ }
29541
+ }
29542
+ async function generateI001(client, nodeName) {
29543
+ const report = createBaseReport("I001", "I/O statistics (pg_stat_io)", nodeName);
29544
+ const postgresVersion = await getPostgresVersion(client);
29545
+ const parsedPgMajorVersion = parseInt(postgresVersion.server_major_ver, 10);
29546
+ const pgMajorVersion = Number.isFinite(parsedPgMajorVersion) ? parsedPgMajorVersion : 0;
29547
+ if (pgMajorVersion < 16) {
29548
+ report.results[nodeName] = {
29549
+ data: {
29550
+ available: false,
29551
+ min_version_required: "16",
29552
+ by_backend_type: [],
29553
+ analysis: {
29554
+ total_read_mb: 0,
29555
+ total_write_mb: 0,
29556
+ total_io_time_ms: 0,
29557
+ read_hit_ratio_pct: 0,
29558
+ avg_read_time_ms: null,
29559
+ avg_write_time_ms: null
29560
+ },
29561
+ stats_reset_s: null
29562
+ },
29563
+ postgres_version: postgresVersion
29564
+ };
29565
+ return report;
29566
+ }
29567
+ const ioStats = await getIOStatistics(client, pgMajorVersion);
29568
+ ioStats.sort((a, b) => {
29569
+ if (a.backend_type === "total")
29570
+ return -1;
29571
+ if (b.backend_type === "total")
29572
+ return 1;
29573
+ return a.backend_type.localeCompare(b.backend_type);
29574
+ });
29575
+ let totalStats = ioStats.find((s) => s.backend_type === "total");
29576
+ if (!totalStats && ioStats.length > 0) {
29577
+ totalStats = {
29578
+ backend_type: "total",
29579
+ reads: ioStats.reduce((sum, s) => sum + s.reads, 0),
29580
+ read_bytes_mb: ioStats.reduce((sum, s) => sum + s.read_bytes_mb, 0),
29581
+ read_time_ms: ioStats.reduce((sum, s) => sum + s.read_time_ms, 0),
29582
+ writes: ioStats.reduce((sum, s) => sum + s.writes, 0),
29583
+ write_bytes_mb: ioStats.reduce((sum, s) => sum + s.write_bytes_mb, 0),
29584
+ write_time_ms: ioStats.reduce((sum, s) => sum + s.write_time_ms, 0),
29585
+ writebacks: ioStats.reduce((sum, s) => sum + s.writebacks, 0),
29586
+ writeback_bytes_mb: ioStats.reduce((sum, s) => sum + s.writeback_bytes_mb, 0),
29587
+ writeback_time_ms: ioStats.reduce((sum, s) => sum + s.writeback_time_ms, 0),
29588
+ fsyncs: ioStats.reduce((sum, s) => sum + s.fsyncs, 0),
29589
+ fsync_time_ms: ioStats.reduce((sum, s) => sum + s.fsync_time_ms, 0),
29590
+ extends: ioStats.reduce((sum, s) => sum + (s.extends || 0), 0),
29591
+ extend_bytes_mb: ioStats.reduce((sum, s) => sum + (s.extend_bytes_mb || 0), 0),
29592
+ hits: ioStats.reduce((sum, s) => sum + s.hits, 0),
29593
+ evictions: ioStats.reduce((sum, s) => sum + s.evictions, 0),
29594
+ reuses: ioStats.reduce((sum, s) => sum + s.reuses, 0)
29595
+ };
29596
+ }
29597
+ const totalReadMb = totalStats?.read_bytes_mb || 0;
29598
+ const totalWriteMb = totalStats?.write_bytes_mb || 0;
29599
+ const totalReadTime = totalStats?.read_time_ms || 0;
29600
+ const totalWriteTime = totalStats?.write_time_ms || 0;
29601
+ const totalIoTimeMs = totalReadTime + totalWriteTime;
29602
+ const totalReads = totalStats?.reads || 0;
29603
+ const totalWrites = totalStats?.writes || 0;
29604
+ const totalHits = totalStats?.hits || 0;
29605
+ const totalRequests = totalHits + totalReads;
29606
+ const readHitRatioPct = totalRequests > 0 ? Math.round(totalHits / totalRequests * 1e4) / 100 : 0;
29607
+ const avgReadTimeMs = totalReads > 0 ? Math.round(totalReadTime / totalReads * 1000) / 1000 : null;
29608
+ const avgWriteTimeMs = totalWrites > 0 ? Math.round(totalWriteTime / totalWrites * 1000) / 1000 : null;
29609
+ let statsResetS = null;
29610
+ try {
29611
+ const resetResult = await client.query(`
29612
+ select max(extract(epoch from now() - stats_reset)::int) as stats_reset_s
29613
+ from pg_stat_io
29614
+ `);
29615
+ if (resetResult.rows.length > 0 && resetResult.rows[0].stats_reset_s !== null) {
29616
+ const parsedStatsResetS = parseInt(resetResult.rows[0].stats_reset_s, 10);
29617
+ statsResetS = Number.isFinite(parsedStatsResetS) ? parsedStatsResetS : null;
29618
+ }
29619
+ } catch (err) {}
29620
+ report.results[nodeName] = {
29621
+ data: {
29622
+ available: ioStats.length > 0,
29623
+ by_backend_type: ioStats,
29624
+ analysis: {
29625
+ total_read_mb: totalReadMb,
29626
+ total_write_mb: totalWriteMb,
29627
+ total_io_time_ms: totalIoTimeMs,
29628
+ read_hit_ratio_pct: readHitRatioPct,
29629
+ avg_read_time_ms: avgReadTimeMs,
29630
+ avg_write_time_ms: avgWriteTimeMs
29631
+ },
29632
+ stats_reset_s: statsResetS
29633
+ },
29634
+ postgres_version: postgresVersion
29635
+ };
29636
+ return report;
29637
+ }
29047
29638
  var REPORT_GENERATORS = {
29048
29639
  A002: generateA002,
29049
29640
  A003: generateA003,
@@ -29059,7 +29650,8 @@ var REPORT_GENERATORS = {
29059
29650
  G003: generateG003,
29060
29651
  H001: generateH001,
29061
29652
  H002: generateH002,
29062
- H004: generateH004
29653
+ H004: generateH004,
29654
+ I001: generateI001
29063
29655
  };
29064
29656
  var CHECK_INFO = (() => {
29065
29657
  const fullMap = buildCheckInfoMap();
@@ -29095,6 +29687,7 @@ function getCheckupEntry(code) {
29095
29687
  }
29096
29688
 
29097
29689
  // lib/checkup-api.ts
29690
+ import * as http2 from "http";
29098
29691
  import * as https from "https";
29099
29692
  import { URL as URL3 } from "url";
29100
29693
  var DEFAULT_RETRY_CONFIG = {
@@ -29224,7 +29817,15 @@ async function postRpc(params) {
29224
29817
  clearTimeout(timeoutId);
29225
29818
  resolve6(value);
29226
29819
  };
29227
- const req = https.request(url, {
29820
+ if (url.protocol === "http:") {
29821
+ const hostname = url.hostname.replace(/^\[|\]$/g, "");
29822
+ const isLoopback = ["localhost", "127.0.0.1", "::1"].includes(hostname);
29823
+ if (!isLoopback && process.env.CHECKUP_ALLOW_HTTP !== "1") {
29824
+ throw new Error(`Refusing to send API key over plaintext HTTP to '${url.host}'. ` + `Use https://, a loopback hostname, or set CHECKUP_ALLOW_HTTP=1.`);
29825
+ }
29826
+ }
29827
+ const transport = url.protocol === "http:" ? http2 : https;
29828
+ const req = transport.request(url, {
29228
29829
  method: "POST",
29229
29830
  headers,
29230
29831
  signal: controller.signal
@@ -29594,18 +30195,13 @@ function closeReadline() {
29594
30195
  rl = null;
29595
30196
  }
29596
30197
  }
29597
- async function execPromise(command) {
29598
- return new Promise((resolve7, reject) => {
29599
- childProcess.exec(command, (error2, stdout, stderr) => {
29600
- if (error2) {
29601
- const err = error2;
29602
- err.code = typeof error2.code === "number" ? error2.code : 1;
29603
- reject(err);
29604
- } else {
29605
- resolve7({ stdout, stderr });
29606
- }
29607
- });
29608
- });
30198
+ function stripMatchingQuotes(value) {
30199
+ const trimmed = value.trim();
30200
+ const quote = trimmed[0];
30201
+ if (trimmed.length >= 2 && (quote === '"' || quote === "'") && trimmed.endsWith(quote)) {
30202
+ return trimmed.slice(1, -1);
30203
+ }
30204
+ return trimmed;
29609
30205
  }
29610
30206
  async function execFilePromise(file, args) {
29611
30207
  return new Promise((resolve7, reject) => {
@@ -30963,6 +31559,20 @@ Usage: postgresai checkup ${checkId} postgresql://user@host:5432/dbname
30963
31559
  spinner.update("Connecting to Postgres");
30964
31560
  const connResult = await connectWithSslFallback(Client, adminConn);
30965
31561
  client = connResult.client;
31562
+ spinner.update("Checking database permissions");
31563
+ const permCheck = await checkCurrentUserPermissions(client);
31564
+ const permMessages = formatPermissionCheckMessages(permCheck);
31565
+ for (const w of permMessages.warnings) {
31566
+ console.error(w);
31567
+ }
31568
+ if (permMessages.failed) {
31569
+ spinner.stop();
31570
+ for (const e of permMessages.errors) {
31571
+ console.error(e);
31572
+ }
31573
+ process.exitCode = 1;
31574
+ return;
31575
+ }
30966
31576
  let reports;
30967
31577
  if (checkId === "ALL") {
30968
31578
  reports = await generateAllReports(client, opts.nodeName, (p) => {
@@ -31270,12 +31880,12 @@ async function runCompose(args, grafanaPassword) {
31270
31880
  if (!env.VM_AUTH_USERNAME) {
31271
31881
  const m = envContent.match(/^VM_AUTH_USERNAME=([^\r\n]+)/m);
31272
31882
  if (m)
31273
- env.VM_AUTH_USERNAME = m[1].trim().replace(/^["']|["']$/g, "");
31883
+ env.VM_AUTH_USERNAME = stripMatchingQuotes(m[1]);
31274
31884
  }
31275
31885
  if (!env.VM_AUTH_PASSWORD) {
31276
31886
  const m = envContent.match(/^VM_AUTH_PASSWORD=([^\r\n]+)/m);
31277
31887
  if (m)
31278
- env.VM_AUTH_PASSWORD = m[1].trim().replace(/^["']|["']$/g, "");
31888
+ env.VM_AUTH_PASSWORD = stripMatchingQuotes(m[1]);
31279
31889
  }
31280
31890
  } catch (err) {
31281
31891
  if (process.env.DEBUG) {
@@ -31322,6 +31932,9 @@ mon.command("local-install").description("install local monitoring stack (genera
31322
31932
  const envFile = path6.resolve(projectDir, ".env");
31323
31933
  let existingRegistry = null;
31324
31934
  let existingPassword = null;
31935
+ let existingReplicatorPassword = null;
31936
+ let existingVmAuthUsername = null;
31937
+ let existingVmAuthPassword = null;
31325
31938
  if (fs6.existsSync(envFile)) {
31326
31939
  const existingEnv = fs6.readFileSync(envFile, "utf8");
31327
31940
  const registryMatch = existingEnv.match(/^PGAI_REGISTRY=(.+)$/m);
@@ -31330,6 +31943,15 @@ mon.command("local-install").description("install local monitoring stack (genera
31330
31943
  const pwdMatch = existingEnv.match(/^GF_SECURITY_ADMIN_PASSWORD=(.+)$/m);
31331
31944
  if (pwdMatch)
31332
31945
  existingPassword = pwdMatch[1].trim();
31946
+ const replicatorPwdMatch = existingEnv.match(/^REPLICATOR_PASSWORD=(.+)$/m);
31947
+ if (replicatorPwdMatch)
31948
+ existingReplicatorPassword = replicatorPwdMatch[1].trim();
31949
+ const vmAuthUserMatch = existingEnv.match(/^VM_AUTH_USERNAME=(.+)$/m);
31950
+ if (vmAuthUserMatch)
31951
+ existingVmAuthUsername = stripMatchingQuotes(vmAuthUserMatch[1]);
31952
+ const vmAuthPasswordMatch = existingEnv.match(/^VM_AUTH_PASSWORD=(.+)$/m);
31953
+ if (vmAuthPasswordMatch)
31954
+ existingVmAuthPassword = stripMatchingQuotes(vmAuthPasswordMatch[1]);
31333
31955
  }
31334
31956
  const imageTag = opts.tag || package_default.version;
31335
31957
  const envLines = [`PGAI_TAG=${imageTag}`];
@@ -31339,6 +31961,9 @@ mon.command("local-install").description("install local monitoring stack (genera
31339
31961
  if (existingPassword) {
31340
31962
  envLines.push(`GF_SECURITY_ADMIN_PASSWORD=${existingPassword}`);
31341
31963
  }
31964
+ envLines.push(`REPLICATOR_PASSWORD=${existingReplicatorPassword || crypto2.randomBytes(32).toString("hex")}`);
31965
+ envLines.push(`VM_AUTH_USERNAME=${existingVmAuthUsername || "vmauth"}`);
31966
+ envLines.push(`VM_AUTH_PASSWORD=${existingVmAuthPassword || crypto2.randomBytes(18).toString("base64")}`);
31342
31967
  fs6.writeFileSync(envFile, envLines.join(`
31343
31968
  `) + `
31344
31969
  `, { encoding: "utf8", mode: 384 });
@@ -31462,18 +32087,23 @@ Use demo mode without API key: postgres-ai mon local-install --demo`);
31462
32087
  console.log(`\u2713 Monitoring target '${instanceName}' added
31463
32088
  `);
31464
32089
  console.log("Testing connection to the added instance...");
31465
- try {
31466
- const client = new Client({ connectionString: connStr });
31467
- await client.connect();
31468
- const result = await client.query("select version();");
31469
- console.log("\u2713 Connection successful");
31470
- console.log(`${result.rows[0].version}
32090
+ {
32091
+ let testClient = null;
32092
+ try {
32093
+ testClient = new Client({ connectionString: connStr, connectionTimeoutMillis: 1e4 });
32094
+ await testClient.connect();
32095
+ const result = await testClient.query("select version();");
32096
+ console.log("\u2713 Connection successful");
32097
+ console.log(`${result.rows[0].version}
31471
32098
  `);
31472
- await client.end();
31473
- } catch (error2) {
31474
- const message = error2 instanceof Error ? error2.message : String(error2);
31475
- console.error(`\u2717 Connection failed: ${message}
32099
+ } catch (error2) {
32100
+ const message = error2 instanceof Error ? error2.message : String(error2);
32101
+ console.error(`\u2717 Connection failed: ${message}
31476
32102
  `);
32103
+ } finally {
32104
+ if (testClient)
32105
+ await testClient.end();
32106
+ }
31477
32107
  }
31478
32108
  } else if (opts.yes) {
31479
32109
  console.log("Auto-yes mode: no database URL provided, skipping database setup");
@@ -31517,18 +32147,23 @@ You can provide either:`);
31517
32147
  console.log(`\u2713 Monitoring target '${instanceName}' added
31518
32148
  `);
31519
32149
  console.log("Testing connection to the added instance...");
31520
- try {
31521
- const client = new Client({ connectionString: connStr });
31522
- await client.connect();
31523
- const result = await client.query("select version();");
31524
- console.log("\u2713 Connection successful");
31525
- console.log(`${result.rows[0].version}
32150
+ {
32151
+ let testClient = null;
32152
+ try {
32153
+ testClient = new Client({ connectionString: connStr, connectionTimeoutMillis: 1e4 });
32154
+ await testClient.connect();
32155
+ const result = await testClient.query("select version();");
32156
+ console.log("\u2713 Connection successful");
32157
+ console.log(`${result.rows[0].version}
31526
32158
  `);
31527
- await client.end();
31528
- } catch (error2) {
31529
- const message = error2 instanceof Error ? error2.message : String(error2);
31530
- console.error(`\u2717 Connection failed: ${message}
32159
+ } catch (error2) {
32160
+ const message = error2 instanceof Error ? error2.message : String(error2);
32161
+ console.error(`\u2717 Connection failed: ${message}
31531
32162
  `);
32163
+ } finally {
32164
+ if (testClient)
32165
+ await testClient.end();
32166
+ }
31532
32167
  }
31533
32168
  }
31534
32169
  } else {
@@ -31588,9 +32223,8 @@ Searched: ${demoCandidates.join(", ")}
31588
32223
  }
31589
32224
  if (!grafanaPassword) {
31590
32225
  console.log("Generating secure Grafana password...");
31591
- const { stdout: password } = await execPromise(`openssl rand -base64 12 | tr -d '
31592
- '`);
31593
- grafanaPassword = password.trim();
32226
+ const { stdout: password } = await execFilePromise("openssl", ["rand", "-base64", "12"]);
32227
+ grafanaPassword = password.trim().replace(/\n/g, "");
31594
32228
  let configContent = "";
31595
32229
  if (fs6.existsSync(cfgPath)) {
31596
32230
  const stats = fs6.statSync(cfgPath);
@@ -31619,17 +32253,16 @@ Searched: ${demoCandidates.join(", ")}
31619
32253
  const userMatch = envContent.match(/^VM_AUTH_USERNAME=([^\r\n]+)/m);
31620
32254
  const passMatch = envContent.match(/^VM_AUTH_PASSWORD=([^\r\n]+)/m);
31621
32255
  if (userMatch)
31622
- vmAuthUsername = userMatch[1].trim().replace(/^["']|["']$/g, "");
32256
+ vmAuthUsername = stripMatchingQuotes(userMatch[1]);
31623
32257
  if (passMatch)
31624
- vmAuthPassword = passMatch[1].trim().replace(/^["']|["']$/g, "");
32258
+ vmAuthPassword = stripMatchingQuotes(passMatch[1]);
31625
32259
  }
31626
32260
  if (!vmAuthUsername || !vmAuthPassword) {
31627
32261
  console.log("Generating VictoriaMetrics auth credentials...");
31628
32262
  vmAuthUsername = vmAuthUsername || "vmauth";
31629
32263
  if (!vmAuthPassword) {
31630
- const { stdout: vmPass } = await execPromise(`openssl rand -base64 12 | tr -d '
31631
- '`);
31632
- vmAuthPassword = vmPass.trim();
32264
+ const { stdout: vmPass } = await execFilePromise("openssl", ["rand", "-base64", "12"]);
32265
+ vmAuthPassword = vmPass.trim().replace(/\n/g, "");
31633
32266
  }
31634
32267
  let envContent = "";
31635
32268
  if (fs6.existsSync(envFile2)) {
@@ -31873,12 +32506,12 @@ mon.command("update").description("update monitoring stack").action(async () =>
31873
32506
  return;
31874
32507
  }
31875
32508
  console.log("Fetching latest changes...");
31876
- await execPromise("git fetch origin");
31877
- const { stdout: branch } = await execPromise("git rev-parse --abbrev-ref HEAD");
32509
+ await execFilePromise("git", ["fetch", "origin"]);
32510
+ const { stdout: branch } = await execFilePromise("git", ["rev-parse", "--abbrev-ref", "HEAD"]);
31878
32511
  const currentBranch = branch.trim();
31879
32512
  console.log(`Current branch: ${currentBranch}`);
31880
32513
  console.log("Pulling latest changes...");
31881
- const { stdout: pullOut } = await execPromise("git pull origin " + currentBranch);
32514
+ const { stdout: pullOut } = await execFilePromise("git", ["pull", "origin", currentBranch]);
31882
32515
  console.log(pullOut);
31883
32516
  console.log(`
31884
32517
  Updating Docker images...`);
@@ -32092,7 +32725,8 @@ targets.command("add [connStr] [name]").description("add monitoring target datab
32092
32725
  } catch (err) {
32093
32726
  const isFile = fs6.existsSync(file) && !fs6.lstatSync(file).isDirectory();
32094
32727
  const content2 = isFile ? fs6.readFileSync(file, "utf8") : "";
32095
- if (new RegExp(`^- name: ${instanceName}$`, "m").test(content2)) {
32728
+ const escapedName = instanceName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32729
+ if (new RegExp(`^- name: ${escapedName}$`, "m").test(content2)) {
32096
32730
  console.error(`Monitoring target '${instanceName}' already exists`);
32097
32731
  process.exitCode = 1;
32098
32732
  return;
@@ -32174,7 +32808,7 @@ targets.command("test <name>").description("test monitoring target database conn
32174
32808
  return;
32175
32809
  }
32176
32810
  console.log(`Testing connection to monitoring target '${name}'...`);
32177
- const client = new Client({ connectionString: instance.conn_str });
32811
+ const client = new Client({ connectionString: instance.conn_str, connectionTimeoutMillis: 1e4 });
32178
32812
  try {
32179
32813
  await client.connect();
32180
32814
  const result = await client.query("select version();");
@@ -32443,9 +33077,8 @@ mon.command("generate-grafana-password").description("generate Grafana password
32443
33077
  const { projectDir } = await resolveOrInitPaths();
32444
33078
  const cfgPath = path6.resolve(projectDir, ".pgwatch-config");
32445
33079
  try {
32446
- const { stdout: password } = await execPromise(`openssl rand -base64 12 | tr -d '
32447
- '`);
32448
- const newPassword = password.trim();
33080
+ const { stdout: password } = await execFilePromise("openssl", ["rand", "-base64", "12"]);
33081
+ const newPassword = password.trim().replace(/\n/g, "");
32449
33082
  if (!newPassword) {
32450
33083
  console.error("Failed to generate password");
32451
33084
  process.exitCode = 1;
@@ -32524,8 +33157,8 @@ Grafana credentials:`);
32524
33157
  if (vmUser && vmPass) {
32525
33158
  console.log(`
32526
33159
  VictoriaMetrics credentials:`);
32527
- console.log(` Username: ${vmUser[1].trim().replace(/^["']|["']$/g, "")}`);
32528
- console.log(` Password: ${vmPass[1].trim().replace(/^["']|["']$/g, "")}`);
33160
+ console.log(` Username: ${stripMatchingQuotes(vmUser[1])}`);
33161
+ console.log(` Password: ${stripMatchingQuotes(vmPass[1])}`);
32529
33162
  }
32530
33163
  }
32531
33164
  console.log("");
@@ -33264,7 +33897,7 @@ mcp.command("install [client]").description("install MCP server configuration fo
33264
33897
  try {
33265
33898
  let pgaiPath;
33266
33899
  try {
33267
- const execPath = await execPromise("which pgai");
33900
+ const execPath = await execFilePromise("which", ["pgai"]);
33268
33901
  pgaiPath = execPath.stdout.trim();
33269
33902
  } catch {
33270
33903
  pgaiPath = "pgai";
@@ -33272,7 +33905,7 @@ mcp.command("install [client]").description("install MCP server configuration fo
33272
33905
  if (client === "claude-code") {
33273
33906
  console.log("Installing PostgresAI MCP server for Claude Code...");
33274
33907
  try {
33275
- const { stdout, stderr } = await execPromise(`claude mcp add -s user postgresai ${pgaiPath} mcp start`);
33908
+ const { stdout, stderr } = await execFilePromise("claude", ["mcp", "add", "-s", "user", "postgresai", pgaiPath, "mcp", "start"]);
33276
33909
  if (stdout)
33277
33910
  console.log(stdout);
33278
33911
  if (stderr)