Skip to content

Commit d8c905f

Browse files
committed
Merge branch '66-cli-command-renames-and-api-key-authentication' into 'main'
refactor: improve CLI commands and authentication flow Closes #66 See merge request postgres-ai/postgres_ai!113
2 parents 0a40779 + d07214b commit d8c905f

6 files changed

Lines changed: 159 additions & 73 deletions

File tree

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -79,49 +79,49 @@ Use the CLI to create/update the monitoring role and grant all required permissi
7979
# Monitoring password:
8080
# - by default, postgresai generates a strong password automatically
8181
# - it is printed only in interactive (TTY) mode, or if you opt in via --print-password
82-
PGPASSWORD='...' npx postgresai init postgresql://admin@host:5432/dbname
82+
PGPASSWORD='...' npx postgresai prepare-db postgresql://admin@host:5432/dbname
8383
```
8484

8585
Optional permissions (RDS/self-managed extras) are enabled by default. To skip them:
8686

8787
```bash
88-
PGPASSWORD='...' npx postgresai init postgresql://admin@host:5432/dbname --skip-optional-permissions
88+
PGPASSWORD='...' npx postgresai prepare-db postgresql://admin@host:5432/dbname --skip-optional-permissions
8989
```
9090

9191
Verify everything is in place (no changes):
9292

9393
```bash
94-
PGPASSWORD='...' npx postgresai init postgresql://admin@host:5432/dbname --verify
94+
PGPASSWORD='...' npx postgresai prepare-db postgresql://admin@host:5432/dbname --verify
9595
```
9696

9797
If you want to reset the monitoring password only (no other changes), you can rely on auto-generation:
9898

9999
```bash
100-
PGPASSWORD='...' npx postgresai init postgresql://admin@host:5432/dbname --reset-password
100+
PGPASSWORD='...' npx postgresai prepare-db postgresql://admin@host:5432/dbname --reset-password
101101
```
102102

103-
By default, `postgresai init` auto-generates a strong password (see above).
103+
By default, `postgresai prepare-db` auto-generates a strong password (see above).
104104

105105
If you want to set a specific password instead:
106106

107107
```bash
108-
PGPASSWORD='...' npx postgresai init postgresql://admin@host:5432/dbname --reset-password --password 'new_password'
108+
PGPASSWORD='...' npx postgresai prepare-db postgresql://admin@host:5432/dbname --reset-password --password 'new_password'
109109
```
110110

111111
If you want to see what will be executed first, use `--print-sql` (prints the SQL plan and exits; passwords redacted by default). This can be done without a DB connection:
112112

113113
```bash
114-
npx postgresai init --print-sql
114+
npx postgresai prepare-db --print-sql
115115
```
116116

117117
Optionally, to render the plan for a specific database:
118118

119119
```bash
120120
# Pick database (default is PGDATABASE or "postgres"):
121-
npx postgresai init --print-sql -d dbname
121+
npx postgresai prepare-db --print-sql -d dbname
122122

123123
# Provide an explicit monitoring password (still redacted in output):
124-
npx postgresai init --print-sql -d dbname --password '...'
124+
npx postgresai prepare-db --print-sql -d dbname --password '...'
125125
```
126126

127127
### Troubleshooting
@@ -140,7 +140,7 @@ If you see errors like `permission denied` / `insufficient_privilege` / code `42
140140
- **Review SQL before running** (audit-friendly):
141141

142142
```bash
143-
npx postgresai init --print-sql -d mydb
143+
npx postgresai prepare-db --print-sql -d mydb
144144
```
145145

146146
**One command setup:**

