postgresai 0.15.0-dev.2 → 0.15.0-dev.3
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/bin/postgres-ai.ts +10 -9
- package/dist/bin/postgres-ai.js +11 -7
- package/package.json +1 -1
- package/test/checkup.test.ts +28 -0
- package/test/reports.cli.test.ts +84 -0
package/bin/postgres-ai.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
|
|
3
|
-
import { Command } from "commander";
|
|
3
|
+
import { Command, Option } from "commander";
|
|
4
4
|
import pkg from "../package.json";
|
|
5
5
|
import * as config from "../lib/config";
|
|
6
6
|
import * as yaml from "js-yaml";
|
|
@@ -343,7 +343,8 @@ function writeReportFiles(reports: Record<string, any>, outputPath: string): voi
|
|
|
343
343
|
for (const [checkId, report] of Object.entries(reports)) {
|
|
344
344
|
const filePath = path.join(outputPath, `${checkId}.json`);
|
|
345
345
|
fs.writeFileSync(filePath, JSON.stringify(report, null, 2), "utf8");
|
|
346
|
-
|
|
346
|
+
const title = report.checkTitle || checkId;
|
|
347
|
+
console.log(`✓ ${checkId} ${title}: ${filePath}`);
|
|
347
348
|
}
|
|
348
349
|
}
|
|
349
350
|
|
|
@@ -1925,8 +1926,8 @@ program
|
|
|
1925
1926
|
}
|
|
1926
1927
|
}
|
|
1927
1928
|
|
|
1928
|
-
// Output JSON to stdout
|
|
1929
|
-
if (shouldPrintJson) {
|
|
1929
|
+
// Output JSON to stdout (unless --output is specified, in which case files are written instead)
|
|
1930
|
+
if (shouldPrintJson && !outputPath) {
|
|
1930
1931
|
console.log(JSON.stringify(reports, null, 2));
|
|
1931
1932
|
}
|
|
1932
1933
|
|
|
@@ -4198,11 +4199,11 @@ reports
|
|
|
4198
4199
|
.command("list")
|
|
4199
4200
|
.description("list checkup reports")
|
|
4200
4201
|
.option("--project-id <id>", "filter by project id", (v: string) => parseInt(v, 10))
|
|
4201
|
-
.
|
|
4202
|
-
.option("--limit <n>", "max number of reports to return (default: 20)", (v: string) => parseInt(v, 10))
|
|
4202
|
+
.addOption(new Option("--status <status>", "filter by status (e.g., completed)").hideHelp())
|
|
4203
|
+
.option("--limit <n>", "max number of reports to return (default: 20, max: 100)", (v: string) => { const n = parseInt(v, 10); return Number.isNaN(n) ? 20 : Math.max(1, Math.min(n, 100)); })
|
|
4203
4204
|
.option("--before <date>", "show reports created before this date (YYYY-MM-DD, DD.MM.YYYY, etc.)")
|
|
4204
4205
|
.option("--all", "fetch all reports (paginated automatically)")
|
|
4205
|
-
.
|
|
4206
|
+
.addOption(new Option("--debug", "enable debug output").hideHelp())
|
|
4206
4207
|
.option("--json", "output raw JSON")
|
|
4207
4208
|
.action(async (opts: { projectId?: number; status?: string; limit?: number; before?: string; all?: boolean; debug?: boolean; json?: boolean }) => {
|
|
4208
4209
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching reports...");
|
|
@@ -4260,7 +4261,7 @@ reports
|
|
|
4260
4261
|
.description("list files of a checkup report (metadata only, no content)")
|
|
4261
4262
|
.option("--type <type>", "filter by file type: json, md")
|
|
4262
4263
|
.option("--check-id <id>", "filter by check ID (e.g., H002)")
|
|
4263
|
-
.
|
|
4264
|
+
.addOption(new Option("--debug", "enable debug output").hideHelp())
|
|
4264
4265
|
.option("--json", "output raw JSON")
|
|
4265
4266
|
.action(async (reportId: string | undefined, opts: { type?: "json" | "md"; checkId?: string; debug?: boolean; json?: boolean }) => {
|
|
4266
4267
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching report files...");
|
|
@@ -4317,7 +4318,7 @@ reports
|
|
|
4317
4318
|
.option("--check-id <id>", "filter by check ID (e.g., H002)")
|
|
4318
4319
|
.option("--formatted", "render markdown with ANSI styling (experimental)")
|
|
4319
4320
|
.option("-o, --output <dir>", "save files to directory (uses original filenames)")
|
|
4320
|
-
.
|
|
4321
|
+
.addOption(new Option("--debug", "enable debug output").hideHelp())
|
|
4321
4322
|
.option("--json", "output raw JSON")
|
|
4322
4323
|
.action(async (reportId: string | undefined, opts: { type?: "json" | "md"; checkId?: string; formatted?: boolean; output?: string; debug?: boolean; json?: boolean }) => {
|
|
4323
4324
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching report data...");
|
package/dist/bin/postgres-ai.js
CHANGED
|
@@ -13064,7 +13064,7 @@ var {
|
|
|
13064
13064
|
// package.json
|
|
13065
13065
|
var package_default = {
|
|
13066
13066
|
name: "postgresai",
|
|
13067
|
-
version: "0.15.0-dev.
|
|
13067
|
+
version: "0.15.0-dev.3",
|
|
13068
13068
|
description: "postgres_ai CLI",
|
|
13069
13069
|
license: "Apache-2.0",
|
|
13070
13070
|
private: false,
|
|
@@ -15892,7 +15892,7 @@ var Result = import_lib.default.Result;
|
|
|
15892
15892
|
var TypeOverrides = import_lib.default.TypeOverrides;
|
|
15893
15893
|
var defaults = import_lib.default.defaults;
|
|
15894
15894
|
// package.json
|
|
15895
|
-
var version = "0.15.0-dev.
|
|
15895
|
+
var version = "0.15.0-dev.3";
|
|
15896
15896
|
var package_default2 = {
|
|
15897
15897
|
name: "postgresai",
|
|
15898
15898
|
version,
|
|
@@ -29543,7 +29543,8 @@ function writeReportFiles(reports, outputPath) {
|
|
|
29543
29543
|
for (const [checkId, report] of Object.entries(reports)) {
|
|
29544
29544
|
const filePath = path5.join(outputPath, `${checkId}.json`);
|
|
29545
29545
|
fs5.writeFileSync(filePath, JSON.stringify(report, null, 2), "utf8");
|
|
29546
|
-
|
|
29546
|
+
const title = report.checkTitle || checkId;
|
|
29547
|
+
console.log(`\u2713 ${checkId} ${title}: ${filePath}`);
|
|
29547
29548
|
}
|
|
29548
29549
|
}
|
|
29549
29550
|
function printUploadSummary(summary, projectWasGenerated, useStderr, reports) {
|
|
@@ -30780,7 +30781,7 @@ Usage: postgresai checkup ${checkId} postgresql://user@host:5432/dbname
|
|
|
30780
30781
|
}
|
|
30781
30782
|
}
|
|
30782
30783
|
}
|
|
30783
|
-
if (shouldPrintJson) {
|
|
30784
|
+
if (shouldPrintJson && !outputPath) {
|
|
30784
30785
|
console.log(JSON.stringify(reports, null, 2));
|
|
30785
30786
|
}
|
|
30786
30787
|
const hadOutput = shouldPrintJson || shouldConvertMarkdown || outputPath || uploadSummary;
|
|
@@ -32591,7 +32592,10 @@ issues.command("update-action-item <actionItemId>").description("update an actio
|
|
|
32591
32592
|
}
|
|
32592
32593
|
});
|
|
32593
32594
|
var reports = program2.command("reports").description("checkup reports management");
|
|
32594
|
-
reports.command("list").description("list checkup reports").option("--project-id <id>", "filter by project id", (v) => parseInt(v, 10)).
|
|
32595
|
+
reports.command("list").description("list checkup reports").option("--project-id <id>", "filter by project id", (v) => parseInt(v, 10)).addOption(new Option("--status <status>", "filter by status (e.g., completed)").hideHelp()).option("--limit <n>", "max number of reports to return (default: 20, max: 100)", (v) => {
|
|
32596
|
+
const n = parseInt(v, 10);
|
|
32597
|
+
return Number.isNaN(n) ? 20 : Math.max(1, Math.min(n, 100));
|
|
32598
|
+
}).option("--before <date>", "show reports created before this date (YYYY-MM-DD, DD.MM.YYYY, etc.)").option("--all", "fetch all reports (paginated automatically)").addOption(new Option("--debug", "enable debug output").hideHelp()).option("--json", "output raw JSON").action(async (opts) => {
|
|
32595
32599
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching reports...");
|
|
32596
32600
|
try {
|
|
32597
32601
|
const rootOpts = program2.opts();
|
|
@@ -32640,7 +32644,7 @@ reports.command("list").description("list checkup reports").option("--project-id
|
|
|
32640
32644
|
process.exitCode = 1;
|
|
32641
32645
|
}
|
|
32642
32646
|
});
|
|
32643
|
-
reports.command("files [reportId]").description("list files of a checkup report (metadata only, no content)").option("--type <type>", "filter by file type: json, md").option("--check-id <id>", "filter by check ID (e.g., H002)").
|
|
32647
|
+
reports.command("files [reportId]").description("list files of a checkup report (metadata only, no content)").option("--type <type>", "filter by file type: json, md").option("--check-id <id>", "filter by check ID (e.g., H002)").addOption(new Option("--debug", "enable debug output").hideHelp()).option("--json", "output raw JSON").action(async (reportId, opts) => {
|
|
32644
32648
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching report files...");
|
|
32645
32649
|
try {
|
|
32646
32650
|
const rootOpts = program2.opts();
|
|
@@ -32686,7 +32690,7 @@ reports.command("files [reportId]").description("list files of a checkup report
|
|
|
32686
32690
|
process.exitCode = 1;
|
|
32687
32691
|
}
|
|
32688
32692
|
});
|
|
32689
|
-
reports.command("data [reportId]").description("get checkup report file data (includes content)").option("--type <type>", "filter by file type: json, md").option("--check-id <id>", "filter by check ID (e.g., H002)").option("--formatted", "render markdown with ANSI styling (experimental)").option("-o, --output <dir>", "save files to directory (uses original filenames)").
|
|
32693
|
+
reports.command("data [reportId]").description("get checkup report file data (includes content)").option("--type <type>", "filter by file type: json, md").option("--check-id <id>", "filter by check ID (e.g., H002)").option("--formatted", "render markdown with ANSI styling (experimental)").option("-o, --output <dir>", "save files to directory (uses original filenames)").addOption(new Option("--debug", "enable debug output").hideHelp()).option("--json", "output raw JSON").action(async (reportId, opts) => {
|
|
32690
32694
|
const spinner = createTtySpinner(process.stdout.isTTY ?? false, "Fetching report data...");
|
|
32691
32695
|
try {
|
|
32692
32696
|
const rootOpts = program2.opts();
|
package/package.json
CHANGED
package/test/checkup.test.ts
CHANGED
|
@@ -1098,6 +1098,34 @@ describe("CLI tests", () => {
|
|
|
1098
1098
|
expect(r.stderr).not.toMatch(/connection string required/i);
|
|
1099
1099
|
expect(r.stderr).not.toMatch(/unknown option/i);
|
|
1100
1100
|
});
|
|
1101
|
+
|
|
1102
|
+
// Tests for --output flag behavior (suppresses stdout when specified)
|
|
1103
|
+
test("checkup --output option is recognized", () => {
|
|
1104
|
+
const r = runCli(["checkup", "postgresql://test:test@localhost:5432/test", "--no-upload", "--output", "/tmp/test-output"]);
|
|
1105
|
+
// Connection will fail, but option parsing should succeed
|
|
1106
|
+
expect(r.stderr).not.toMatch(/unknown option/i);
|
|
1107
|
+
expect(r.stderr).not.toMatch(/did you mean/i);
|
|
1108
|
+
});
|
|
1109
|
+
|
|
1110
|
+
test("checkup --json --output should NOT output JSON to stdout (writes to files only)", () => {
|
|
1111
|
+
// This is a behavioral test - when --output is specified along with --json,
|
|
1112
|
+
// JSON should only be written to files, not to stdout.
|
|
1113
|
+
// We verify by checking the help text describes this behavior
|
|
1114
|
+
const r = runCli(["checkup", "--help"]);
|
|
1115
|
+
expect(r.status).toBe(0);
|
|
1116
|
+
expect(r.stdout).toMatch(/--output/);
|
|
1117
|
+
expect(r.stdout).toMatch(/--json/);
|
|
1118
|
+
});
|
|
1119
|
+
|
|
1120
|
+
test("checkup --output creates directory if it doesn't exist", () => {
|
|
1121
|
+
const env = { XDG_CONFIG_HOME: "/tmp/postgresai-test-empty-config" };
|
|
1122
|
+
// Use a temp directory that might not exist
|
|
1123
|
+
const tempDir = `/tmp/postgresai-test-output-${Date.now()}`;
|
|
1124
|
+
const r = runCli(["checkup", "postgresql://test:test@localhost:5432/test", "--no-upload", "--json", "--output", tempDir], env);
|
|
1125
|
+
// Connection will fail, but directory creation should be attempted before connection
|
|
1126
|
+
// The error should be about connection, not about directory
|
|
1127
|
+
expect(r.stderr).not.toMatch(/Failed to create output directory/i);
|
|
1128
|
+
});
|
|
1101
1129
|
});
|
|
1102
1130
|
|
|
1103
1131
|
// Tests for checkup-api module
|
package/test/reports.cli.test.ts
CHANGED
|
@@ -299,6 +299,90 @@ describe("CLI reports command group", () => {
|
|
|
299
299
|
}
|
|
300
300
|
});
|
|
301
301
|
|
|
302
|
+
test("reports list --limit caps at 100", async () => {
|
|
303
|
+
const api = await startFakeApi();
|
|
304
|
+
try {
|
|
305
|
+
await runCliAsync(
|
|
306
|
+
["reports", "list", "--limit", "200"],
|
|
307
|
+
isolatedEnv({
|
|
308
|
+
PGAI_API_KEY: "test-key",
|
|
309
|
+
PGAI_API_BASE_URL: api.baseUrl,
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
|
|
313
|
+
const req = api.requests.find((x) =>
|
|
314
|
+
x.pathname.endsWith("/checkup_reports")
|
|
315
|
+
);
|
|
316
|
+
expect(req).toBeTruthy();
|
|
317
|
+
expect(req!.searchParams.limit).toBe("100");
|
|
318
|
+
} finally {
|
|
319
|
+
api.stop();
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
|
|
323
|
+
test("reports list --limit below cap passes through", async () => {
|
|
324
|
+
const api = await startFakeApi();
|
|
325
|
+
try {
|
|
326
|
+
await runCliAsync(
|
|
327
|
+
["reports", "list", "--limit", "50"],
|
|
328
|
+
isolatedEnv({
|
|
329
|
+
PGAI_API_KEY: "test-key",
|
|
330
|
+
PGAI_API_BASE_URL: api.baseUrl,
|
|
331
|
+
})
|
|
332
|
+
);
|
|
333
|
+
|
|
334
|
+
const req = api.requests.find((x) =>
|
|
335
|
+
x.pathname.endsWith("/checkup_reports")
|
|
336
|
+
);
|
|
337
|
+
expect(req).toBeTruthy();
|
|
338
|
+
expect(req!.searchParams.limit).toBe("50");
|
|
339
|
+
} finally {
|
|
340
|
+
api.stop();
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("reports list --limit with invalid value falls back to default", async () => {
|
|
345
|
+
const api = await startFakeApi();
|
|
346
|
+
try {
|
|
347
|
+
await runCliAsync(
|
|
348
|
+
["reports", "list", "--limit", "abc"],
|
|
349
|
+
isolatedEnv({
|
|
350
|
+
PGAI_API_KEY: "test-key",
|
|
351
|
+
PGAI_API_BASE_URL: api.baseUrl,
|
|
352
|
+
})
|
|
353
|
+
);
|
|
354
|
+
|
|
355
|
+
const req = api.requests.find((x) =>
|
|
356
|
+
x.pathname.endsWith("/checkup_reports")
|
|
357
|
+
);
|
|
358
|
+
expect(req).toBeTruthy();
|
|
359
|
+
expect(req!.searchParams.limit).toBe("20");
|
|
360
|
+
} finally {
|
|
361
|
+
api.stop();
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
test("reports list --limit with negative value clamps to 1", async () => {
|
|
366
|
+
const api = await startFakeApi();
|
|
367
|
+
try {
|
|
368
|
+
await runCliAsync(
|
|
369
|
+
["reports", "list", "--limit", "-5"],
|
|
370
|
+
isolatedEnv({
|
|
371
|
+
PGAI_API_KEY: "test-key",
|
|
372
|
+
PGAI_API_BASE_URL: api.baseUrl,
|
|
373
|
+
})
|
|
374
|
+
);
|
|
375
|
+
|
|
376
|
+
const req = api.requests.find((x) =>
|
|
377
|
+
x.pathname.endsWith("/checkup_reports")
|
|
378
|
+
);
|
|
379
|
+
expect(req).toBeTruthy();
|
|
380
|
+
expect(req!.searchParams.limit).toBe("1");
|
|
381
|
+
} finally {
|
|
382
|
+
api.stop();
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
302
386
|
test("reports files succeeds against a fake API", async () => {
|
|
303
387
|
const api = await startFakeApi();
|
|
304
388
|
try {
|