@carllee1983/dbcli 1.11.0 → 1.18.0
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/CHANGELOG.md +120 -0
- package/README.md +94 -0
- package/README.zh-TW.md +39 -16
- package/assets/SKILL.md +109 -13
- package/assets/reference.md +480 -4
- package/assets/ui-template.html +306 -0
- package/dist/cli.mjs +15441 -15971
- package/dist/ui-style.css +3 -0
- package/package.json +15 -5
package/assets/reference.md
CHANGED
|
@@ -135,9 +135,13 @@ dbcli query "DEL stale:key" # requires data-admin+
|
|
|
135
135
|
# Elasticsearch: DSL body or Lucene q-string
|
|
136
136
|
dbcli query '{"query":{"match":{"status":"active"}}}' --collection orders
|
|
137
137
|
dbcli query 'status:active AND amount:>100' --index orders --limit 50
|
|
138
|
+
|
|
139
|
+
# Interactive HTML dashboard (see "Interactive HTML dashboard" below)
|
|
140
|
+
dbcli query "SELECT day, dau FROM dau_daily" --ui # open in browser
|
|
141
|
+
dbcli query "SELECT * FROM orders" --format html > orders.html # pipe to stdout
|
|
138
142
|
```
|
|
139
143
|
|
|
140
|
-
**Options:** `--format <table|json|csv>`, `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`)
|
|
144
|
+
**Options:** `--format <table|json|csv|html>`, `--ui` (open the dashboard in the system browser; implies `--format html`), `--limit <number>`, `--no-limit`, `--collection <name>` (MongoDB / Elasticsearch), `--index <name>` (Elasticsearch alias for `--collection`), `--recovery`
|
|
141
145
|
**Permission:** query-only+ (Redis: per-command; Elasticsearch: per HTTP method/path)
|
|
142
146
|
|
|
143
147
|
> **MongoDB notes:**
|
|
@@ -156,6 +160,31 @@ dbcli query 'status:active AND amount:>100' --index orders --limit 50
|
|
|
156
160
|
> - Hits are flattened: each result row contains `_id` plus dotted-path fields from `_source`. Pass `--format json` to keep nested structures readable.
|
|
157
161
|
> - Query-only mode caps at 1000 hits; `--no-limit` is internally capped at 10 000 (use saved searches / `search_after` for deeper pagination).
|
|
158
162
|
|
|
163
|
+
### plan
|
|
164
|
+
|
|
165
|
+
Static SQL risk analyzer. Classifies a statement into the same permission tiers
|
|
166
|
+
used by `query` (`query-only` / `read-write` / `data-admin` / `admin`) and lists
|
|
167
|
+
the underlying signals (DML / DDL / multi-statement / unsafe constructs) without
|
|
168
|
+
ever connecting to the database.
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
dbcli plan "SELECT * FROM users"
|
|
172
|
+
dbcli plan "UPDATE users SET name='x'" # human-readable text classification
|
|
173
|
+
dbcli plan "DROP TABLE users" --format json # machine-readable risk report
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
**Options:** `--format <text|json>` (default `text`).
|
|
177
|
+
**Permission:** n/a (offline analyzer; no connection opened).
|
|
178
|
+
|
|
179
|
+
Use cases:
|
|
180
|
+
- Agents that want to decide whether to call `query` vs `insert` / `update` /
|
|
181
|
+
`delete` before sending SQL.
|
|
182
|
+
- Pre-flight safety check before binding parameters into a saved snippet.
|
|
183
|
+
- Lint hook for code review pipelines that store SQL in source.
|
|
184
|
+
|
|
185
|
+
`plan` does not enforce blacklist or auto-`LIMIT`; those still apply when the
|
|
186
|
+
SQL is actually executed via `query` / `q`.
|
|
187
|
+
|
|
159
188
|
### q
|
|
160
189
|
|
|
161
190
|
Run a saved query snippet by `@name`. Snippets are parameterised SELECT/WITH statements resolved from three layers, with **local > shared > builtin** precedence (a local file always shadows shared and builtin variants of the same key):
|
|
@@ -172,15 +201,19 @@ dbcli q @dau --param days=30 --format json # override a param
|
|
|
172
201
|
dbcli q @analytics/revenue --param-file params.json
|
|
173
202
|
dbcli q @dau --dry-run # show final SQL + bind values
|
|
174
203
|
dbcli q @dau --no-limit # disable size guard wrap
|
|
204
|
+
dbcli q @analytics/revenue --param days=30 --ui # open dashboard
|
|
205
|
+
dbcli q @analytics/revenue --param days=30 --format html > report.html
|
|
175
206
|
```
|
|
176
207
|
|
|
177
208
|
**Options:**
|
|
178
|
-
- `--format <table|json|csv>` — output format (default: `table`)
|
|
209
|
+
- `--format <table|json|csv|html>` — output format (default: `table`)
|
|
210
|
+
- `--ui` — open the rendered HTML dashboard in the system browser (implies `--format html`; writes to a temp file then invokes `open` / `xdg-open` / `start`)
|
|
179
211
|
- `--param <key=value>` — pass a parameter (repeatable)
|
|
180
212
|
- `--param-file <path>` — JSON object whose keys are param names
|
|
181
213
|
- `--no-limit` — skip the `SELECT * FROM (…) AS _dbcli_guard LIMIT 1000` wrap
|
|
182
214
|
- `--dry-run` — print the bound SQL + values without executing
|
|
183
215
|
- `--use <name>` — pick a v2 named connection
|
|
216
|
+
- `--recovery` — emit a `RecoveryEnvelope` on failure (see `recover`)
|
|
184
217
|
|
|
185
218
|
**Permission:** query-only+
|
|
186
219
|
|
|
@@ -201,6 +234,13 @@ Each `.sql` file is plain SQL with optional YAML frontmatter inside a leading `-
|
|
|
201
234
|
-- description: lookback window in days
|
|
202
235
|
-- enum: [7, 30, 90]
|
|
203
236
|
-- tags: [analytics]
|
|
237
|
+
-- intent: perf.slow-query # optional; consumed by `queries suggest`
|
|
238
|
+
-- visual: # optional; consumed by `--ui` / `--format html`
|
|
239
|
+
-- title: Daily Active Users
|
|
240
|
+
-- kpis:
|
|
241
|
+
-- - { label: DAU, value_column: dau, format: number }
|
|
242
|
+
-- charts:
|
|
243
|
+
-- - { type: line, title: DAU trend, x: day, y: [dau] }
|
|
204
244
|
-- ---
|
|
205
245
|
SELECT COUNT(DISTINCT user_id) AS dau
|
|
206
246
|
FROM events
|
|
@@ -209,6 +249,8 @@ WHERE created_at > NOW() - (:days || ' days')::interval;
|
|
|
209
249
|
|
|
210
250
|
Param placeholders use `:name`. They are rewritten to `$1, $2, …` (Postgres) or `?, ?, …` (MySQL) at execution time and passed as bind values — string interpolation is never used.
|
|
211
251
|
|
|
252
|
+
The `visual:` block is documented in detail under [Interactive HTML dashboard](#interactive-html-dashboard) below. Unknown / malformed fields are silently dropped at parse time; the snippet still runs and the dashboard falls back to a sortable table.
|
|
253
|
+
|
|
212
254
|
#### Param type coercion
|
|
213
255
|
|
|
214
256
|
| Declared `type` | Accepts |
|
|
@@ -299,6 +341,10 @@ dbcli queries list --tag analytics --engine postgres --format json
|
|
|
299
341
|
dbcli queries list --source local # only personal overrides
|
|
300
342
|
dbcli queries show @dau # frontmatter + SQL
|
|
301
343
|
dbcli queries show @dau --format json # MCP-shaped contract
|
|
344
|
+
dbcli queries search slow query # fuzzy-ranked keyword search across snippets
|
|
345
|
+
dbcli queries search cache --engine postgres --source builtin --limit 5
|
|
346
|
+
dbcli queries suggest perf # browse snippets by intent prefix (v1.11+)
|
|
347
|
+
dbcli queries suggest perf.cache-hit --format json
|
|
302
348
|
|
|
303
349
|
# Authoring
|
|
304
350
|
dbcli queries new @new/sample # scaffold under .dbcli-shared/queries/
|
|
@@ -319,8 +365,10 @@ dbcli queries export @dau --output dau.sql # write snippet body to a fi
|
|
|
319
365
|
dbcli queries export @diag/connections --engine postgres # pick a variant when multiple engines exist
|
|
320
366
|
```
|
|
321
367
|
|
|
322
|
-
**`list` options:** `--format <table|json|csv>`, `--tag <tag>`, `--engine <postgres|mysql>`, `--source <local|shared>`
|
|
368
|
+
**`list` options:** `--format <table|json|csv>`, `--tag <tag>`, `--engine <postgres|mysql|redis|elasticsearch|all>`, `--source <local|shared|builtin|all>`
|
|
323
369
|
**`show` options:** `--format <table|json|csv>`
|
|
370
|
+
**`search` options:** `--format <table|json>`, `--engine <postgres|mysql|redis|elasticsearch|all>`, `--source <local|shared|builtin|all>`, `--limit <n>` (default 10), `--include-internal` (show fuzzy ranking score). Keyword(s) are fuzzy-matched against name, description, tags, intent.
|
|
371
|
+
**`suggest` options:** `--format <table|json>`, `--engine <postgres|mysql|redis|elasticsearch|all>`, `--source <local|shared|builtin|all>`. Intent prefix-matched against the snippet's `intent` frontmatter field. Common intents: `perf.slow-query`, `perf.cache-hit`, `capacity.size`, `safety.connections`, `monitor.cluster-health`.
|
|
324
372
|
**`new` options:** `--local`, `--edit`
|
|
325
373
|
**`edit` options:** `--shared`
|
|
326
374
|
**`check` options:** `--strict`, `--format <table|json|csv>`
|
|
@@ -378,11 +426,15 @@ Export query results to file or stdout.
|
|
|
378
426
|
dbcli export "SELECT * FROM users" --format csv --output users.csv
|
|
379
427
|
dbcli export "SELECT * FROM users" --format csv --output users.csv --force # Skip overwrite confirmation
|
|
380
428
|
dbcli export "SELECT * FROM users" --format json | jq '.[]'
|
|
429
|
+
dbcli export "SELECT * FROM users" --format jsonl --output users.ndjson
|
|
430
|
+
dbcli export "SELECT * FROM orders" --format html --output orders.html # standalone dashboard
|
|
381
431
|
```
|
|
382
432
|
|
|
383
|
-
**Options:** `--format <json|csv>` (required), `--output <path>`, `--force`
|
|
433
|
+
**Options:** `--format <json|jsonl|csv|html>` (required), `--output <path>`, `--force`, `--recovery`
|
|
384
434
|
**Permission:** query-only+
|
|
385
435
|
|
|
436
|
+
The `html` format emits the same self-contained dashboard as `query --ui` (see [Interactive HTML dashboard](#interactive-html-dashboard)). Because `export` runs raw SQL (no snippet metadata), the HTML report is always rendered as a sortable / filterable table — no KPIs or charts. Use `dbcli q @<name> --format html` (or `--ui`) for the charted view.
|
|
437
|
+
|
|
386
438
|
### blacklist
|
|
387
439
|
|
|
388
440
|
Manage sensitive data blacklist to prevent AI access to restricted tables/columns.
|
|
@@ -439,6 +491,302 @@ dbcli status --format text # Human-readable text output
|
|
|
439
491
|
**Output:** `permission`, `system`, `blacklist` summary, `version`
|
|
440
492
|
**Permission:** query-only+
|
|
441
493
|
|
|
494
|
+
### inspect
|
|
495
|
+
|
|
496
|
+
Read-only snapshot for AI agents. Never emits credentials or blacklisted values.
|
|
497
|
+
|
|
498
|
+
| Flag | Purpose |
|
|
499
|
+
|------|---------|
|
|
500
|
+
| `--format <json\|markdown>` | Output format (default `json`) |
|
|
501
|
+
| `--brief` | Drop sample arrays and trim suggested commands to ≤3 |
|
|
502
|
+
| `--for-agent` | Shortcut for `--format json --brief` |
|
|
503
|
+
| `--no-connect` | Skip the cheap version/object probe (no DB traffic) |
|
|
504
|
+
| `--probe-timeout <ms>` | Hard timeout for the version/object probe (default 1500) |
|
|
505
|
+
|
|
506
|
+
Example:
|
|
507
|
+
|
|
508
|
+
```bash
|
|
509
|
+
dbcli inspect --for-agent
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Output schema is locked at `schemaVersion: 1`. Sections: `connection`, `permission`, `blacklist`, `objects`, `schemaCache`, `snippets`, `suggestedCommands`, `warnings`.
|
|
513
|
+
|
|
514
|
+
**Permission:** query-only+
|
|
515
|
+
|
|
516
|
+
### report
|
|
517
|
+
|
|
518
|
+
Diagnostic report built on top of `inspect`. Reuses inspect context (connection,
|
|
519
|
+
permission, blacklist, snippet inventory) and additionally runs curated built-in
|
|
520
|
+
`@diag/*` snippets grouped into sections.
|
|
521
|
+
|
|
522
|
+
Flags:
|
|
523
|
+
- `--format json|markdown` (default: json)
|
|
524
|
+
- `--section health,capacity,perf` (default: all three)
|
|
525
|
+
- `--brief` — drop evidence rows; keep counts and statuses
|
|
526
|
+
- `--for-agent` — shortcut for `--format json --brief`
|
|
527
|
+
- `--no-connect` — context-only snapshot (skip diagnostics + inspect probe)
|
|
528
|
+
- `--per-snippet-timeout <ms>` (default 3000)
|
|
529
|
+
- `--max-rows-per-evidence <n>` (default 50)
|
|
530
|
+
- `--probe-timeout <ms>` (default 1500, inherited from inspect)
|
|
531
|
+
|
|
532
|
+
Examples:
|
|
533
|
+
|
|
534
|
+
dbcli report --format json
|
|
535
|
+
dbcli report --format markdown --section health,capacity
|
|
536
|
+
dbcli report --for-agent
|
|
537
|
+
dbcli report --no-connect
|
|
538
|
+
|
|
539
|
+
Boundaries:
|
|
540
|
+
- Read-only. Skips snippets whose required params have no default value.
|
|
541
|
+
- Never connects in `--no-connect` mode.
|
|
542
|
+
- MongoDB and no-config workspaces emit a context-only snapshot with a warning.
|
|
543
|
+
|
|
544
|
+
**Permission:** query-only+
|
|
545
|
+
|
|
546
|
+
### guide
|
|
547
|
+
|
|
548
|
+
Deterministic next-command planner for a fixed set of database goals. Reuses
|
|
549
|
+
`inspect` context (cache-first) and the workspace's saved-query inventory to
|
|
550
|
+
emit an ordered, read-only plan that an AI agent can follow step-by-step.
|
|
551
|
+
|
|
552
|
+
Goals (fixed list):
|
|
553
|
+
- `slow-query` — diagnose slow queries (long-running, locks, cache, indexes).
|
|
554
|
+
- `capacity` — audit storage and memory.
|
|
555
|
+
- `health` — connections, locks, cluster status.
|
|
556
|
+
- `index-usage` — index effectiveness audit.
|
|
557
|
+
- `permissions` — review permission level, blacklist, snippet inventory.
|
|
558
|
+
- `schema-overview` — orient in an unfamiliar database.
|
|
559
|
+
|
|
560
|
+
Flags:
|
|
561
|
+
- `--format json|markdown` (default: json)
|
|
562
|
+
- `--brief` — drop rationale + expects fields
|
|
563
|
+
- `--for-agent` — shortcut for `--format json --brief`
|
|
564
|
+
- `--list` — list available goals and exit
|
|
565
|
+
- `--probe` — refresh inspect context via live probe (default: cache-first)
|
|
566
|
+
- `--probe-timeout <ms>` (default 1500, inherited from inspect)
|
|
567
|
+
|
|
568
|
+
Examples:
|
|
569
|
+
|
|
570
|
+
dbcli guide slow-query
|
|
571
|
+
dbcli guide capacity --format markdown
|
|
572
|
+
dbcli guide --list
|
|
573
|
+
dbcli guide health --for-agent
|
|
574
|
+
dbcli guide schema-overview --probe
|
|
575
|
+
|
|
576
|
+
Boundaries:
|
|
577
|
+
- Read-only. Guide plans commands; it does not execute them.
|
|
578
|
+
- Goal vocabulary is fixed in v1.14.0; user-supplied goals are rejected.
|
|
579
|
+
- Each step carries `risk: 'readonly'` in v1.14.0 (forward-compatible with v1.15.0 recovery).
|
|
580
|
+
- Coexists with `dbcli skill tasks plan` (template-driven). Use guide for ad-hoc goals; use task packs for repeatable workflows.
|
|
581
|
+
|
|
582
|
+
**Permission:** query-only+
|
|
583
|
+
|
|
584
|
+
### recovery
|
|
585
|
+
|
|
586
|
+
Machine-readable error envelope. Two surfaces share one `RecoveryEnvelope`
|
|
587
|
+
shape (`schemaVersion: 1`):
|
|
588
|
+
|
|
589
|
+
1. **Standalone lookup**: `dbcli recovery --code <CODE>` synthesizes an
|
|
590
|
+
envelope for any known recovery code without needing a real failure.
|
|
591
|
+
2. **Failing-command opt-in**: pass `--recovery` to `dbcli query` or
|
|
592
|
+
`dbcli q`. On failure, the envelope is written to stdout as JSON, the
|
|
593
|
+
human stderr message is suppressed, and the process exits non-zero.
|
|
594
|
+
|
|
595
|
+
Recovery codes (fixed in v1.15.0):
|
|
596
|
+
- `CONFIG_MISSING` — no `.dbcli` config; run `dbcli init`.
|
|
597
|
+
- `CONN_REFUSED` / `CONN_AUTH_FAILED` / `CONN_TIMEOUT` / `CONN_HOST_NOT_FOUND` / `CONN_UNKNOWN` — connection failure variants.
|
|
598
|
+
- `PERMISSION_DENIED` — active permission level forbids the operation.
|
|
599
|
+
- `BLACKLIST_TABLE` / `BLACKLIST_COLUMN_WRITE` — blacklist violations.
|
|
600
|
+
- `SNIPPET_NOT_FOUND` / `SNIPPET_AMBIGUOUS` / `SNIPPET_PARAM_MISSING` — saved-query failures.
|
|
601
|
+
- `SCHEMA_CACHE_MISSING` — local schema cache missing or stale.
|
|
602
|
+
- `UNKNOWN` — fallback for unclassified errors.
|
|
603
|
+
|
|
604
|
+
Flags (lookup mode):
|
|
605
|
+
- `--code <CODE>` — required unless `--list` is set.
|
|
606
|
+
- `--list` — list all codes and exit.
|
|
607
|
+
- `--format json|markdown` (default: json).
|
|
608
|
+
- `--brief` — drop `rationale` + `expects` from steps.
|
|
609
|
+
- `--for-agent` — shortcut for `--format json --brief`.
|
|
610
|
+
- `--hint <text>` — bind into placeholder steps.
|
|
611
|
+
- `--snippet <name>` — bind snippet placeholder.
|
|
612
|
+
- `--table <name>` — bind table placeholder.
|
|
613
|
+
|
|
614
|
+
Examples:
|
|
615
|
+
|
|
616
|
+
dbcli recovery --code CONN_REFUSED
|
|
617
|
+
dbcli recovery --code BLACKLIST_TABLE --table users --format markdown
|
|
618
|
+
dbcli recovery --list --for-agent
|
|
619
|
+
dbcli query "SELECT * FROM users" --recovery
|
|
620
|
+
dbcli q @diag/missing --recovery
|
|
621
|
+
|
|
622
|
+
Boundaries:
|
|
623
|
+
- Recovery only **suggests** commands; agents (or humans) execute them. No automatic remediation in v1.15.0.
|
|
624
|
+
- As of v1.16.0, `--recovery` is honored on `query`, `q`, `insert`, `update`, `delete`, `export`, `schema`, and `inspect`. Other commands (`report`, `guide`, `doctor`, `migrate`, `init`, `use`, `status`, `list`, `check`, `diff`, `plan`, `shell`, `blacklist`, `completion`, `upgrade`, `skill`) keep their existing error behavior.
|
|
625
|
+
- `dbcli inspect --require-schema-cache` throws `SCHEMA_CACHE_MISSING` when the active SQL connection has no usable schema cache. Combine with `--recovery` for the structured envelope.
|
|
626
|
+
- `BLACKLIST_COLUMN_WRITE` and `PERMISSION_DENIED` envelopes prepend a `risk: 'dry-run'` step (e.g. `dbcli insert <table> --dry-run`) when the failing operation was an INSERT / UPDATE / DELETE.
|
|
627
|
+
- Recovery steps reuse the v1.14.0 `GuideStep` shape, including the full `risk` enum (`readonly` / `dry-run` / `write` / `unknown`).
|
|
628
|
+
|
|
629
|
+
**Permission:** n/a
|
|
630
|
+
|
|
631
|
+
### recover
|
|
632
|
+
|
|
633
|
+
(v1.17.0+) Inspect or apply the last recovery plan saved by `--recovery`.
|
|
634
|
+
|
|
635
|
+
| Flag | Purpose | Default |
|
|
636
|
+
|---|---|---|
|
|
637
|
+
| `--apply` | Execute the saved plan under risk gating. | off (inspect only) |
|
|
638
|
+
| `--from <path>` | Read the envelope from this file instead of `.dbcli/last-recovery.json`. Accepts raw `RecoveryEnvelope` or `SavedRecoveryEnvelope`. | — |
|
|
639
|
+
| `--allow-write <tier>` | Open the risk gate. Values: `readonly-cmd` (local-side writes) \| `write-cmd` (database writes). | `none` |
|
|
640
|
+
| `--no-verify` | Skip the verify step appended after a successful `--apply`. | off (verify runs by default) |
|
|
641
|
+
| `--format <format>` | `markdown` \| `json`. | `markdown` for inspect, `json` for `--apply` |
|
|
642
|
+
|
|
643
|
+
#### Plan source resolution
|
|
644
|
+
|
|
645
|
+
1. `--from <path>` if provided. The file must be either a raw `RecoveryEnvelope` or a `SavedRecoveryEnvelope` wrapper. When the file is a `SavedRecoveryEnvelope`, its `cwd` is reused for child-process execution. Strict zod validation; malformed → exit 2 with structured reason.
|
|
646
|
+
2. Otherwise, `.dbcli/last-recovery.json` (auto-saved on every recovery emission). Validated with the same schema; missing fields, unknown `error.code`, or `cwd` that no longer exists → exit 2.
|
|
647
|
+
3. Otherwise, exits 2 with `No recovery plan available. Run a command with --recovery to generate one, or pass --from <file>.`
|
|
648
|
+
|
|
649
|
+
#### Code-owned tier (trust boundary)
|
|
650
|
+
|
|
651
|
+
`--apply` derives the canonical execution tier from the per-`error.code` allowlist after parsing argv, **not** from the envelope's `risk` / `dbWrite` / `interactive` fields. Envelope hints can only widen safety (skip more steps); they cannot escalate execution.
|
|
652
|
+
|
|
653
|
+
| Allowlist tier | Meaning | Example commands |
|
|
654
|
+
|---|---|---|
|
|
655
|
+
| `readonly` | local read-only | `dbcli inspect`, `dbcli doctor`, `dbcli blacklist list`, `dbcli schema <table>` |
|
|
656
|
+
| `dry-run` | write subcommand invoked with `--dry-run` | `dbcli update orders --where id=1 --dry-run`, `dbcli q @x --dry-run` |
|
|
657
|
+
| `local-write` | writes local config / cache / blacklist | `dbcli blacklist remove <table>`, `dbcli use <name>`, `dbcli schema --refresh` |
|
|
658
|
+
| `db-write` | mutates the connected database | `dbcli update orders --where id=1 --set …` (no `--dry-run`), `dbcli q @x` (no `--dry-run`) |
|
|
659
|
+
| `interactive` | requires TTY | `dbcli init`, `dbcli init --force` |
|
|
660
|
+
|
|
661
|
+
`insert` / `update` / `delete` / `q` are tier `dry-run` only when argv contains `--dry-run`; otherwise they are tier `db-write` regardless of envelope `risk` claim.
|
|
662
|
+
|
|
663
|
+
#### Risk gate matrix
|
|
664
|
+
|
|
665
|
+
| Allowlist tier | Default | `--allow-write=readonly-cmd` | `--allow-write=write-cmd` |
|
|
666
|
+
|---|---|---|---|
|
|
667
|
+
| `readonly` | run | run | run |
|
|
668
|
+
| `dry-run` | run | run | run |
|
|
669
|
+
| `local-write` | `skipped:risk` | run | run |
|
|
670
|
+
| `db-write` | `skipped:risk` | `skipped:risk` | run |
|
|
671
|
+
| `interactive` | `skipped:interactive` | `skipped:interactive` | `skipped:interactive` |
|
|
672
|
+
| unresolved placeholder in `command` | `skipped:placeholder` | `skipped:placeholder` | `skipped:placeholder` |
|
|
673
|
+
| command fails parse / allowlist | `skipped:unsafe-command` | `skipped:unsafe-command` | `skipped:unsafe-command` |
|
|
674
|
+
|
|
675
|
+
Precedence: envelope `interactive: true` > `placeholder` > `unsafe-command` > allowlist `interactive` > tier-based gating.
|
|
676
|
+
|
|
677
|
+
#### Exit codes
|
|
678
|
+
|
|
679
|
+
| Code | Condition |
|
|
680
|
+
|---|---|
|
|
681
|
+
| 0 | At least one step ran successfully and no step failed. |
|
|
682
|
+
| 1 | A step exited non-zero (fail-fast); see `stoppedAt`. |
|
|
683
|
+
| 2 | Envelope missing or malformed (failed schema validation, or saved `cwd` missing). |
|
|
684
|
+
| 3 | Every step was skipped — open `--allow-write` or fill placeholders. |
|
|
685
|
+
|
|
686
|
+
#### Auto-saved envelope
|
|
687
|
+
|
|
688
|
+
Every command that emits a `RecoveryEnvelope` (`query`, `q`, `insert`, `update`, `delete`, `export`, `schema`, `inspect` — all with `--recovery`) atomically writes the envelope to `.dbcli/last-recovery.json`. The wrapper carries `schemaVersion`, `savedAt`, a sanitized `command` summary, the workspace `cwd`, and the envelope itself. SQL text and `--where` / `--set` / `--data` / `--param` values are redacted as `<sql>` or `<redacted>`. `.dbcli/` is gitignored.
|
|
689
|
+
|
|
690
|
+
#### Verification (P4)
|
|
691
|
+
|
|
692
|
+
Each `RecoveryEnvelope` now carries an optional `verify: GuideStep` (always
|
|
693
|
+
`risk: 'readonly'`, never carries placeholders). `dbcli recover --apply` runs
|
|
694
|
+
the verify step after the main plan, only when `finalStatus === 'ok'` and
|
|
695
|
+
`--no-verify` is not set.
|
|
696
|
+
|
|
697
|
+
| Recovery code | Verify command | Heuristic |
|
|
698
|
+
|---|---|---|
|
|
699
|
+
| CONFIG_MISSING | `dbcli inspect --no-connect --format json` | `connection.name` truthy → passed |
|
|
700
|
+
| CONN_REFUSED / CONN_TIMEOUT / CONN_UNKNOWN / CONN_AUTH_FAILED / CONN_HOST_NOT_FOUND | `dbcli doctor --format json` | exit 0 → passed |
|
|
701
|
+
| PERMISSION_DENIED | `dbcli inspect --for-agent` | exit 0 → passed |
|
|
702
|
+
| BLACKLIST_TABLE | `dbcli inspect --for-agent` | exit 0 → passed |
|
|
703
|
+
| BLACKLIST_COLUMN_WRITE | `dbcli inspect --for-agent` | exit 0 → passed |
|
|
704
|
+
| SNIPPET_NOT_FOUND / SNIPPET_AMBIGUOUS / SNIPPET_PARAM_MISSING | `dbcli queries list --format json` | exit 0 → passed |
|
|
705
|
+
| SCHEMA_CACHE_MISSING | `dbcli inspect --format json` | `schemaCache.available === true` → passed |
|
|
706
|
+
| UNKNOWN | `dbcli doctor --format json` | exit 0 → passed |
|
|
707
|
+
|
|
708
|
+
`verifyStatus` values:
|
|
709
|
+
|
|
710
|
+
- `passed` — heuristic confirmed.
|
|
711
|
+
- `failed` — verifier exited non-zero or timed out.
|
|
712
|
+
- `indeterminate` — verifier exited 0 but expected shape not present, or the
|
|
713
|
+
step was gated (placeholder / unsafe-command); agents should re-check.
|
|
714
|
+
|
|
715
|
+
Exit codes are unchanged — `verifyStatus` is signal, not gate.
|
|
716
|
+
|
|
717
|
+
**Schema additions.** `RecoveryEnvelope.verify?: GuideStep` is additive (no
|
|
718
|
+
`schemaVersion` bump). v1.16 consumers ignore the field.
|
|
719
|
+
|
|
720
|
+
#### Multi-turn `--next` (P2)
|
|
721
|
+
|
|
722
|
+
`dbcli recover --next` returns the single next step in a saved recovery plan,
|
|
723
|
+
given which step the agent just executed and the result of that step. v1 walks
|
|
724
|
+
the plan linearly; future codes may branch on `prevResult.stdoutSummary`
|
|
725
|
+
deterministically.
|
|
726
|
+
|
|
727
|
+
| Flag | Required | Description |
|
|
728
|
+
|---|---|---|
|
|
729
|
+
| `--next` | yes | Activate the multi-turn lookup. |
|
|
730
|
+
| `--after-step <n>` | yes | 1-based order of the step the agent just executed. Range: `[1, envelope.recovery.length]`. |
|
|
731
|
+
| `--result <value>` | yes | JSON `StepResultSummary` (inline) or `@<path>` to read from a file. |
|
|
732
|
+
| `--from <path>` | no | Override the auto-saved envelope. |
|
|
733
|
+
| `--format <fmt>` | no | `json` (default) or `markdown`. |
|
|
734
|
+
|
|
735
|
+
`--next` and `--apply` cannot be combined. `--allow-write` and `--no-verify`
|
|
736
|
+
are silently ignored under `--next` (no execution, no verification).
|
|
737
|
+
|
|
738
|
+
**`StepResultSummary` shape**
|
|
739
|
+
|
|
740
|
+
```ts
|
|
741
|
+
interface StepResultSummary {
|
|
742
|
+
status: 'ok' | 'failed' | 'skipped'
|
|
743
|
+
exitCode?: number
|
|
744
|
+
stdoutSummary?: string // last 4 KB; longer rejected
|
|
745
|
+
stderrSummary?: string // last 4 KB; longer rejected
|
|
746
|
+
}
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
`@<path>` resolves relative to the dbcli invocation cwd. File whole-size cap is
|
|
750
|
+
64 KB; per-field 4 KB cap still applies.
|
|
751
|
+
|
|
752
|
+
**`NextResult` shape (output)**
|
|
753
|
+
|
|
754
|
+
```ts
|
|
755
|
+
interface NextResult {
|
|
756
|
+
schemaVersion: 1
|
|
757
|
+
kind: 'step' | 'done'
|
|
758
|
+
source: { kind: 'auto' | 'from'; path: string }
|
|
759
|
+
errorCode: RecoveryCode
|
|
760
|
+
cursor: number // step.order when kind='step'; totalSteps when 'done'
|
|
761
|
+
totalSteps: number
|
|
762
|
+
step?: GuideStep // present iff kind='step'
|
|
763
|
+
}
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
**Exit codes**
|
|
767
|
+
|
|
768
|
+
| Exit | Condition |
|
|
769
|
+
|---|---|
|
|
770
|
+
| 0 | Returned a step or `done`. |
|
|
771
|
+
| 2 | Envelope missing/malformed; `--after-step` missing/out-of-range; `--result` missing/malformed; `--next` combined with `--apply`. |
|
|
772
|
+
|
|
773
|
+
**Examples**
|
|
774
|
+
|
|
775
|
+
```bash
|
|
776
|
+
# Walk a 3-step plan to completion
|
|
777
|
+
dbcli recover --next --after-step 1 --result '{"status":"ok"}' # → step 2
|
|
778
|
+
dbcli recover --next --after-step 2 --result '{"status":"ok"}' # → step 3
|
|
779
|
+
dbcli recover --next --after-step 3 --result '{"status":"ok"}' # → done
|
|
780
|
+
|
|
781
|
+
# Result read from file (when stdout is large)
|
|
782
|
+
dbcli recover --next --after-step 1 --result @/tmp/r1.json
|
|
783
|
+
|
|
784
|
+
# Markdown for human inspection
|
|
785
|
+
dbcli recover --next --after-step 1 --result '{"status":"ok"}' --format markdown
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
**Permission:** n/a (always-allowed lookup; child processes inherit the active permission level).
|
|
789
|
+
|
|
442
790
|
### doctor
|
|
443
791
|
|
|
444
792
|
Run diagnostic checks on environment, configuration, connection, and data.
|
|
@@ -554,6 +902,32 @@ dbcli migrate drop-enum status --execute --force
|
|
|
554
902
|
|
|
555
903
|
**AI agent note:** Always use dry-run first (no `--execute`) to preview generated SQL. Only add `--execute` after confirming the SQL is correct. For DROP operations, both `--execute` and `--force` are required.
|
|
556
904
|
|
|
905
|
+
### skill
|
|
906
|
+
|
|
907
|
+
Emit `SKILL.md` (and the companion `reference.md`) to stdout, a file, or one of
|
|
908
|
+
four AI-agent platform directories. The skill is the source of truth that lets
|
|
909
|
+
Claude Code / Gemini / Copilot / Cursor know how to drive dbcli safely.
|
|
910
|
+
|
|
911
|
+
```bash
|
|
912
|
+
dbcli skill # print SKILL.md to stdout
|
|
913
|
+
dbcli skill --output ./SKILL.md # write to a file (no platform install)
|
|
914
|
+
dbcli skill --install claude # install to ~/.claude/skills/dbcli/
|
|
915
|
+
dbcli skill --install gemini # install to ~/.gemini/skills/dbcli/
|
|
916
|
+
dbcli skill --install copilot # install to .github/skills/dbcli/ (repo-local)
|
|
917
|
+
dbcli skill --install cursor # install to .cursor/skills/dbcli/ (repo-local)
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
**Options:**
|
|
921
|
+
- `--install <platform>` — `claude` | `gemini` | `copilot` | `cursor`. Writes `SKILL.md` plus `reference.md` next to it so the agent gets progressive disclosure.
|
|
922
|
+
- `--output <path>` — write `SKILL.md` to a file instead of stdout. Does not install `reference.md`.
|
|
923
|
+
|
|
924
|
+
**Notes:**
|
|
925
|
+
- Both files come straight from `assets/SKILL.md` + `assets/reference.md` inside the dbcli package — no runtime rendering. Keep these in sync when shipping a release.
|
|
926
|
+
- `claude` / `gemini` install paths are user-global; `copilot` / `cursor` are repo-local under `.github/` / `.cursor/`.
|
|
927
|
+
- Re-running `--install` overwrites the existing skill atomically; no prompt.
|
|
928
|
+
|
|
929
|
+
**Permission:** n/a.
|
|
930
|
+
|
|
557
931
|
### skill tasks (Agent Task Packs)
|
|
558
932
|
|
|
559
933
|
```bash
|
|
@@ -581,6 +955,108 @@ Task storage layers:
|
|
|
581
955
|
Higher tiers override lower tiers by task name. Task name is derived from the
|
|
582
956
|
file path under the tier root (e.g. `diag/inspect.md` → `diag/inspect`).
|
|
583
957
|
|
|
958
|
+
## Interactive HTML dashboard
|
|
959
|
+
|
|
960
|
+
`query`, `q`, and `export` can render results as a single, fully self-contained
|
|
961
|
+
HTML file backed by a bundled React + Recharts template. The template lives at
|
|
962
|
+
`assets/ui-template.html` and is installed alongside the binary; no external
|
|
963
|
+
network, CDN, or runtime is required to view the report.
|
|
964
|
+
|
|
965
|
+
### Entry points
|
|
966
|
+
|
|
967
|
+
| Command form | Behaviour |
|
|
968
|
+
|--------------|-----------|
|
|
969
|
+
| `dbcli query "<sql>" --ui` | Render to a temp file under `$TMPDIR/dbcli-query-<ts>.html` and open with `open` / `xdg-open` / `start`. |
|
|
970
|
+
| `dbcli q @<name> --ui` | Same, with snippet metadata (`name`, `description`, `visual:` block). |
|
|
971
|
+
| `dbcli query "<sql>" --format html` | Print HTML to stdout (pipe, redirect, attach). |
|
|
972
|
+
| `dbcli q @<name> --format html` | Same, snippet-aware. |
|
|
973
|
+
| `dbcli export "<sql>" --format html --output report.html` | Write HTML to an explicit path; respects `--force` / overwrite confirmation. |
|
|
974
|
+
|
|
975
|
+
`--ui` is a convenience flag — it implies `--format html` and then opens the
|
|
976
|
+
file. `--ui` and `--format` are mutually compatible; passing both is allowed and
|
|
977
|
+
behaves as `--ui`.
|
|
978
|
+
|
|
979
|
+
### Data injection contract
|
|
980
|
+
|
|
981
|
+
The template ships with a single placeholder, `/*DBCLI_PAYLOAD*/`, which dbcli
|
|
982
|
+
replaces with:
|
|
983
|
+
|
|
984
|
+
```js
|
|
985
|
+
window.__DBCLI_PAYLOAD__ = { "meta": {...}, "rows": [...] };
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
Hardening rules applied before injection:
|
|
989
|
+
|
|
990
|
+
- Payload is `JSON.stringify(...)`-encoded.
|
|
991
|
+
- Every `<` is replaced with `<` so a malicious row containing `</script>`
|
|
992
|
+
cannot terminate the inline script tag.
|
|
993
|
+
- Blacklist redaction (`dbcli blacklist`) runs **before** the formatter — masked
|
|
994
|
+
columns never reach the dashboard.
|
|
995
|
+
- The replacement uses a function callback (`html.replace(..., () => injection)`)
|
|
996
|
+
so `$&`-style backreferences in the payload are not interpreted.
|
|
997
|
+
|
|
998
|
+
### `meta` shape
|
|
999
|
+
|
|
1000
|
+
`meta` is the `SavedQueryMeta` object (see `dbcli queries show @<name> --format json`):
|
|
1001
|
+
|
|
1002
|
+
```jsonc
|
|
1003
|
+
{
|
|
1004
|
+
"name": "Revenue Trend", // display title
|
|
1005
|
+
"key": "@analytics/revenue", // snippet key, or "raw-sql" / "export"
|
|
1006
|
+
"description": "...", // free text (SQL preview for raw query)
|
|
1007
|
+
"params": [...], // ParamSpec[]
|
|
1008
|
+
"tags": ["analytics"],
|
|
1009
|
+
"intent": "perf.slow-query",
|
|
1010
|
+
"visual": { ... } // optional, see below
|
|
1011
|
+
}
|
|
1012
|
+
```
|
|
1013
|
+
|
|
1014
|
+
For raw `query` / `export` invocations, `meta.params` is `[]` and
|
|
1015
|
+
`meta.visual` is absent — the dashboard renders a sortable / filterable table.
|
|
1016
|
+
|
|
1017
|
+
### `visual:` block (snippet frontmatter)
|
|
1018
|
+
|
|
1019
|
+
```yaml
|
|
1020
|
+
visual:
|
|
1021
|
+
title: Revenue (last :days days) # optional override of meta.name
|
|
1022
|
+
kpis:
|
|
1023
|
+
- label: Total Revenue
|
|
1024
|
+
value_column: total_revenue # must exist in result rows
|
|
1025
|
+
format: currency # currency | number | percent (optional)
|
|
1026
|
+
- label: Orders
|
|
1027
|
+
value_column: order_count
|
|
1028
|
+
format: number
|
|
1029
|
+
charts:
|
|
1030
|
+
- type: line # line | bar | area | pie | scatter
|
|
1031
|
+
title: Daily Revenue
|
|
1032
|
+
x: day # column for X axis
|
|
1033
|
+
y: [revenue] # 1..N columns for series
|
|
1034
|
+
- type: bar
|
|
1035
|
+
title: By Channel
|
|
1036
|
+
x: channel
|
|
1037
|
+
y: [revenue, refunds]
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
Parser behaviour (`src/core/saved-queries/parser.ts::normaliseVisual`):
|
|
1041
|
+
|
|
1042
|
+
- The block is **optional**. Missing → table-only render.
|
|
1043
|
+
- Items missing required fields (`kpi.label` + `kpi.value_column`, or
|
|
1044
|
+
`chart.type` + `chart.x` + `chart.y[]`) are silently dropped.
|
|
1045
|
+
- Unknown `format` / `type` values are forwarded as strings; the dashboard
|
|
1046
|
+
decides how to render them (unknown chart types fall back gracefully).
|
|
1047
|
+
- The snippet still executes as a normal SQL/DSL query — `visual:` only affects
|
|
1048
|
+
the HTML renderer.
|
|
1049
|
+
|
|
1050
|
+
### Limitations
|
|
1051
|
+
|
|
1052
|
+
- The dashboard is read-only; there is no in-page editor or re-run button.
|
|
1053
|
+
- Raw `query` / `export` HTML output never shows KPIs or charts (no snippet
|
|
1054
|
+
metadata is available). Use `dbcli q @<name>` for the charted view.
|
|
1055
|
+
- Engine support follows the underlying command: SQL, MongoDB (`--collection`),
|
|
1056
|
+
Redis, and Elasticsearch (`--collection`) all render through the same template.
|
|
1057
|
+
- Very wide / very long result sets render as a single client-side table; for
|
|
1058
|
+
>10k rows prefer `--format csv` / `--format jsonl` and a downstream tool.
|
|
1059
|
+
|
|
584
1060
|
## MongoDB Support
|
|
585
1061
|
|
|
586
1062
|
MongoDB connections use a JSON-based query model instead of SQL. Treat MongoDB support as a narrower document-database path, not as a full SQL feature equivalent.
|