cli/README.md

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,26 +50,26 @@ If you want `npx pgai ...` as a shorthand for `npx postgresai ...`, install the
5050
npx pgai --help
5151
```
5252

53-
## init (create monitoring user in Postgres)
53+
## prepare-db (create monitoring user in Postgres)
5454

5555
This command creates (or updates) the `postgres_ai_mon` user, creates the required view(s), and grants the permissions described in the root `README.md` (it is idempotent). Where supported, it also enables observability extensions described there.
5656

5757
Run without installing (positional connection string):
5858

5959
```bash
60-
npx postgresai init postgresql://admin@host:5432/dbname
60+
npx postgresai prepare-db postgresql://admin@host:5432/dbname
6161
```
6262

63-
It also accepts libpq conninfo syntax:
63+
It also accepts libpq "conninfo" syntax:
6464

6565
```bash
66-
npx postgresai init "dbname=dbname host=host user=admin"
66+
npx postgresai prepare-db "dbname=dbname host=host user=admin"
6767
```
6868

6969
And psql-like options:
7070

7171
```bash
72-
npx postgresai init -h host -p 5432 -U admin -d dbname
72+
npx postgresai prepare-db -h host -p 5432 -U admin -d dbname
7373
```
7474

7575
Password input options (in priority order):
@@ -83,29 +83,29 @@ By default, the generated password is printed **only in interactive (TTY) mode**
8383
Optional permissions (RDS/self-managed extras from the root `README.md`) are enabled by default. To skip them:
8484

8585
```bash
86-
npx postgresai init postgresql://admin@host:5432/dbname --skip-optional-permissions
86+
npx postgresai prepare-db postgresql://admin@host:5432/dbname --skip-optional-permissions
8787
```
8888

8989
### Print SQL / dry run
9090

9191
To see what SQL would be executed (passwords redacted by default):
9292

9393
```bash
94-
npx postgresai init postgresql://admin@host:5432/dbname --print-sql
94+
npx postgresai prepare-db postgresql://admin@host:5432/dbname --print-sql
9595
```
9696

9797
### Verify and password reset
9898

9999
Verify that everything is configured as expected (no changes):
100100

101101
```bash
102-
npx postgresai init postgresql://admin@host:5432/dbname --verify
102+
npx postgresai prepare-db postgresql://admin@host:5432/dbname --verify
103103
```
104104

105105
Reset monitoring user password only (no other changes):
106106

107107
```bash
108-
npx postgresai init postgresql://admin@host:5432/dbname --reset-password --password 'new_password'
108+
npx postgresai prepare-db postgresql://admin@host:5432/dbname --reset-password --password 'new_password'
109109
```
110110

111111
## Quick start
@@ -126,17 +126,17 @@ This will:
126126

127127
Start monitoring with demo database:
128128
```bash
129-
postgres-ai mon quickstart --demo
129+
postgres-ai mon local-install --demo
130130
```
131131

132132
Start monitoring with your own database:
133133
```bash
134-
postgres-ai mon quickstart --db-url postgresql://user:pass@host:5432/db
134+
postgres-ai mon local-install --db-url postgresql://user:pass@host:5432/db
135135
```
136136

137137
Complete automated setup with API key and database:
138138
```bash
139-
postgres-ai mon quickstart --api-key your_key --db-url postgresql://user:pass@host:5432/db -y
139+
postgres-ai mon local-install --api-key your_key --db-url postgresql://user:pass@host:5432/db -y
140140
```
141141

142142
This will:
@@ -153,12 +153,12 @@ This will:
153153
#### Service lifecycle
154154
```bash
155155
# Complete setup with various options
156-
postgres-ai mon quickstart # Interactive setup for production
157-
postgres-ai mon quickstart --demo # Demo mode with sample database
158-
postgres-ai mon quickstart --api-key <key> # Setup with API key
159-
postgres-ai mon quickstart --db-url <url> # Setup with database URL
160-
postgres-ai mon quickstart --api-key <key> --db-url <url> # Complete automated setup
161-
postgres-ai mon quickstart -y # Auto-accept all defaults
156+
postgres-ai mon local-install # Interactive setup for production
157+
postgres-ai mon local-install --demo # Demo mode with sample database
158+
postgres-ai mon local-install --api-key <key> # Setup with API key
159+
postgres-ai mon local-install --db-url <url> # Setup with database URL
160+
postgres-ai mon local-install --api-key <key> --db-url <url> # Complete automated setup
161+
postgres-ai mon local-install -y # Auto-accept all defaults
162162

163163
# Service management
164164
postgres-ai mon start # Start monitoring services
@@ -168,7 +168,7 @@ postgres-ai mon status # Show monitoring services status
168168
postgres-ai mon health [--wait <sec>] # Check monitoring services health
169169
```
170170

171-
##### Quickstart options
171+
##### local-install options
172172
- `--demo` - Demo mode with sample database (testing only, cannot use with --api-key)
173173
- `--api-key <key>` - Postgres AI API key for automated report uploads
174174
- `--db-url <url>` - PostgreSQL connection URL to monitor (format: `postgresql://user:pass@host:port/db`)
@@ -256,10 +256,10 @@ postgres-ai mon show-grafana-credentials # Show Grafana credentials
256256

257257
### Authentication and API key management
258258
```bash
259-
postgres-ai auth # Authenticate via browser (recommended)
260-
postgres-ai add-key <key> # Manually store API key
261-
postgres-ai show-key # Show stored key (masked)
262-
postgres-ai remove-key # Remove stored key
259+
postgres-ai auth # Authenticate via browser (OAuth)
260+
postgres-ai auth --set-key <key> # Store API key directly
261+
postgres-ai show-key # Show stored key (masked)
262+
postgres-ai remove-key # Remove stored key
263263
```
264264

