postgresai 0.14.0-dev.36 → 0.14.0-dev.38

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.
@@ -157,7 +157,7 @@ async function withTempPostgres(t) {
157
157
  async function runCliInit(args, env = {}) {
158
158
  const node = process.execPath;
159
159
  const cliPath = path.resolve(__dirname, "..", "dist", "bin", "postgres-ai.js");
160
- const res = spawnSync(node, [cliPath, "init", ...args], {
160
+ const res = spawnSync(node, [cliPath, "prepare-db", ...args], {
161
161
  encoding: "utf8",
162
162
  env: { ...process.env, ...env },
163
163
  });
@@ -165,7 +165,7 @@ async function runCliInit(args, env = {}) {
165
165
  }
166
166
 
167
167
  test(
168
- "integration: init supports URI / conninfo / psql-like connection styles",
168
+ "integration: prepare-db supports URI / conninfo / psql-like connection styles",
169
169
  { skip: !havePostgresBinaries() },
170
170
  async (t) => {
171
171
  const pg = await withTempPostgres(t);
@@ -207,7 +207,7 @@ test(
207
207
  );
208
208
 
209
209
  test(
210
- "integration: init requires explicit monitoring password in non-interactive mode (unless --print-password)",
210
+ "integration: prepare-db requires explicit monitoring password in non-interactive mode (unless --print-password)",
211
211
  { skip: !havePostgresBinaries() },
212
212
  async (t) => {
213
213
  const pg = await withTempPostgres(t);
@@ -231,7 +231,7 @@ test(
231
231
  );
232
232
 
233
233
  test(
234
- "integration: init fixes slightly-off permissions idempotently",
234
+ "integration: prepare-db fixes slightly-off permissions idempotently",
235
235
  { skip: !havePostgresBinaries() },
236
236
  async (t) => {
237
237
  const pg = await withTempPostgres(t);
@@ -285,7 +285,7 @@ test(
285
285
  }
286
286
  );
287
287
 
288
- test("integration: init reports nicely when lacking permissions", { skip: !havePostgresBinaries() }, async (t) => {
288
+ test("integration: prepare-db reports nicely when lacking permissions", { skip: !havePostgresBinaries() }, async (t) => {
289
289
  const pg = await withTempPostgres(t);
290
290
  const { Client } = require("pg");
291
291
 
@@ -310,13 +310,13 @@ test("integration: init reports nicely when lacking permissions", { skip: !haveP
310
310
  const limitedUri = `postgresql://limited:${limitedPw}@127.0.0.1:${pg.port}/testdb`;
311
311
  const r = await runCliInit([limitedUri, "--password", "monpw", "--skip-optional-permissions"]);
312
312
  assert.notEqual(r.status, 0);
313
- assert.match(r.stderr, /Error: init:/);
313
+ assert.match(r.stderr, /Error: prepare-db:/);
314
314
  // Should include step context and hint.
315
315
  assert.match(r.stderr, /Failed at step "/);
316
316
  assert.match(r.stderr, /Fix: connect as a superuser/i);
317
317
  });
318
318
 
319
- test("integration: init --verify returns 0 when ok and non-zero when missing", { skip: !havePostgresBinaries() }, async (t) => {
319
+ test("integration: prepare-db --verify returns 0 when ok and non-zero when missing", { skip: !havePostgresBinaries() }, async (t) => {
320
320
  const pg = await withTempPostgres(t);
321
321
  const { Client } = require("pg");
322
322
 
@@ -330,7 +330,7 @@ test("integration: init --verify returns 0 when ok and non-zero when missing", {
330
330
  {
331
331
  const r = await runCliInit([pg.adminUri, "--verify", "--skip-optional-permissions"]);
332
332
  assert.equal(r.status, 0, r.stderr || r.stdout);
333
- assert.match(r.stdout, /init verify: OK/i);
333
+ assert.match(r.stdout, /prepare-db verify: OK/i);
334
334
  }
335
335
 
336
336
  // Break a required privilege and ensure verify fails
@@ -345,12 +345,12 @@ test("integration: init --verify returns 0 when ok and non-zero when missing", {
345
345
  {
346
346
  const r = await runCliInit([pg.adminUri, "--verify", "--skip-optional-permissions"]);
347
347
  assert.notEqual(r.status, 0);
348
- assert.match(r.stderr, /init verify failed/i);
348
+ assert.match(r.stderr, /prepare-db verify failed/i);
349
349
  assert.match(r.stderr, /pg_catalog\.pg_index/i);
350
350
  }
351
351
  });
352
352
 
353
- test("integration: init --reset-password updates the monitoring role login password", { skip: !havePostgresBinaries() }, async (t) => {
353
+ test("integration: prepare-db --reset-password updates the monitoring role login password", { skip: !havePostgresBinaries() }, async (t) => {
354
354
  const pg = await withTempPostgres(t);
355
355
  const { Client } = require("pg");
356
356
 
@@ -177,8 +177,8 @@ test("resolveAdminConnection rejects when connection is missing", () => {
177
177
  assert.throws(() => init.resolveAdminConnection({}), /Connection is required/);
178
178
  });
179
179
 
180
- test("cli: init with missing connection prints init help/options", () => {
181
- const r = runCli(["init"]);
180
+ test("cli: prepare-db with missing connection prints help/options", () => {
181
+ const r = runCli(["prepare-db"]);
182
182
  assert.notEqual(r.status, 0);
183
183
  // We should show options, not just the error message.
184
184
  assert.match(r.stderr, /--print-sql/);
@@ -307,8 +307,8 @@ test("redactPasswordsInSql redacts password literals with embedded quotes", asyn
307
307
  assert.match(redacted, /password '<redacted>'/i);
308
308
  });
309
309
 
310
- test("cli: init --print-sql works without connection (offline mode)", () => {
311
- const r = runCli(["init", "--print-sql", "-d", "mydb", "--password", "monpw"]);
310
+ test("cli: prepare-db --print-sql works without connection (offline mode)", () => {
311
+ const r = runCli(["prepare-db", "--print-sql", "-d", "mydb", "--password", "monpw"]);
312
312
  assert.equal(r.status, 0, r.stderr || r.stdout);
313
313
  assert.match(r.stdout, /SQL plan \(offline; not connected\)/);
314
314
  assert.match(r.stdout, new RegExp(`grant connect on database "mydb" to "${DEFAULT_MONITORING_USER}"`, "i"));
@@ -320,4 +320,73 @@ test("pgai wrapper forwards to postgresai CLI", () => {
320
320
  assert.match(r.stdout, /postgresai|PostgresAI/i);
321
321
  });
322
322
 
323
+ test("cli: prepare-db command exists and shows help", () => {
324
+ const r = runCli(["prepare-db", "--help"]);
325
+ assert.equal(r.status, 0, r.stderr || r.stdout);
326
+ assert.match(r.stdout, /monitoring user/i);
327
+ assert.match(r.stdout, /--print-sql/);
328
+ });
329
+
330
+ test("cli: prepare-db with missing connection prints help/options", () => {
331
+ const r = runCli(["prepare-db"]);
332
+ assert.notEqual(r.status, 0);
333
+ assert.match(r.stderr, /--print-sql/);
334
+ assert.match(r.stderr, /--monitoring-user/);
335
+ });
336
+
337
+ test("cli: prepare-db --print-sql works without connection (offline mode)", () => {
338
+ const r = runCli(["prepare-db", "--print-sql", "-d", "mydb", "--password", "monpw"]);
339
+ assert.equal(r.status, 0, r.stderr || r.stdout);
340
+ assert.match(r.stdout, /SQL plan \(offline; not connected\)/);
341
+ assert.match(r.stdout, new RegExp(`grant connect on database "mydb" to "${DEFAULT_MONITORING_USER}"`, "i"));
342
+ });
343
+
344
+ test("cli: mon local-install command exists and shows help", () => {
345
+ const r = runCli(["mon", "local-install", "--help"]);
346
+ assert.equal(r.status, 0, r.stderr || r.stdout);
347
+ assert.match(r.stdout, /--demo/);
348
+ assert.match(r.stdout, /--api-key/);
349
+ });
350
+
351
+ // Auth --set-key tests
352
+ test("cli: auth --set-key stores key without OAuth", () => {
353
+ const fs = require("node:fs");
354
+ const path = require("node:path");
355
+ const os = require("node:os");
356
+
357
+ // Use a temp directory for config to avoid modifying user's actual config
358
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "pgai-auth-test-"));
359
+
360
+ try {
361
+ // Create the postgresai subdirectory so we know exactly where config goes
362
+ const postgresaiDir = path.join(tmpDir, "postgresai");
363
+ fs.mkdirSync(postgresaiDir, { recursive: true });
364
+
365
+ // Set XDG_CONFIG_HOME to redirect config to temp dir
366
+ const r = runCli(["auth", "--set-key", "test-api-key-12345"], {
367
+ XDG_CONFIG_HOME: tmpDir,
368
+ // Also clear HOME to prevent fallbacks
369
+ HOME: tmpDir,
370
+ });
371
+
372
+ assert.equal(r.status, 0, r.stderr || r.stdout);
373
+ assert.match(r.stdout, /API key saved/i);
374
+
375
+ // Verify the config file was created with the API key
376
+ const actualConfigPath = path.join(postgresaiDir, "config.json");
377
+ assert.ok(fs.existsSync(actualConfigPath), "Config file should exist at " + actualConfigPath);
378
+
379
+ const config = JSON.parse(fs.readFileSync(actualConfigPath, "utf8"));
380
+ assert.equal(config.apiKey, "test-api-key-12345");
381
+ } finally {
382
+ // Cleanup
383
+ fs.rmSync(tmpDir, { recursive: true, force: true });
384
+ }
385
+ });
386
+
387
+ test("cli: auth --help shows --set-key option", () => {
388
+ const r = runCli(["auth", "--help"]);
389
+ assert.equal(r.status, 0, r.stderr || r.stdout);
390
+ assert.match(r.stdout, /--set-key/);
391
+ });
323
392