265265
## Configuration

cli/bin/postgres-ai.ts

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -203,8 +203,8 @@ program
203203
);
204204

205205
program
206-
.command("init [conn]")
207-
.description("Create a monitoring user, required view(s), and grant required permissions (idempotent)")
206+
.command("prepare-db [conn]")
207+
.description("Prepare database for monitoring: create monitoring user, required view(s), and grant permissions (idempotent)")
208208
.option("--db-url <url>", "PostgreSQL connection URL (admin) to run the setup against (deprecated; pass it as positional arg)")
209209
.option("-h, --host <host>", "PostgreSQL host (psql-like)")
210210
.option("-p, --port <port>", "PostgreSQL port (psql-like)")
@@ -223,9 +223,9 @@ program
223223
[
224224
"",
225225
"Examples:",
226-
" postgresai init postgresql://admin@host:5432/dbname",
227-
" postgresai init \"dbname=dbname host=host user=admin\"",
228-
" postgresai init -h host -p 5432 -U admin -d dbname",
226+
" postgresai prepare-db postgresql://admin@host:5432/dbname",
227+
" postgresai prepare-db \"dbname=dbname host=host user=admin\"",
228+
" postgresai prepare-db -h host -p 5432 -U admin -d dbname",
229229
"",
230230
"Admin password:",
231231
" --admin-password <password> or PGPASSWORD=... (libpq standard)",
@@ -247,16 +247,16 @@ program
247247
" PGAI_MON_PASSWORD — monitoring password",
248248
"",
249249
"Inspect SQL without applying changes:",
250-
" postgresai init <conn> --print-sql",
250+
" postgresai prepare-db <conn> --print-sql",
251251
"",
252252
"Verify setup (no changes):",
253-
" postgresai init <conn> --verify",
253+
" postgresai prepare-db <conn> --verify",
254254
"",
255255
"Reset monitoring password only:",
256-
" postgresai init <conn> --reset-password --password '...'",
256+
" postgresai prepare-db <conn> --reset-password --password '...'",
257257
"",
258258
"Offline SQL plan (no DB connection):",
259-
" postgresai init --print-sql",
259+
" postgresai prepare-db --print-sql",
260260
].join("\n")
261261
)
262262
.action(async (conn: string | undefined, opts: {
@@ -336,7 +336,7 @@ program
336336
});
337337
} catch (e) {
338338
const msg = e instanceof Error ? e.message : String(e);
339-
console.error(`Error: init: ${msg}`);
339+
console.error(`Error: prepare-db: ${msg}`);
340340
// When connection details are missing, show full init help (options + examples).
341341
if (typeof msg === "string" && msg.startsWith("Connection is required.")) {
342342
console.error("");
@@ -372,14 +372,14 @@ program
372372
includeOptionalPermissions,
373373
});
374374
if (v.ok) {
375-
console.log("✓ init verify: OK");
375+
console.log("✓ prepare-db verify: OK");
376376
if (v.missingOptional.length > 0) {
377377
console.log("⚠ Optional items missing:");
378378
for (const m of v.missingOptional) console.log(`- ${m}`);
379379
}
380380
return;
381381
}
382-
console.error("✗ init verify failed: missing required items");
382+
console.error("✗ prepare-db verify failed: missing required items");
383383
for (const m of v.missingRequired) console.error(`- ${m}`);
384384
if (v.missingOptional.length > 0) {
385385
console.error("Optional items missing:");
@@ -455,7 +455,7 @@ program
455455

456456
const { applied, skippedOptional } = await applyInitPlan({ client, plan: effectivePlan });
457457

458-
console.log(opts.resetPassword ? "✓ init password reset completed" : "✓ init completed");
458+
console.log(opts.resetPassword ? "✓ prepare-db password reset completed" : "✓ prepare-db completed");
459459
if (skippedOptional.length > 0) {
460460
console.log("⚠ Some optional steps were skipped (not supported or insufficient privileges):");
461461
for (const s of skippedOptional) console.log(`- ${s}`);
@@ -477,7 +477,7 @@ program
477477
if (!message || message === "[object Object]") {
478478
message = "Unknown error";
479479
}
480-
console.error(`Error: init: ${message}`);
480+
console.error(`Error: prepare-db: ${message}`);
481481
// If this was a plan step failure, surface the step name explicitly to help users diagnose quickly.
482482
const stepMatch =
483483
typeof message === "string" ? message.match(/Failed at step "([^"]+)":/i) : null;
@@ -679,16 +679,16 @@ program.command("help", { isDefault: true }).description("show help").action(()
679679
const mon = program.command("mon").description("monitoring services management");
680680

681681
mon
682-
.command("quickstart")
683-
.description("complete setup (generate config, start monitoring services)")
682+
.command("local-install")
683+
.description("install local monitoring stack (generate config, start services)")
684684
.option("--demo", "demo mode with sample database", false)
685685
.option("--api-key <key>", "Postgres AI API key for automated report uploads")
686686
.option("--db-url <url>", "PostgreSQL connection URL to monitor")
687687
.option("--tag <tag>", "Docker image tag to use (e.g., 0.14.0, 0.14.0-dev.33)")
688688
.option("-y, --yes", "accept all defaults and skip interactive prompts", false)
689689
.action(async (opts: { demo: boolean; apiKey?: string; dbUrl?: string; tag?: string; yes: boolean }) => {
690690
console.log("\n=================================");
691-
console.log(" PostgresAI Monitoring Quickstart");
691+
console.log(" PostgresAI monitoring local install");
692692
console.log("=================================\n");
693693
console.log("This will install, configure, and start the monitoring system\n");
694694

@@ -726,8 +726,8 @@ mon
726726
if (opts.demo && opts.apiKey) {
727727
console.error("✗ Cannot use --api-key with --demo mode");
728728
console.error("✗ Demo mode is for testing only and does not support API key integration");
729-
console.error("\nUse demo mode without API key: postgres-ai mon quickstart --demo");
730-
console.error("Or use production mode with API key: postgres-ai mon quickstart --api-key=your_key");
729+
console.error("\nUse demo mode without API key: postgres-ai mon local-install --demo");
730+
console.error("Or use production mode with API key: postgres-ai mon local-install --api-key=your_key");
731731
process.exitCode = 1;
732732
return;
733733
}
@@ -989,7 +989,7 @@ mon
989989

990990
// Final summary
991991
console.log("=================================");
992-
console.log(" 🎉 Quickstart setup completed!");
992+
console.log(" Local install completed!");
993993
console.log("=================================\n");
994994

995995
console.log("What's running:");
@@ -1536,10 +1536,26 @@ targets
15361536
// Authentication and API key management
15371537
program
15381538
.command("auth")
1539-
.description("authenticate via browser and obtain API key")
1539+
.description("authenticate via browser (OAuth) or store API key directly")
1540+
.option("--set-key <key>", "store API key directly without OAuth flow")
15401541
.option("--port <port>", "local callback server port (default: random)", parseInt)
15411542
.option("--debug", "enable debug output")
1542-
.action(async (opts: { port?: number; debug?: boolean }) => {
1543+
.action(async (opts: { setKey?: string; port?: number; debug?: boolean }) => {
1544+
// If --set-key is provided, store it directly without OAuth
1545+
if (opts.setKey) {
1546+
const trimmedKey = opts.setKey.trim();
1547+
if (!trimmedKey) {
1548+
console.error("Error: API key cannot be empty");
1549+
process.exitCode = 1;
1550+
return;
1551+
}
1552+
1553+
config.writeConfig({ apiKey: trimmedKey });
1554+
console.log(`API key saved to ${config.getConfigPath()}`);
1555+
return;
1556+
}
1557+
1558+
// Otherwise, proceed with OAuth flow
15431559
const pkce = require("../lib/pkce");
15441560
const authServer = require("../lib/auth-server");
15451561

@@ -1765,8 +1781,9 @@ program
17651781

17661782
program
17671783
.command("add-key <apiKey>")
1768-
.description("store API key")
1784+
.description("store API key (deprecated: use 'auth --set-key' instead)")
17691785
.action(async (apiKey: string) => {
1786+
console.warn("Warning: 'add-key' is deprecated. Use 'auth --set-key <key>' instead.\n");
17701787
config.writeConfig({ apiKey });
17711788
console.log(`API key saved to ${config.getConfigPath()}`);
17721789
});
@@ -1893,7 +1910,7 @@ mon
18931910
const { projectDir } = await resolveOrInitPaths();
18941911
const cfgPath = path.resolve(projectDir, ".pgwatch-config");
18951912
if (!fs.existsSync(cfgPath)) {
1896-
console.error("Configuration file not found. Run 'postgres-ai mon quickstart' first.");
1913+
console.error("Configuration file not found. Run 'postgres-ai mon local-install' first.");
18971914
process.exitCode = 1;
18981915
return;
18991916
}

0 commit comments

Comments
 (0)